Incorrect AES key length (89 bytes)

690 Views Asked by At

Can someone please guide us what we might be doing wrong here? The code crashes with "raise ValueError("Incorrect AES key length (%d bytes)" % len(key)) ValueError: Incorrect AES key length (89 bytes)"

Note: The file symmetric_key.txt contains the exact same sequence as the hardcoded variable i.e. [EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e

#!/usr/bin/python3

from Crypto import Random

from Crypto.Cipher import AES 

import os

import os.path

from os import listdir

from os.path import isfile, join

import time

import sys

class Encryptor:
    def __init__(self, key):
        self.key = key

    def pad(self, s):
        return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

    def encrypt(self, message, key, key_size=256):
        message = self.pad(message)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return iv + cipher.encrypt(message)

    def encrypt_file(self, file_name):
        with open(file_name, 'rb') as fo:
            plaintext = fo.read()
        enc = self.encrypt(plaintext, self.key)
        with open(file_name + ".enc", 'wb') as fo:
            fo.write(enc)
        os.remove(file_name)

    def decrypt(self, ciphertext, key):
        iv = ciphertext[:AES.block_size]
        cipher = AES.new(key, AES.MODE_CBC, iv)
        plaintext = cipher.decrypt(ciphertext[AES.block_size:])
        return plaintext.rstrip(b"\0")

    def decrypt_file(self, file_name):
        with open(file_name, 'rb') as fo:
            ciphertext = fo.read()
        dec = self.decrypt(ciphertext, self.key)
        with open(file_name[:-4], 'wb') as fo:
            fo.write(dec)
        os.remove(file_name)

    def getAllFiles(self):
        dir_path = os.path.dirname(os.path.realpath(__file__))
        dirs = []
        for dirName, subdirList, fileList in os.walk(dir_path):
            for fname in fileList:
                if (fname != 'encryptor_git.py' and fname != 'data.txt.enc'):
                    dirs.append(dirName + "\\" + fname)
        return dirs

    def encrypt_all_files(self):
        dirs = self.getAllFiles()
        for file_name in dirs:
            self.encrypt_file(file_name)

    def decrypt_all_files(self):
        dirs = self.getAllFiles()
        for file_name in dirs:
            self.decrypt_file(file_name)

## file fetching the symmetric key
with open("symmetric_key.txt", "rb") as k1:
    key_from_file = k1.read()
    
## this hardcoded key works fine
key = b'[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e'
key = key_from_file

print (type (key))


enc = Encryptor(key) ## created object of Encryptor class 
clear = lambda: os.system('cls') 


enc.encrypt_file(str(input("Enter name of file to encrypt: ")))            
1

There are 1 best solutions below

5
bereal On

The in-code version of the key is defined through a string literal. When Python interprets the line:

key = b'[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e'

it handles all the \xc8 kind of sequences and converts them to proper internal representation. On the other hand, the same string read from a file is left as is. I'd rather store the key in hex or base64 encoding, but if you have to deal with what you have, you can use e.g. ast.literal_eval:

key = ast.literal_eval(f'"{key_from_file}"')

Update: if key_from_file is bytes, not string, like in your example, the quotes are redundant, e.g.

key = ast.literal_eval(str(key_from_file))

That all said, the more reliable way is to use base64 to store the key.