AES解密-Java至python代码转换

问题描述

我正在尝试与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端相同)并解密完整的密文。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...