简体   繁体   中英

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

I am new to Python and rewriting AES encryption written in Java to Python, but got Exception has occurred:

OverflowError unsigned byte integer is less than minimum

The algorithm to convert 32 bytes key string to bytes array with 16 bytes length is fixed which implemented in function keyToBytes , I cannot use other approaches like using sha256 to a hash key string.

/**
 * 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

Finfally solve the problem In java

keyInBytes = keyToBytes("7e585aedb1dd597382cf5aaaabfa221d")

output

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

for each value in this array is signed byte in decimal form in range of -128 to + 127 Note that for each pair of two characters 7e 58 5a ed... it's converted with 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 

In Python side,even subtract by 256 and got masked value -19, it's still a 32 bits singed integer not a signed byte.

To Convert a list of 32-bits signed integer to bytes form

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

aes encryption

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==

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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