我正在尝试在Java中的两个设备之间实现AES加密的基本示例。但是,每次我们运行应用程序时,在两个设备上使用相同的密码(128位)生成AES密钥会导致两个设备上的密钥不同。因此,我们无法解密在设备之间发送的文本。
我使用的方法如下,它们是我在其他地方找到的代码的略微修改版本:
public String encryptMessage(String message, String password) throws Exception {
// Creating key and cipher
SecretKeySpec aesKey = new SecretKeySpec(password.getBytes("UTF-8"), "AES");
byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
//AES cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivspec);
byte[] encrypted;
encrypted = cipher.doFinal(message.getBytes());
return new String(encrypted, "UTF-8");
}
public String decryptMessage(String encryptedMessage, String password) throws Exception {
// Creating key and cipher
byte[] passwordBytes = password.getBytes("UTF-8");
SecretKeySpec aesKey = new SecretKeySpec(passwordBytes, "AES");
byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
//AES cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
// decrypting the text
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivspec);
String decrypted = new String(cipher.doFinal(encryptedMessage.getBytes(Charset.forName("UTF-8"))));
//returning decrypted text
return decrypted;
}
每次运行此代码并打印出aesKey时,它都是不同的。
我对AES和对称加密的理解是,给定相同的密码,它应该生成相同的密钥,否则它将如何解密伪像? 是我对AES的坚持不对吗,还是有人可以建议可能会发生什么?
答案 0 :(得分:2)
您的理解是正确的,并且代码中的键是相同的。
由于aesKey
没有SecretKeySpec
方法,因此您无法“打印” toString()
。因此将调用内置的Object.toString()
,它仅会打印内存中对象的地址
javax.crypto.spec.SecretKeySpec@14c7f // <--- useless info //
您的代码只有几个问题:
请勿将加密的字节转换为UTF-8字符串。可能存在在UTF-8中无效的组合以及00个字节。使用Base64或Hex编码来打印加密的数据。
您不应使用ASCII字节作为密钥,这会大大降低密钥的安全性。 派生密码中的密钥,至少使用SHA-256,但最好使用PBKDF2或scrypt。
使用高熵随机IV并将其与密文一起存储。
这是一个更新版本,表明它正在运行:
public static String encryptMessageGH(String message, String password) throws Exception {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] key = sha.digest(password.getBytes("UTF-8"));
SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(iv));
byte[] ciphertext = cipher.doFinal(message.getBytes());
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decryptMessageGH(String encryptedMessage, String password) throws Exception {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] key = sha.digest(password.getBytes("UTF-8"));
SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
byte[] encrypted = Base64.getDecoder().decode(encryptedMessage);
byte[] iv = new byte[16];
System.arraycopy(encrypted, 0, iv, 0, iv.length);
byte[] ciphertext = new byte[encrypted.length - iv.length];
System.arraycopy(encrypted, iv.length, ciphertext, 0, ciphertext.length);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));
return new String(cipher.doFinal(ciphertext), "UTF-8");
}
public static void main(String[] args) throws Exception {
String orig = "Test message";
String enc = encryptMessageGH(orig, "abcdef123");
System.out.println("Encrypted: " + enc);
String dec = decryptMessageGH(enc, "abcdef123");
System.out.println("Decrypted: " + dec);
}
输出:
Encrypted: lcqcd9UZpjLSY9SsQ/N7kV/cpdzL3c7HQcCSiIs6p/k=
Decrypted: Test message