アプリ版:「スタンプのみでお礼する」機能のリリースについて

現在下記仕様でパラメータの暗号化複合化処理を作成していますが例外が発生して困っています。

方式:DES
モード:CBC
パディング:PKCS5Padding
秘密鍵:kagi1234
BASE64でエンコードしてString変換

【例外内容】
Exception in thread "main" java.lang.RuntimeException: java.security.InvalidKeyException: Parameters missing
at enc.Main01.decrypt(Main01.java:114)

【ソースコード】
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Encoder;

public class Main01 {

public static void main(String[] args) {

try {
String val1 = encrypt("10000", "key12345");
System.out.println(decrypt(val1, "key12345"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String text, String secretKey) throws Exception {

SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES");
Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding");
cp.init(Cipher.ENCRYPT_MODE, sks);
return new BASE64Encoder().encodeBuffer(cp.doFinal(text.getBytes()));

}
public static String decrypt(String decValue, String secretKey) throws Exception {

SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES");
byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue);
Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding");
cp.init(Cipher.DECRYPT_MODE, sks);
return new String(cp.doFinal(decArr));
}
}
対処方法がも解らず自力解決は困難です。
お手数ですが解決方法を御教授願えないでしょうか?
よろしくお願いします。
環境(WidowsXP SP2, JDK1.5.0_07-b03)

A 回答 (3件)

Sunのサンプルコードを見ると、


暗号化に使ったSecurityAlgorithmParametersを、復号に使う必要があります。ENCRYPT_MODEでinitした際に暗黙的に生成されてるみたい。
質問文のコードを改変したもの(☆が追加):

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters; /* ☆ */
import sun.misc.BASE64Encoder;

public class Main01 {

private static byte[] enc_param_; /* ☆ */
public static void main(String[] args) {

try {
String val1 = encrypt( args[0], "key12345");
System.out.println(val1);
System.out.println(decrypt(val1, "key12345"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String encValue, String secretKey) throws Exception {

SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES");
Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding");
cp.init(Cipher.ENCRYPT_MODE, sks);
enc_param_ = cp.getParameters().getEncoded(); /* ☆ */
return new BASE64Encoder().encodeBuffer(cp.doFinal(encValue.getBytes()));

}
public static String decrypt(String decValue, String secretKey) throws Exception {

SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES");
Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding");
AlgorithmParameters saprm = AlgorithmParameters.getInstance("DES"); /* ☆ */
saprm.init( enc_param_ ); /* ☆ */
cp.init(Cipher.DECRYPT_MODE, sks, saprm /* ☆ */ );
byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue);
return new String(cp.doFinal(decArr));
}
}

この回答への補足

osamuy様

早速の回答ありがとうございます。
いただいたソースを実行してみましたが、無事暗号、複合化を行なうことができました。
ただ、実行する度に暗号化した文字列が異なってしまいます。
これは回避不能なのでしょうか?
実は今回、秘密鍵を使用してパラメータを暗号化し、拠点Aと拠点BでHTTPで通信を行なう必要があります。
秘密鍵はお互いの外部ファイルに保持していますので、その鍵を使用して暗号、復号できればと考えているのです。
この場合、同じ秘密鍵を使用して暗号化したならば、必ず同じ暗号になりませんと送信先で復号できないと思っています。
DESを使用した暗号化/複合化の場合、秘密鍵をお互い保持しておくだけでなく
今回osamuy様追加した変数の「enc_param_」も送信先に引き継がなければならないのでしょうか?

≪いただいたソースの実行結果≫
引数に「10000」を指定

【1回目】
暗号化後:6wc4lWqk4XI=
複合化後:10000

【2回目】
暗号化後:I58cD3SogT4=
複合化後:10000

【3回目】
暗号化後:w536VsFvHJY=
複合化後:10000

補足日時:2006/12/10 20:54
    • good
    • 0

> ただ、実行する度に暗号化した文字列が異なってしまいます。


> 変数の「enc_param_」も送信先に引き継がなければならないのでしょうか?
多分YESです。
手っ取り早く、ソースにハードコードしといて、常に同じsecurity.AlgorithmParametersを使用する手もあります。
例)
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import sun.misc.BASE64Encoder;

public class code {

private final static String SECRET_PW = "key12345";
private final static byte[] enc_param_ = {4,8,-9,98,88,-115,5,-124,-69,31};

public static void main(String[] args) {

try {
String val1 = encrypt( args[0], SECRET_PW );
System.out.println(val1);
System.out.println(decrypt( val1, SECRET_PW ));
} catch (Exception e) { e.printStackTrace(); }
}
private static Cipher setup_cipher( int ci_mode, String secretKey ) throws Exception {
SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES");
AlgorithmParameters saprm = AlgorithmParameters.getInstance("DES");
saprm.init( enc_param_ );
Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding");
cp.init( ci_mode, sks, saprm );
return cp;
}
public static String encrypt(String encValue, String secretKey) throws Exception {
Cipher cp = setup_cipher( Cipher.ENCRYPT_MODE, secretKey );
return new BASE64Encoder().encodeBuffer(cp.doFinal(encValue.getBytes()));
}
public static String decrypt(String decValue, String secretKey) throws Exception {
Cipher cp = setup_cipher( Cipher.DECRYPT_MODE, secretKey );
byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue);
return new String(cp.doFinal(decArr));
}
}

>実は今回、秘密鍵を使用してパラメータを暗号化し、拠点Aと拠点BでHTTPで通信を行なう必要があります。

だったら、SSLを使う方が簡単では。
    • good
    • 0

>ただ、実行する度に暗号化した文字列が異なってしまいます。



回答ではありませんが、CBCモードについていま一度勉強されてみてはいかがでしょうか?

参考サイトを参考にしてください。

参考URL:http://www.ss.iij4u.or.jp/~somali/web/_block_mod …
    • good
    • 1
この回答へのお礼

ご回答ありがとうございます。
下記の記述でProviderを追加するようにした所
毎回同じ値を作成することができました。

Security.addProvider(new com.sun.crypto.provider.SunJCE());

回答をしてくださったみなさま
ありがとうございました。

お礼日時:2006/12/17 14:02

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!