AES解密——java到python码转换

AES decryption - java to python code conversion

我正在尝试与银行集成 API。这是银行提供的 Java 示例代码,用于执行 encryption/decryption.

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, 0x12, 0x39,
                (byte) 0x9C, 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, 0x12, 0x39, (byte) 0x9C,
                0x07, 0x72, 0x6F, 0x5A, (byte) 0x8E, 0x12, 0x39,
                (byte) 0x9C, 0x17, 0x71, 0x61, 0x5A };
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv1);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(2, skeySpec, 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, AES.MODE_CBC, 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-side银行API使用固定的iv(即UNSECURE)用于加密和解密,但在加密时不与密文连接边.

您的 Python 代码使用的是 RANDOM iv(这很好)但它与密文 (iv|ciphertext) 连接在一起。在解密方面,您获取 iv 并解密其余部分 - 这就是某些文本似乎丢失的原因。

解决方案:对您的PYTHON代码使用相同的静态iv(与Java端相同)并解密完整的密文。