Java 中的 AES 加密移植到 Python
AES Encryption in Java porting to Python
免责声明:这是我继承的不安全加密,所有相关人员都知道这一点。我在这里要做的是摆脱这个遗留系统的第一步,这个遗留系统有比这个更大的问题。
我在 Java 中有一个现有系统,我正在尝试将其移植到 Python,该系统执行 AES 加密:
public static String encrypt(String text, SecretKey secretKey) throws Exception {
byte[] cipherText = null;
String encryptedString = null;
// get an RSA cipher object and print the provider
Cipher cipher = Cipher.getInstance(SYMMETRIC_KEY_ALGORITHM); // AES
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
cipherText = cipher.doFinal(text.getBytes());
encryptedString = Base64.getEncoder().encodeToString(cipherText);
return encryptedString;
}
我遇到的问题是尝试使用 Python 和密码学库来获得相同的 AES 设置组合以获得相同的结果:
我看到很多来自看似已失效的 PyCrypto 库的示例,我什至无法在我的 Windows 系统上安装它们,更不用说工作了。
我最近的尝试是这样的,我确实得到了加密,但它与 Java AES 输出不匹配:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
key = b'Some random key '
cipher = Cipher(algorithms.AES(key), modes.GCM(b'000000000000'))
encryptor = cipher.encryptor()
ct = encryptor.update(ENC_MESSAGE)
base64EncodedStr = base64.b64encode(ct).decode('utf-8')
print('BASE64:', base64EncodedStr)
根据 rzwitserloot 的回答更新。
我将模式从 GCM 更改为 ECB,现在我在 Python 中获得的结果几乎相同。首先是更新后的代码:
key = b'Some random key '
cipher = Cipher(algorithms.AES(key), modes.ECB())
encryptor = cipher.encryptor()
ct = encryptor.update(PLAINTEXT.encode('utf-8'))
base64EncodedStr = base64.b64encode(ct).decode('utf-8')
print('Encrypted:', base64EncodedStr)
参考(即Java)输出长度为 1004 个字符,而 Python 输出长度仅为 984 个字符。但最多匹配 Python 字符串末尾的 3 个字符:
我确实检查了解密,发现两个加密文本字符串解密为相同的明文。
最终更新:
填充是问题所在。我更新了代码以像这样使用 PKCS7 填充,现在我从 Java 和 Python:
得到相同的结果
from cryptography.hazmat.primitives import padding as symmetric_padding
padder = symmetric_padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(PLAINTEXT.encode('utf-8')) + padder.finalize()
ct = encryptor.update(padded_data)
您需要所有内容在两个版本之间完全相同。目前情况并非如此;解决这个问题。
您的 java 代码使用:
- 块大小为 128 的 AES,因为这正是 AES 的运行方式。无需配置。
- AES 密钥大小为 128、192 或 256 位。
- 钥匙。
- 操作模式。您的 java 代码使用 ECB(不安全)。您已指定 python 代码使用 GCM。显然,那是行不通的。您也需要在那里指定 ECB。
- 鉴于它是 ECB,因此没有 IV。
- 填充模式。 Java 代码在此处执行 PKCS5Padding。
- 加密基本上是基于字节的,但您要加密的不是字符串。这意味着字符串正在转换为字节,这意味着使用了字符集编码。您没有在 java 代码中指定,这意味着您得到 'platform default'。可怕的想法,但如果你不能改变 java 的一面,弄清楚那是什么,并在你的 python 代码中使用相同的编码。
- 最后,您的 java 代码 base64 就是结果。
对于其中的大部分,我根本无法告诉你;您粘贴的代码不足。例如,AES 密钥大小和密钥实际上是否相同?我不知道 - 你告诉我。你是如何制作那个 SecretKey key
对象的?
我对 python 不太熟悉,但看起来确实像是您对其进行了 base64 编码,然后再次解码。那是.. 不,不要那样做。您的 java 代码进行编码,仅此而已。您的 python 代码应该使用 base64 编码,仅此而已。
我很确定 python 也默认为 PKCS5Padding。
剩下 java 和 python 之间 100% 不匹配的编码模式给出了您粘贴的少量代码,以及您构造密钥的方式。如果您要加密的文本不是直接的 ASCII,字符集编码可能也会造成差异。
这是加密货币。一个微小的差异,输出就会大不相同。
免责声明:这是我继承的不安全加密,所有相关人员都知道这一点。我在这里要做的是摆脱这个遗留系统的第一步,这个遗留系统有比这个更大的问题。
我在 Java 中有一个现有系统,我正在尝试将其移植到 Python,该系统执行 AES 加密:
public static String encrypt(String text, SecretKey secretKey) throws Exception {
byte[] cipherText = null;
String encryptedString = null;
// get an RSA cipher object and print the provider
Cipher cipher = Cipher.getInstance(SYMMETRIC_KEY_ALGORITHM); // AES
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
cipherText = cipher.doFinal(text.getBytes());
encryptedString = Base64.getEncoder().encodeToString(cipherText);
return encryptedString;
}
我遇到的问题是尝试使用 Python 和密码学库来获得相同的 AES 设置组合以获得相同的结果:
我看到很多来自看似已失效的 PyCrypto 库的示例,我什至无法在我的 Windows 系统上安装它们,更不用说工作了。
我最近的尝试是这样的,我确实得到了加密,但它与 Java AES 输出不匹配:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
key = b'Some random key '
cipher = Cipher(algorithms.AES(key), modes.GCM(b'000000000000'))
encryptor = cipher.encryptor()
ct = encryptor.update(ENC_MESSAGE)
base64EncodedStr = base64.b64encode(ct).decode('utf-8')
print('BASE64:', base64EncodedStr)
根据 rzwitserloot 的回答更新。
我将模式从 GCM 更改为 ECB,现在我在 Python 中获得的结果几乎相同。首先是更新后的代码:
key = b'Some random key '
cipher = Cipher(algorithms.AES(key), modes.ECB())
encryptor = cipher.encryptor()
ct = encryptor.update(PLAINTEXT.encode('utf-8'))
base64EncodedStr = base64.b64encode(ct).decode('utf-8')
print('Encrypted:', base64EncodedStr)
参考(即Java)输出长度为 1004 个字符,而 Python 输出长度仅为 984 个字符。但最多匹配 Python 字符串末尾的 3 个字符:
我确实检查了解密,发现两个加密文本字符串解密为相同的明文。
最终更新:
填充是问题所在。我更新了代码以像这样使用 PKCS7 填充,现在我从 Java 和 Python:
得到相同的结果from cryptography.hazmat.primitives import padding as symmetric_padding
padder = symmetric_padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(PLAINTEXT.encode('utf-8')) + padder.finalize()
ct = encryptor.update(padded_data)
您需要所有内容在两个版本之间完全相同。目前情况并非如此;解决这个问题。
您的 java 代码使用:
- 块大小为 128 的 AES,因为这正是 AES 的运行方式。无需配置。
- AES 密钥大小为 128、192 或 256 位。
- 钥匙。
- 操作模式。您的 java 代码使用 ECB(不安全)。您已指定 python 代码使用 GCM。显然,那是行不通的。您也需要在那里指定 ECB。
- 鉴于它是 ECB,因此没有 IV。
- 填充模式。 Java 代码在此处执行 PKCS5Padding。
- 加密基本上是基于字节的,但您要加密的不是字符串。这意味着字符串正在转换为字节,这意味着使用了字符集编码。您没有在 java 代码中指定,这意味着您得到 'platform default'。可怕的想法,但如果你不能改变 java 的一面,弄清楚那是什么,并在你的 python 代码中使用相同的编码。
- 最后,您的 java 代码 base64 就是结果。
对于其中的大部分,我根本无法告诉你;您粘贴的代码不足。例如,AES 密钥大小和密钥实际上是否相同?我不知道 - 你告诉我。你是如何制作那个 SecretKey key
对象的?
我对 python 不太熟悉,但看起来确实像是您对其进行了 base64 编码,然后再次解码。那是.. 不,不要那样做。您的 java 代码进行编码,仅此而已。您的 python 代码应该使用 base64 编码,仅此而已。
我很确定 python 也默认为 PKCS5Padding。
剩下 java 和 python 之间 100% 不匹配的编码模式给出了您粘贴的少量代码,以及您构造密钥的方式。如果您要加密的文本不是直接的 ASCII,字符集编码可能也会造成差异。
这是加密货币。一个微小的差异,输出就会大不相同。