繁体   English   中英

Python 和 Java 中的 AES-128 加密但溢出错误,无符号字节 integer 小于最小值

[英]AES-128 encryption in both Python and Java but overflow error,unsigned byte integer is less than minimum

我是 Python 的新手,并将用 Java 编写的AES加密重写为 Python,但发生了异常:

OverflowError 无符号字节 integer 小于最小值

将 32 字节密钥字符串转换为 16 字节长度的字节数组的算法是固定的,该算法在 function keyToBytes中实现,我不能使用其他方法,例如使用sha256到 hash 密钥字符串。

/**
 * custom algorithm to convert the string of key to bytes
 * @param key
 * @return
 */
public static byte[] keyToBytes(String key) {

    int length = key.length();//32 bytes
    byte[] bArr = new byte[(length / 2)]; //16 bytes length
    int a2 = 0;
    int b = 30;
    int c = 2;
    while (true) {
        int i = a2 + 2;
        if (i > length) {
            i = length - 1;
        }
        int i2 = a2 / 2;
        String substring = key.substring(a2, i);

        bArr[i2] = (byte) Integer.parseInt(substring, 16);
        if (a2 == b) {
            break;
        }
        a2 += c;
    }
    return bArr;
}

public static String aesEncrypt(byte[]key, String text) {

    try {
        IvParameterSpec ivParameterSpec = new IvParameterSpec(new byte[16]);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
        Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
        instance.init(1, secretKeySpec, ivParameterSpec);
        byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
        String result = Base64.getEncoder().encodeToString(instance.doFinal(bytes));
        return result;
    } catch (NoSuchAlgorithmException e) {
        System.out.println(e);
        return null;
    } catch (InvalidKeyException e) {
        System.out.println(e);
        return null;
    }  catch (IllegalBlockSizeException e) {
        System.out.println(e);
        return null;
    } catch (InvalidAlgorithmParameterException e) {
        System.out.println(e);
        return null;
    } catch (BadPaddingException e) {
        System.out.println(e);
        return null;
    } catch (NoSuchPaddingException e) {
        System.out.println(e);
        return null;
    }
}

public static void main(String[] args) {
    String key = "7e585aedb1dd597382cf5aaaabfa221d";
    byte [] keyInBytes = keyToBytes(key);
    System.out.println(Arrays.toString(keyInBytes));
    String text = "hello world";
    String ret = aesEncrypt(keyInBytes,text);
    System.out.println(ret);
}

output

[126, 88, 90, -19, -79, -35, 89, 115, -126, -49, 90, -86, -85, -6, 34, 29]
2gAIBaXGgTfepnHit0A7sg==
import base64
from Crypto.Cipher import AES
from Crypto import Random
import array
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
class AESChiper:

    def __init__(self, key):
        self.bs = 16
        self.key = array.array('B',key).tobytes()

    def encrypt(self, message):
        message = self._pad(message)
        iv = b'0'*16
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(message)).decode('utf-8')


    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]
    @staticmethod
    def keyToBytes(key:str):
        keyLength = len(key)
        bArr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        a2 = 0
        b = 30
        c = 2
        while True:
            i = a2 +2
            if  i > keyLength:
                i = keyLength - 1
            i2 = int(a2/2)
            substring = key[a2:i]

            num = int(substring,16)         
            ## convert hex string to decimal 
            ## 8 bits integer in 2's complement
            ## if the value not between -128 - 127 then do substraction
            if num > 127:      
                num = num - 256
            bArr[i2] = num 
            if a2 == b:
                break
            a2 = a2 + c
        return bArr



if __name__ == "__main__":
    key = "7e585aedb1dd597382cf5aaaabfa221d"
    text = 'hello world'
    keyInBytes = AESChiper.keyToBytes(key)
    print(keyInBytes)
    ciphter = AESChiper(keyInBytes)
    ret = ciphter.encrypt(text)
    print(ret)

output

[126, 88, 90, -19, -79, -35, 89, 115, -126, -49, 90, -86, -85, -6, 34, 29]
exception has occurred: OverflowError in  
self.key = array.array('B',key).tobytes()
unsigned byte integer is less than minimum

最终解决java中的问题

keyInBytes = keyToBytes("7e585aedb1dd597382cf5aaaabfa221d")

output

[126, 88, 90, -19, -79, -35, 89, 115, -126, -49, 90, -86, -85, -6, 34, 29]

对于此数组中的每个值都是十进制形式的有符号字节,范围为 -128 到 + 127 请注意,对于每对两个字符 7e 58 5a ed... 它使用 Interger.parseInt("ed",16) == int('ed',16) == 237 So, the represented 32 bits signed integer in both Python and Java, they are same But In Java, when the integer 237 was converted to byte, it's by default masked to 237 - 256 = -19

 if num > 127:      
    num = num - 256
bArr[i2] = num 

在 Python 方面,即使减去 256 并得到掩码值 -19,它仍然是一个 32 位,integer 不是有符号字节。

将 32 位有符号 integer 列表转换为字节形式

key = [126, 88, 90, -19, -79, -35, 89, 115, -126, -49, 90, -86, -85, -6, 34, 29]
keyInBytes = array.array('b',key).tobytes()

aes加密

def encrypt(self, message):
     message = self._pad(message)
     iv = array.array('b',[0]*16).tobytes()
     cipher = AES.new(self.key, AES.MODE_CBC, iv)
     return base64.b64encode(cipher.encrypt(message)).decode('utf-8')

output

2gAIBaXGgTfepnHit0A7sg==

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM