使用AES-CFB在Java中加密并解密 [英] Encrypt in python and decrypt in Java with AES-CFB
问题描述
我知道一个与此非常相似的问题(如何在Python中进行加密并在Java中进行解密?)但是我有一个不同的问题。
我的问题是,我无法解密在Java中正确。尽管使用正确的键和IV,我仍然在解密之后得到垃圾字符。我在Java中没有编译/运行时错误或异常,所以我相信我正在使用正确的参数进行解密。
Python加密代码 -
从Crypto.Cipher导入AES
import base64
key ='0123456789012345'
iv ='RandomInitVector '
raw ='samplePlainText'
cipher = AES.new(key,AES.MODE_CFB,iv)
encrypted = base64.b64encode(iv + cipher.encrypt(raw))
Java解密代码 -
private static String KEY =0123456789012345;
public static String decrypt(String encrypted_encoded_string)throws NoSuchAlgorithmException,NoSuchPaddingException,
InvalidKeyException,IllegalBlockSizeException,BadPaddingException {
String plain_text =;
try {
byte [] encrypted_decoded_bytes = Base64.getDecoder()。decode(encrypted_encoded_string);
String encrypted_decoded_string = new String(encrypted_decoded_bytes);
String iv_string = encrypted_decoded_string.substring(0,16); // IV正确检索
IvParameterSpec iv = new IvParameterSpec(iv_string.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes(UTF-8),AES);
密码密码= Cipher.getInstance(AES / CFB / NoPadding);
cipher.init(Cipher.DECRYPT_MODE,skeySpec,iv);
plain_text = new String(cipher.doFinal(encrypted_decoded_bytes)); //返回垃圾字符
return plain_text;
} catch(Exception e){
System.err.println(Caught Exception:+ e.getMessage());
}
return plain_text;
}
有没有什么明显的我失踪?
密码反馈(CFB)操作模式是一种模式。它由段大小(或寄存器大小)参数化。 PyCrypto具有默认的分段大小为8位和Java(实际上是OpenJDK)的默认段大小为与块大小相同(AES为128位)。
如果你想要CFB -128在pycrypto中,您可以使用 AES.new(key,AES.MODE_CFB,iv,segment_size = 128)
。如果您想在Java中使用CFB-8,可以使用 Cipher.getInstance(AES / CFB8 / NoPadding);
。
现在我们有了这个方法,你有其他问题:
-
始终指定您正在使用的字符集,因为它可以在不同的JVM之间切换:
new String(someBytes,UTF-8)
和someString.getBytes( UTF-8)
。不要使用字符串来存储二进制数据(new String(encrypted_decoded_bytes);
)。您可以直接复制字节:IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(encrypted_decoded_bytes,16));
和cipher.doFinal(Arrays.copyOfRange (encrypted_decoded_bytes,16,encrypted_decoded_bytes.length))
。 -
在Java中,你假设IV是在前面的密文,然后编码在一起,但在Python中,你从来没有对IV做任何事情。我想你已经发布了不完整的代码。
-
如果关键码保持不变,CFB模式每次使用不同的 IV至关重要相同。如果您不更改每个加密的IV,您将创建一个多时间的键盘,使攻击者即使不知道密钥也可以推导出明文。
I am aware of a question very similar to this (How do I encrypt in Python and decrypt in Java?) but I have a different problem.
My problem is, I am not able to decrypt in Java correctly. Despite using the correct key and IV, I still get garbage characters after decryption. I don't have any compile/run-time errors or exceptions in Java so I believe I am using the right parameters for decryption.
Python Encryption Code -
from Crypto.Cipher import AES
import base64
key = '0123456789012345'
iv = 'RandomInitVector'
raw = 'samplePlainText'
cipher = AES.new(key,AES.MODE_CFB,iv)
encrypted = base64.b64encode(iv + cipher.encrypt(raw))
Java Decryption Code -
private static String KEY = "0123456789012345";
public static String decrypt(String encrypted_encoded_string) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String plain_text = "";
try{
byte[] encrypted_decoded_bytes = Base64.getDecoder().decode(encrypted_encoded_string);
String encrypted_decoded_string = new String(encrypted_decoded_bytes);
String iv_string = encrypted_decoded_string.substring(0,16); //IV is retrieved correctly.
IvParameterSpec iv = new IvParameterSpec(iv_string.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
plain_text = new String(cipher.doFinal(encrypted_decoded_bytes));//Returns garbage characters
return plain_text;
} catch (Exception e) {
System.err.println("Caught Exception: " + e.getMessage());
}
return plain_text;
}
Is there anything obvious that I am missing?
The Cipher Feedback (CFB) mode of operation is a family of modes. It is parametrized by the segment size (or register size). PyCrypto has a default segment size of 8 bit and Java (actually OpenJDK) has a default segment size the same as the block size (128 bit for AES).
If you want CFB-128 in pycrypto, you can use AES.new(key, AES.MODE_CFB, iv, segment_size=128)
. If you want CFB-8 in Java, you can use Cipher.getInstance("AES/CFB8/NoPadding");
.
Now that we have that out the way, you have other problems:
Always specify the character set you're using, because it can change between different JVMs:
new String(someBytes, "UTF-8")
andsomeString.getBytes("UTF-8")
. When you do, be consistent.Never use a String to store binary data (
new String(encrypted_decoded_bytes);
). You can copy the bytes directly:IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(encrypted_decoded_bytes, 16));
andcipher.doFinal(Arrays.copyOfRange(encrypted_decoded_bytes, 16, encrypted_decoded_bytes.length))
.In Java, you're assuming that the IV is written in front of the ciphertext and then encoded together, but in Python, you're never doing anything with the IV. I guess you posted incomplete code.
It is crucial for CFB mode to use a different IV every time if the key stays the same. If you don't change the IV for every encryption, you will create a multi-time pad which enables an attacker to deduce the plaintext even without knowing the key.
这篇关于使用AES-CFB在Java中加密并解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!