AES-CBC 128, 192 and 256 encryption decryption in Python 3 using PKCS#7 padding

13,978

Made it working by padding of 16 bytes for any encryption types. For that I used AES.block_size which is 16 by default for AES.

import base64
from Crypto.Cipher import AES

class AESCipher:
    class InvalidBlockSizeError(Exception):
        """Raised for invalid block sizes"""
        pass

    def __init__(self, key):
        self.key = key
        self.iv = bytes(key[0:16], 'utf-8')
        print(self.key)
        print(key[0:16])

    def __pad(self, text):
        text_length = len(text)
        amount_to_pad = AES.block_size - (text_length % AES.block_size)
        if amount_to_pad == 0:
            amount_to_pad = AES.block_size
        pad = chr(amount_to_pad)
        return text + pad * amount_to_pad

    def __unpad(self, text):
        pad = ord(text[-1])
        return text[:-pad]

    def encrypt( self, raw ):
        raw = self.__pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(cipher.encrypt(raw)) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
        return self.__unpad(cipher.decrypt(enc).decode("utf-8"))

e = AESCipher('1234567812345678', 16)
#e = AESCipher('123456781234567812345678', 24)
#e = AESCipher('12345678123456781234567812345678', 32)
secret_data = "hi"
enc_str = e.encrypt(secret_data)
print('enc_str: ' + enc_str.decode())
dec_str = e.decrypt(enc_str)
print('dec str: ' + dec_str)
Share:
13,978
Nilesh Vora
Author by

Nilesh Vora

Embedded Software developer at Dryad Networks Gmbh, Berlin

Updated on June 09, 2022

Comments

  • Nilesh Vora
    Nilesh Vora almost 2 years

    I have searched a lot on SO about complete encryption decryption example with my requirement. In fact, I've got many links and examples but None is working for me for AES-192-CBC mode and AES-256-CBC.

    I have got following example which is supposed to be working with all types but it is working only with AES-128-CBC mode. I am new to Python. Can anyone help me where I am wrong?

    I am using Python 3.4 on windows and I can not move to Python 2.7.

    import base64
    from Crypto.Cipher import AES
    
    class AESCipher:
        class InvalidBlockSizeError(Exception):
            """Raised for invalid block sizes"""
            pass
    
        def __init__(self, key, block_size=16):
            if block_size < 2 or block_size > 255:
                raise AESCipher.InvalidBlockSizeError('The block size must be between 2 and 255, inclusive')
            self.block_size = block_size
            self.key = key
            self.iv = bytes(key[0:16], 'utf-8')
            print(self.key)
            print(key[0:16])
    
        def __pad(self, text):
            text_length = len(text)
            amount_to_pad = self.block_size - (text_length % self.block_size)
            if amount_to_pad == 0:
                amount_to_pad = self.block_size
            self.pad = chr(amount_to_pad)
            return text + self.pad * amount_to_pad
    
        def __unpad(self, text):
            #pad = ord(text[-1])
            #return text[:-pad]
            text = text.rstrip(self.pad)
            return text
    
        def encrypt( self, raw ):
            raw = self.__pad(raw)
            cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
            return base64.b64encode(cipher.encrypt(raw)) 
    
        def decrypt( self, enc ):
            enc = base64.b64decode(enc)
            cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
            return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
    
    e = AESCipher('1234567812345678', 16)
    #e = AESCipher('123456781234567812345678', 24)
    #e = AESCipher('12345678123456781234567812345678', 32)
    secret_data = "hi"
    enc_str = e.encrypt(secret_data)
    print('enc_str: ' + enc_str.decode())
    dec_str = e.decrypt(enc_str)
    print('dec str: ' + dec_str)
    

    Though this code encrypts the data with 192 and 256 bit encryption and successfully decrypt that too but my other .Net and Ruby application only able to decrypt the data which was encrypted using 128 encryption.

    Note .Net and Ruby application are successfully tested with each other and with online encryption tool with all encryption types.

    Note that my application requires AES-CBC mode and PKCS#7 padding and must be run on Python 3.4.

  • Artjom B.
    Artjom B. over 7 years
    I don't understand this answer. You've changed self.block_size to 16, but block_size was initialized with 16 so nothing should have changed. Have you changed something else?
  • Nilesh Vora
    Nilesh Vora over 7 years
    please read the question fully. I have wrote that when I took 24 and 32 block size then it was not working. because previously black size initialized with what is passed in argument. See __pad function and commented code man.
  • Artjom B.
    Artjom B. over 7 years
    I see. I haven't seen your commented code. Still, the 256 in AES-256 always means the key size not the block size, because as you probably already learned, AES has a single fixed block size of 16 byte and you can get this with AES.block_size in pyCrypto. You don't need to hard code this. Since you don't need to pass in the block size during initialization, you should include that code in your answer (ping me when you're done, so I can remove my downvote).
  • pors
    pors over 6 years
    It is not secure to use (a slice of) the key as the IV: crypto.stackexchange.com/questions/16161/…
  • caffeinate_me
    caffeinate_me almost 5 years
    The _pad function is unnecessarily expanding the text as amount_to_pad because n % m will never equal m. Also plus 1 to comment about IV coming from key being a fail.