Java 具有内联安全随机 IV 的 AES CBC - 生成相同的密文?
Java AES CBC with Inline Secure Random IV - Produces same Cipher text?
我正在尝试内联我的 IV,这样我就可以在不知道初始 IV 的情况下解密我的消息,只知道密钥。
我生成我的密钥。
我用 SecureRandom 生成我的 IV
我随机化了 IV 字节数组。
(我用 iv+message 创建一条消息)
最后,我用唯一的 IV 加密消息。
不出所料,如果我在接收端删除 IV,我可以解密消息。
但是生成的密文总是一样的
我不知道这是为什么,还没有在网上找到解决方案。
下面是我的代码和输出。
谁能帮我理解这是为什么?
enter code
String mssg = "Hello hellow hello";
byte[] key = "kljhn1234512345abcde123451234512".getBytes();
SecretKeySpec spec = new SecretKeySpec(key, "AES");
SecureRandom rand = new SecureRandom();
for (int i = 0; i < 5; i++) {
//
//initialzize empty byte array for random IV
byte[] iv = new byte[16];
System.out.println("IV pre rand: " + Arrays.toString(iv));
rand.nextBytes(iv); //RANDOMIZE
System.out.println("IV POST rand: " + Arrays.toString(iv));
//CONCATENTATE IV TO FRONT OF MESSAGE TO ENCRYPT
//CONCATENATE MESSAGE TO END OF IV
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
bout.write(iv);
bout.write(mssg.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
byte[] message = bout.toByteArray();
try {
//ENCRYPT USING RANDIMIZED IV.. THIS SHOULD RESULT IN NON EQUAL CIPHER TEXT FOR SAME MESSAGE.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, spec, new IvParameterSpec(iv));
byte[] ct = cipher.doFinal(message);
System.out.println("CIPHER TEXT: " + Arrays.toString(ct));
//DECRYPT. AND USING A WRONG IV.
cipher.init(Cipher.DECRYPT_MODE, spec, new IvParameterSpec(new byte[16]));
System.out.println("DECRYPTED: " + new String(cipher.doFinal(ct)));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
这里
并且输出:
迭代 1
IV pre rand: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [13, 68, 83, 113, 86, 48, 50, -71, -75, -25, 56, 100, -25, 34, -27, - 23]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
迭代 2:
IV pre rand: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [90, 115, 91, 124, 27, -80, -32, -46, -66, -50, -85, 43, 34, -18, - 74, -3]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
迭代 3
IV 前值:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [113, 112, 9, 47, -125, -4, 80, 10, -97, 44, 42, 90, -58, -44, -46, 17]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
如果您查看 the nice picture in Wikipedia of how CBC works,您会发现通过将 IV 放在 CBC 明文的开头,您实际上取消了 IV 并破坏了它旨在提供的语义安全性。具体来说,使用 CBC 加密可以:
将 IV 与第一个明文块进行异或,并将其加密为第一个密文块。由于您将第一个明文块制作为 IV 的副本,因此这始终会加密零块并每次都产生相同的结果。
将第一个密文块与第二个明文块(这里是你搞砸之前的实际明文)进行异或,并将其加密为第二个密文块。由于您将第一个密文块设置为固定值,并且在您的测试中实际明文是相同的,因此每次都会产生相同的结果。
等等等等
做你应该做的事:
用(秘密)密钥和(随机)IV 加密 actual 明文,然后将 IV 与 密文用于传输;连接是一种简单的方法,但不是唯一的方法
在接收时将 IV 从密文中拆分或分离,并使用(秘密)密钥和(随机但可见的)IV 解密密文
我正在尝试内联我的 IV,这样我就可以在不知道初始 IV 的情况下解密我的消息,只知道密钥。
我生成我的密钥。 我用 SecureRandom 生成我的 IV 我随机化了 IV 字节数组。 (我用 iv+message 创建一条消息) 最后,我用唯一的 IV 加密消息。
不出所料,如果我在接收端删除 IV,我可以解密消息。 但是生成的密文总是一样的
我不知道这是为什么,还没有在网上找到解决方案。
下面是我的代码和输出。
谁能帮我理解这是为什么?
enter code
String mssg = "Hello hellow hello";
byte[] key = "kljhn1234512345abcde123451234512".getBytes();
SecretKeySpec spec = new SecretKeySpec(key, "AES");
SecureRandom rand = new SecureRandom();
for (int i = 0; i < 5; i++) {
//
//initialzize empty byte array for random IV
byte[] iv = new byte[16];
System.out.println("IV pre rand: " + Arrays.toString(iv));
rand.nextBytes(iv); //RANDOMIZE
System.out.println("IV POST rand: " + Arrays.toString(iv));
//CONCATENTATE IV TO FRONT OF MESSAGE TO ENCRYPT
//CONCATENATE MESSAGE TO END OF IV
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
bout.write(iv);
bout.write(mssg.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
byte[] message = bout.toByteArray();
try {
//ENCRYPT USING RANDIMIZED IV.. THIS SHOULD RESULT IN NON EQUAL CIPHER TEXT FOR SAME MESSAGE.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, spec, new IvParameterSpec(iv));
byte[] ct = cipher.doFinal(message);
System.out.println("CIPHER TEXT: " + Arrays.toString(ct));
//DECRYPT. AND USING A WRONG IV.
cipher.init(Cipher.DECRYPT_MODE, spec, new IvParameterSpec(new byte[16]));
System.out.println("DECRYPTED: " + new String(cipher.doFinal(ct)));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
这里
并且输出:
迭代 1 IV pre rand: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [13, 68, 83, 113, 86, 48, 50, -71, -75, -25, 56, 100, -25, 34, -27, - 23]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
迭代 2: IV pre rand: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [90, 115, 91, 124, 27, -80, -32, -46, -66, -50, -85, 43, 34, -18, - 74, -3]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
迭代 3
IV 前值:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
IV POST rand: [113, 112, 9, 47, -125, -4, 80, 10, -97, 44, 42, 90, -58, -44, -46, 17]
密文:[-102, -52, -21, -92, -85, 119, -10, -18, -52, 0, -39, -19, 11, -83, 70, 44, 101, -92, -93, -60, 4, 73, -17, 73, -58, 119, 81, 66, -114, 54, -107, -83, 11, 42, -92, 121 , -15, -61, 92, 83, 24, 10, 89, -21, 110, 100, 116, 119]
已解密:��������������������������������你好你好
如果您查看 the nice picture in Wikipedia of how CBC works,您会发现通过将 IV 放在 CBC 明文的开头,您实际上取消了 IV 并破坏了它旨在提供的语义安全性。具体来说,使用 CBC 加密可以:
将 IV 与第一个明文块进行异或,并将其加密为第一个密文块。由于您将第一个明文块制作为 IV 的副本,因此这始终会加密零块并每次都产生相同的结果。
将第一个密文块与第二个明文块(这里是你搞砸之前的实际明文)进行异或,并将其加密为第二个密文块。由于您将第一个密文块设置为固定值,并且在您的测试中实际明文是相同的,因此每次都会产生相同的结果。
等等等等
做你应该做的事:
用(秘密)密钥和(随机)IV 加密 actual 明文,然后将 IV 与 密文用于传输;连接是一种简单的方法,但不是唯一的方法
在接收时将 IV 从密文中拆分或分离,并使用(秘密)密钥和(随机但可见的)IV 解密密文