4

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.
  • 61,146
  • 24
  • 125
  • 222
Nilesh Vora
  • 191
  • 1
  • 3
  • 14

1 Answers1

5

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)
Nilesh Vora
  • 191
  • 1
  • 3
  • 14
  • 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? – Artjom B. Sep 23 '16 at 18:23
  • 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. – Nilesh Vora Sep 24 '16 at 05:04
  • 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). – Artjom B. Sep 24 '16 at 07:24
  • 1
    It is not secure to use (a slice of) the key as the IV: https://crypto.stackexchange.com/questions/16161/problems-with-using-aes-key-as-iv-in-cbc-mode – pors Feb 04 '18 at 10:19
  • 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. – caffeinate_me Jul 05 '19 at 13:54