有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java移植到Python中的AES加密

免责声明:这是我继承的不安全加密,所有相关人员都知道这一点。我在这里试图做的是摆脱这个遗留系统的第一步,这个遗留系统有着比这更大的问题

我有一个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设置组合,以获得相同的结果:

Python Cryptography

我从看似已不存在的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个字符:

Output Strings

我确实检查了解密,发现两个加密的文本字符串解密为相同的明文

最后更新:

填充物是问题所在。我将代码更新为使用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)

共 (1) 个答案

  1. # 1 楼答案

    你需要两个版本之间的所有内容都要完全相同。目前情况并非如此;解决这个问题

    您的java代码使用:

    • 块大小为128的AES,因为AES就是这样滚动的。无需配置
    • AES密钥大小为128、192或256位
    • 钥匙
    • 操作模式。java代码使用ECB(这是不安全的)。您已经告诉python代码使用GCM。这显然是行不通的。你也需要在那里指定ECB
    • 既然是欧洲央行,就没有静脉注射
    • 填充模式。Java代码正在这里添加PKCS5P
    • Crypto基本上是基于字节的,但是你试图加密字符串,而不是。这意味着字符串被转换成字节,这意味着使用了字符集编码。您没有在java代码中指定,这意味着您得到了“平台默认值”。这个想法很糟糕,但是如果你不能改变java方面,那就弄清楚这是什么,然后在你的python代码中使用相同的编码
    • 最后,您的java代码base64就是结果

    对于其中的大多数,我无法告诉你;您粘贴的代码不足。例如,AES密钥大小以及密钥是否完全相同?我不知道——你告诉我。你是如何制作SecretKey key对象的

    我对python不太熟悉,但看起来确实需要对其进行base64编码,然后再次解码。那是。。不,不要那样做。你的java代码编码就是这样。你的python代码应该是base64编码,仅此而已

    我很确定python也默认为PKCS5P

    这就留下了java和python之间100%不匹配的编码模式,给出了粘贴的少量代码,以及构造键的方式。如果加密的文本不是直接的ASCII码,那么字符集编码也可能会造成差异

    这是加密的。一个微小的差异和输出将是完全不同的