问题描述
我正在尝试与Bank API集成。这是银行提供的用于加密/解密的Java示例代码。
package com.example.restservice;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
public class EncHelper {
public static String encrypt(String key,String enc) throws Exception {
// TODO Auto-generated method stub
byte[] iv1 = new byte[] { (byte) 0x81,0x12,0x39,(byte) 0x9C,0x07,0x72,0x6F,0x5A,(byte) 0x8E,0x17,0x71,0x61,0x5A };
StringBuilder sb = new StringBuilder();
for (byte b : iv1) {
sb.append(String.format("%02X",b));
}
System.out.println(sb.toString());
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv1);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"),"AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(1,skeySpec,paramSpec);
byte[] encrypted = cipher.doFinal(enc.getBytes());
String base64encodedString = Base64.getEncoder().encodeToString(encrypted);
// System.out.println(base64encodedString);
return base64encodedString;
}
public static String decrypt(String key,String encrypted) throws Exception {
byte[] keyAsB = key.getBytes("UTF-8");
SecretKeySpec skeySpec = new SecretKeySpec(keyAsB,"AES");
byte[] iv1 = new byte[] { (byte) 0x81,0x5A };
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv1);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(2,paramSpec);
byte[] encBytes = Base64.getDecoder().decode(encrypted.getBytes());
byte[] original = cipher.doFinal(encBytes);
return new String(original);
}
}
我编写的Python代码是
from Crypto.Cipher import AES
import base64
from Crypto import Random
aes_mode = AES.MODE_CBC
BS = 16
pad = lambda s: bytes(s + (BS - len(s) % BS) * chr(BS - len(s) % BS),'utf-8')
unpad = lambda s : s[0:-ord(s[-1:])]
class AESCipher:
def __init__( self,key,key_is_hex=True):
self.size = len(key)
if key_is_hex:
self.key = bytes.fromhex(key)
else:
self.key = bytes(key,'utf-8')
def encrypt( self,raw,padData=True):
raw = pad(raw)
iv = Random.new().read( AES.block_size )
cipher = AES.new(self.key,AES.MODE_CBC,iv )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self,enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key,iv )
d = cipher.decrypt( enc[16:])
return unpad(d).decode('utf8')
如果我使用Java程序并进行加密,则无法使用python代码正确解密
这是用于加密的Java代码
EncHelper.encrypt("skeyskeyskeyskey","ThisTextIsBeingEncryptedHere")
这将输出+CPCZOmJ67d7rwtt/afUaPciCfcUTZtJaFMCctnh2Qs=
cipher1 = AESCipher('skeyskeyskeyskey',False)
x = cipher1.decrypt("+CPCZOmJ67d7rwtt/afUaPciCfcUTZtJaFMCctnh2Qs=")
print(x)
这将输出ncryptedHere
而不是ThisTextIsBeingEncryptedHere
基本上,我在进行解密时会丢失一些字符。
这是什么问题?
解决方法
正在使用的AES模式是“ CBC”,需要初始化向量(iv)。在Java端,银行API使用固定的iv(即 UNSECURE )进行加密和解密,但未与加密端的密文连接。
您的Python代码使用的是RANDOM iv(很好),但它与密文(iv | ciphertext)串联在一起。在解密方面,您可以获取iv并解密其余内容-这就是某些文本似乎丢失的原因。
解决方案:对您的PYTHON代码使用相同的静态iv(与Java端相同)并解密完整的密文。