如何编写与给定Java AES加密代码功能等效的Python3实现?
AES加密Java逻辑转Python3实现修复方案
对接公开API需按照对方提供的Java AES加密规则对请求负载加密,自行实现的Python代码无法生成与Java一致的加密结果,具体修复逻辑如下:
参考Java加密实现
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; import java.security.spec.KeySpec; import java.util.Base64; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Base64.getUrlDecoder; import static java.util.Base64.getUrlEncoder; import static javax.crypto.Cipher.DECRYPT_MODE; import static javax.crypto.Cipher.ENCRYPT_MODE; private static final String AES_ALGO = "AES"; private static final String KEY_ALGO = "PBKDF2WithHmacSHA256"; private static final String AES_CBC_PKCS5 = "AES/CBC/PKCS5Padding"; private static final String secretKey = "ac12ghd75kf75r"; private static final String fi = "FIUID"; public static String encrypt(String strToEncrypt, String salt) { final byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; IvParameterSpec ivspec = new IvParameterSpec(iv); try { SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGO); KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256); SecretKey tmp = factory.generateSecret(spec); SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), AES_ALGO); Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5); cipher.init(ENCRYPT_MODE, secretKey, ivspec); return getUrlEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(UTF_8))); } catch (Exception e) { e.printStackTrace(); } return null; }
初始错误Python实现
import base64 import hashlib from Crypto.Cipher import AES from Crypto import Random from datetime import datetime AES_ALGO = "AES" KEY_ALGO = "PBKDF2WithHmacSHA256" AES_CBC_PKCS5 = "AES/CBC/PKCS5Padding" secretKey = "ac12ghd75kf75r" fi = "FIUID" BLOCK_SIZE = 16 pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE) def encrypt_payload(payload,salt=datetime.utcnow()): private_key = hashlib.pbkdf2_hmac( hash_name = 'sha1', password = b"ac12ghd75kf75r", salt = b"031120201803460", iterations = 65536, dklen = 32 #256 ) raw = pad(payload) iv=bytearray(16) iv=iv.encode("utf8") cipher = AES.new(private_key, AES.MODE_CBC, iv) return_val= base64.b64encode(iv + cipher.encrypt(raw.encode("utf8"))) return return_val def test_encryption(): payload = "txnid=T1234&sessionid=S1234&srcref=Srcref1234&userid=acme@perfios-aa&redirect=https://example.com" encrypted_payload = "6Zdz3bzzu3AKld4d_D_dDBIaTqbXKxPjKGzGQgxkrm-WeDhpFr9Ma_R_BAdekBmUNbAcYFsizzJydDhQAa-fu40KrI9PcauoEEqgxC1C1iot_-0Ues7H7UyoLYgDgbxDpzy8s7zB3AhAvCIlplcYqQ==" print(encrypt_payload(payload, "031120201803460")==encrypted_payload)
问题点梳理
- PBKDF2哈希算法不匹配:Java使用
PBKDF2WithHmacSHA256,初始代码误用了sha1算法 - Base64编码规则不匹配:Java使用URL安全的Base64编码,初始代码使用普通Base64编码
- 密文拼接逻辑错误:Java仅返回加密后的密文,初始代码错误将IV拼接到密文前一起编码
- IV处理逻辑错误:全0 IV不需要额外调用encode方法,直接生成16位全0字节即可
- 盐值参数未生效:函数参数传入的salt没有被实际使用,代码硬编码了固定盐值
- 返回值类型不匹配:Java返回字符串,初始代码返回bytes类型,无法直接和预期字符串比较
最终修复后完整代码
import base64 import hashlib from Crypto.Cipher import AES from datetime import datetime secretKey = b"ac12ghd75kf75r" BLOCK_SIZE = 16 # PKCS5填充逻辑和Java侧一致 pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE) def encrypt_payload(payload, salt=datetime.utcnow().strftime("%Y%m%d%H%M%S")): # 生成256位密钥,使用sha256哈希算法 private_key = hashlib.pbkdf2_hmac( hash_name='sha256', password=secretKey, # 实际使用传入的盐值,转成utf8字节 salt=salt.encode("utf8"), iterations=65536, dklen=32 ) raw = pad(payload) # 16位全0 IV,和Java侧一致 iv = bytes(16) cipher = AES.new(private_key, AES.MODE_CBC, iv) # 仅加密填充后的明文,不拼接IV,使用URL安全Base64编码,转成utf8字符串返回 return base64.urlsafe_b64encode(cipher.encrypt(raw.encode("utf8"))).decode("utf8") def test_encryption(): payload = "txnid=T1234&sessionid=S1234&srcref=Srcref1234&userid=acme@perfios-aa&redirect=https://example.com" encrypted_payload = "6Zdz3bzzu3AKld4d_D_dDBIaTqbXKxPjKGzGQgxkrm-WeDhpFr9Ma_R_BAdekBmUNbAcYFsizzJydDhQAa-fu40KrI9PcauoEEqgxC1C1iot_-0Ues7H7UyoLYgDgbxDpzy8s7zB3AhAvCIlplcYqQ==" print(encrypt_payload(payload, "031120201803460") == encrypted_payload) # 运行测试会输出True test_encryption()
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

