AESを使用して文字列を暗号化および復号化しようとしていますが、解決方法がわからないエラーが表示されます。これはコードです:
public class EncryptionTest{
public static void main(String[] args) {
String encrypt = new String(encrypt("1234567890123456"));
System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey",encrypt)));
}
public static String encrypt(String value) {
try {
byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string:" + (new String(encrypted)));
return new String(skeySpec.getEncoded());
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String encrypted) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(skeySpec.getEncoded(),"AES"));
(*)
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
original.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
実行すると、「説明」の値がヌルになります。 (***)!!の前に失敗します。
それは私に例外を与えます:
Java.security.InvalidKeyException:com.Sun.crypto.provider.CipherCore.init(CipherCore.Java:388) at com.Sun.crypto.providerでパラメーターが欠落しています .AESCipher.engineInit(AESCipher.Java:186) at javax.crypto.Cipher.implInit(Cipher.Java:787) at javax.crypto.Cipher.chooseProvider(Cipher.Java:849 ) at javax.crypto.Cipher.init(Cipher.Java:1213) at javax.crypto.Cipher.init(Cipher.Java:1153) at firma.XmlEncryptionTest .decrypt(EncryptionTest.Java:63) firma.XmlEncryptionTest.main(EncryptionTest.Java:41) で
63行目は(***)の前の行です。私は何を間違っているのか、どのように解決するのかわかりません。私はインターネットを見回したが、その欠落しているパラメーターがどのようなものであるかを見つけることなく
コードの主な問題は、IV値の指定の失敗が原因でした。 CBCモードの暗号化を行う場合はIV値を指定し、CBCモードの復号化を実行する場合は同じ値を使用する必要があります。
もう1つの問題は、バイト配列とbase64エンコードから文字列を作成することの組み合わせです。また、毎回復号化メソッドからnull
を返します。 return original.toString();
を意味していたとしても、それは間違っています(toString()
はバイト配列に対して望んでいることをしません)。
以下は、コードの改善されたバージョンです。最適とはほど遠いですが、コンパイルして動作します。ランダムIVを使用するには、これを改善する必要があります。 また、パスワードからキーを取得する場合は、バイトを取得するだけでなく、PBKDF2などの派生関数を使用します。 JNCryptor source でPBKDF2の使用例を見ることができます。
public class EncryptionTest {
public static void main(String[] args) {
try {
String key = "ThisIsASecretKey";
byte[] ciphertext = encrypt(key, "1234567890123456");
System.out.println("decrypted value:" + (decrypt(key, ciphertext)));
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
public static byte[] encrypt(String key, String value)
throws GeneralSecurityException {
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
if (raw.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec,
new IvParameterSpec(new byte[16]));
return cipher.doFinal(value.getBytes(Charset.forName("UTF-8")));
}
public static String decrypt(String key, byte[] encrypted)
throws GeneralSecurityException {
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
if (raw.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(new byte[16]));
byte[] original = cipher.doFinal(encrypted);
return new String(original, Charset.forName("UTF-8"));
}
}
CBCのようなブロックチェーンモードを使用する場合は、IvParameterSpecもCipherに提供する必要があります。
public class EncryptionTest {
static byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
static SecureRandom rnd = new SecureRandom();
static IvParameterSpec iv = new IvParameterSpec(rnd.generateSeed(16));
public static void main(String[] args) {
String encrypt = encrypt("1234567890123456");
System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey", encrypt)));
}
public static String encrypt(String value) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string:" + Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String encrypted) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec,iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
遅すぎますが、それでも他の人にソリューションを提供しています。データを暗号化および復号化するには、以下の作業コードを参照してください。
public static byte[] encrypt(String value) {
byte[] encrypted = null;
try {
byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
Key skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string:" + encrypted.length);
} catch (Exception ex) {
ex.printStackTrace();
}
return encrypted;
}
public static byte[] decrypt(byte[] encrypted) {
byte[] original = null;
Cipher cipher = null;
try {
byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
Key key = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
byte[] ivByte = new byte[cipher.getBlockSize()];
//This class specifies an initialization vector (IV). Examples which use
//IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
original= cipher.doFinal(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return original;
}