Python与Java的AES加密结果不一致问题排查求助
Java与Python AES-CBC跨语言加密解密不一致问题排查
我在实现Java和Python应用间的加密通信时,遇到双方解密对方加密字符串结果不一致的问题,排查许久没找到代码问题,求指导。测试用的是32字节消息,相关代码如下:
Java端加密函数
public static String encrypt(String value) { try { String privateKey = "1234567887654321"; String stringIV = getRandomIV(); IvParameterSpec iv = new IvParameterSpec(stringIV.getBytes()); SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8)); String encryptedString = new String(encrypted); String toEncrypt = stringIV + encryptedString; return android.util.Base64.encodeToString(toEncrypt.getBytes("UTF-8"), android.util.Base64.DEFAULT); } catch (Exception ex) { ex.printStackTrace(); } return null; } static String getRandomIV() { UUID randomUUID = UUID.randomUUID(); return randomUUID.toString().replaceAll("_", "").replaceAll("-", "").substring(0,16); }
Python端解密代码
msg_bytes=bytes(msg, encoding="utf8").decode("utf-8",'ignore') b64decoded=base64.b64decode(msg_bytes) cipher = AES.new('1234567887654321'.encode("utf8"), AES.MODE_CBC, b64decoded[0:16]) decoded = cipher.decrypt(b64decoded[16:48]) decoded = bytes(decoded).decode("utf-8",'ignore')
Java端解密函数
public static String decrypt(String encrypted) { try { String privateKey = "1234567887654321"; Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); byte[] base64decoded = new byte[0]; base64decoded = android.util.Base64.decode(encrypted, android.util.Base64.DEFAULT); String base64decodedString = new String(base64decoded); byte[] byteiv = Arrays.copyOfRange(base64decoded, 0, 16); IvParameterSpec iv = new IvParameterSpec(byteiv); SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes(), "AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] bytes = Hex.decodeHex(hex(base64decodedString.substring(16,48).getBytes()).toCharArray()); byte[] original = new byte[0]; byte[] bytemsg = Arrays.copyOfRange(base64decoded, 16, base64decoded.length); original = cipher.doFinal(bytemsg); return new String(original.toString()); } catch (Exception ex) { ex.printStackTrace(); } return null; }
Python端加密代码
data = str(json.dumps(data)) iv = Random.get_random_bytes(16) cipher = AES.new('1234567887654321'.encode("utf8"), AES.MODE_CBC, iv) byte_iv = bytearray(iv) encrypted = bytearray(cipher.encrypt(self.pad(data).encode("utf8"))) data = base64.b64encode(bytes(byte_iv + encrypted)) data = list(data) data = bytes(data)
核心问题及修复方案
Java加密时二进制转字符串的编码错误
加密后的encrypted是二进制字节数组,直接用new String(encrypted)会因二进制数据不符合UTF-8编码规则导致字节丢失或乱码。正确做法是直接拼接IV字节数组和加密字节数组,再做Base64编码:// 替换原加密后的字符串拼接逻辑 byte[] ivBytes = stringIV.getBytes(StandardCharsets.UTF_8); byte[] combined = new byte[ivBytes.length + encrypted.length]; System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length); System.arraycopy(encrypted, 0, combined, ivBytes.length, encrypted.length); return android.util.Base64.encodeToString(combined, android.util.Base64.DEFAULT);Python解密时硬编码密文长度
代码中b64decoded[16:48]硬限制了密文长度,只适用于特定测试场景,正确做法是截取16字节IV之后的所有字节作为密文:decoded = cipher.decrypt(b64decoded[16:]) # 取IV之后的全部内容作为密文Java解密时字符串转换错误与冗余逻辑
new String(original.toString())错误,original.toString()返回的是字节数组的对象标识,而非字节对应的字符串,应改为new String(original, StandardCharsets.UTF_8)- 冗余的Hex解码逻辑可直接删除,使用
bytemsg即可完成解密
编码与填充一致性
- Java解密中
privateKey.getBytes()需指定StandardCharsets.UTF_8,避免依赖系统默认编码 - 确保Python端的
pad函数实现PKCS5填充(16字节块大小下,PKCS5与PKCS7填充等价,和Java的PKCS5PADDING匹配)
- Java解密中
内容的提问来源于stack exchange,提问作者Shakib Karami
相关产品推荐
相关产品推荐

