I have found the following code to encrypt an excel file in python. However, I noticed that it is only able to use passwords/key of length 16 or 32 characters in order to encrypt the file. I would like the user to be able to use any length passwords from 8 - 32 characters to encrypt the file. I was thinking that maybe the user could put in a password with 8 characters, and then I could add in some filler characters to get it to a length of 16. However, this does not seem like an idea that is used.
Hence I was wondering how else could I create a key of different length to encrypt the file?
def pad(s):
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)
def encrypt(message, key, key_size=256):
message = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
def decrypt(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 encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
with open(file_name[:-4], 'wb') as fo:
fo.write(dec)
encryptPassword = "some 16 or 32 character password"
key = encryptPassword.encode("utf8")
encrypt_file(excelSheet, key)
Related
Hi I'm programming a basic project about Shamir Secret Sharing but I having a problem while decrypting a file.
I'm using AES to encrypt and decrypt
My code to encrypt:
def encrypt_text(self, text):
pad_text = pad(text, AES.block_size)
iv = Random.new().read(AES.block_size)
password = self.alphanumric_pass(self.key)
cipher = AES.new(password, AES.MODE_CBC, iv)
return iv + cipher.encrypt(pad_text)
def encrypt_file(self):
try:
with open(self.file, 'rb') as f:
orig_file = f.read()
enc_text = self.encrypt_text(orig_file)
except:
print("The file: " + str(self.file) + " does not exist")
sys.exit(1)
return enc_text
def save_encrypted_file(self, out_name):
with open(self.file + ".aes", 'wb') as f:
f.write(self.encrypt_file())
def alphanumric_pass(self, key):
num = str(key)
return hashlib.sha256(num.encode('utf8')).digest()
My code to decrypt:
def decrypt_text(self, text, key):
iv = text[:AES.block_size]
password = self.alphanumric_pass(key)
cipher = AES.new(password, AES.MODE_CBC, iv)
decrypted_text = unpad(cipher.decrypt(text[AES.block_size:]), AES.block_size)
return decrypted_text
def decipher_file(self):
try:
with open(self.file, 'rb') as f:
encrypted_file = f.read()
except:
print("There was an error while reading " + str(self.file))
secret = self.get_secret()
num = str(secret)
key = hashlib.sha256(num.encode('utf-8')).digest()
decrypted_text = self.decrypt_text(encrypted_file, key)
return decrypted_text
def get_secret(self):
return LagrangeInterpolation.reconstruct_secret(self.shares, 0)
def save_decrypted_file(self, new_name):
with open(new_name, 'wb') as f:
f.write(self.decipher_file())
But when I'm trying to decrypt a file I get this error:
File "/home/david/Documentos/Modelado_Y_Programacion/Shamir-Secret-Share-Scheme/s4/Decrypter.py", line 38, in decrypt_text
decrypted_text = unpad(cipher.decrypt(text[AES.block_size:]), AES.block_size)
File "/home/david/.local/lib/python3.7/site-packages/Crypto/Cipher/_mode_cbc.py", line 246, in decrypt
raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size)
ValueError: Data must be padded to 16 byte boundary in CBC mode
Can someone help fix this error? I have been hours searching how to fix it, but can't find anything
I am trying to encrypt/decrypt with pycrypto in python. for the most part things have worked smooth but I am getting an odd problem when decrypting data.I have tried to encrypt/decrypt some jpgs for testing and although they encrypt/decrypt without issue, the decrypted files cannot be opened/are corrupted. To try to find the problem I saved a textfile with a random sentence similar to "test this file for integrity blah blah blah" and it decrypts correctly only after ".... integrity blah blah blah", everything before integrity is still in garbled characters. I'm not that knowledgable on AES, but im assuming that this is an encoding/decoding or padding error.
Here is my code:
#encryption
iv = Random.new().read( AES.block_size)
filePath = input("Path to file for encryption: ")
selFile = open(filePath, 'rb')
getBytes = bytes(selFile.read())
encPW = input("Enter password: ")
hashpw = hashlib.sha256(encPW.encode('UTF-8').digest())
destination = input("Destination path for encrypted file: ")
aes = AES.new(hashpw, AES.Mode_CFB, iv)
encFile = base65.b64encode(aes.encrypt(getBytes))
writetofile = open(destination, 'wb')
writetofile.write(encFile)
writetofile.close()
print("Encryption successful")
#Decryption
iv = Random.new().read( AES.block_size)
filePath = input("Path to file for decryption: ")
selFile = open(filePath, 'rb')
getBytes = bytes(selFile.read())
decPW = input("Enter password: ")
hashdecpw = hashlib.sha256(encPW.encode('UTF-8').digest())
destination = input("Destination path for decrypted file: ")
aes = AES.new(hashdecpw, AES.Mode_CFB, iv)
decFile = aes.decrypt(getBytes)
writetofile = open(destination, 'wb')
writetofile.write(decFile)
writetofile.close()
print("Decryption successful")
Any ideas on what could be causing the loss of the first characters, and preventing me from encrypting/decrypting files correctly?
You have at least three issues:
You probably mean hashlib.sha256(encPW.encode('UTF-8')).digest() instead of hashlib.sha256(encPW.encode('UTF-8').digest()) (the closing brace is at the wrong position)
You're encoding the ciphertext with Base64 before writing it to a file. You've forgot to decode it after reading it back from the file before decrypting it. For example:
getBytes = base64.b64decode(bytes(selFile.read()))
This is the big one: You need the exact same IV during the decryption that you've used for encryption. The IV is not secret, but it needs to be unique for every encryption that you've done with the same key. Commonly the IV is written in front of the ciphertext and read back for decryption.
#encryption
encFile = base64.b64encode(iv + aes.encrypt(getBytes))
#decryption
getBytes = base64.b64decode(bytes(selFile.read()))
iv = getBytes[:16]
aes = AES.new(hashdecpw, AES.Mode_CFB, iv)
decFile = aes.decrypt(getBytes[16:])
You're generating a new IV for encryption and decryption seperately, which comes to yield such problems. Here's what I recommend doing:
def encrypt(inpath, outpath, password):
iv = Random.new().read(AES.block_size)
with open(inpath, "rb") as f:
contents = f.read()
# A context manager automatically calls f.close()
key = pbkdf2.crypt(password, "")
# See notes
aes = AES.new(key, AES.Mode_CFB, iv)
encrypted = aes.encrypt(contents)
with open(outpath, "wb") as f:
f.write(iv + b":")
f.write(encrypted)
print("Encryption successful")
def decrypt(inpath, outpath, password):
with open(inpath, "rb") as f:
contents = f.read()
iv, encrypted = contents.split(b":")
key = pbkdf2.crypt(password, "")
aes = AES.new(key, AES.Mode_CFB, iv)
decrypted = aes.decrypt(contents)
with open(outpath, "wb") as f:
f.write(decrypted)
print("Decryption successful")
Some notes:
An IV is not meant to be secret, so it can be randomly generated once and then written to a file to be used later for decryption (as shown in this example)
A hashing algorithm is not strong enough for deriving keys, which is why there are special tools called key derivation algorithms (like PBKDF2 in python). Use those instead!
I have not tested this code myself, so it may not work properly.
Overview of what I'm trying to do. I have encrypted versions of files that I need to read into pandas. For a couple of reasons it is much better to decrypt into a stream rather than a file, so that's my interest below although I also attempt to decrypt to a file just as an intermediate step (but this also isn't working).
I'm able to get this working for a csv, but not for either hdf or stata (I'd accept an answer that works for either hdf or stata, though the answer might be the same for both, which is why I'm combining in one question).
The code for encrypting/decrypting files is taken from another stackoverflow question (which I can't find at the moment).
import pandas as pd
import io
from Crypto import Random
from Crypto.Cipher import AES
def pad(s):
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)
def encrypt(message, key, key_size=256):
message = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
def decrypt(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 encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
with open(file_name[:-4], 'wb') as fo:
fo.write(dec)
And here's my attempt to extend the code to decrypt to a stream rather than a file.
def decrypt_stream(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
cipherbyte = io.BytesIO()
cipherbyte.write(dec)
cipherbyte.seek(0)
return cipherbyte
Finally, here's the sample program with sample data attempting to make this work:
key = 'this is an example key'[:16]
df = pd.DataFrame({ 'x':[1,2], 'y':[3,4] })
df.to_csv('test.csv',index=False)
df.to_hdf('test.h5','test',mode='w')
df.to_stata('test.dta')
encrypt_file('test.csv',key)
encrypt_file('test.h5',key)
encrypt_file('test.dta',key)
decrypt_file('test.csv.enc',key)
decrypt_file('test.h5.enc',key)
decrypt_file('test.dta.enc',key)
# csv works here but hdf and stata don't
# I'm less interested in this part but include it for completeness
df_from_file = pd.read_csv('test.csv')
df_from_file = pd.read_hdf('test.h5','test')
df_from_file = pd.read_stata('test.dta')
# csv works here but hdf and stata don't
# the hdf and stata lines below are what I really need to get working
df_from_stream = pd.read_csv( decrypt_stream('test.csv.enc',key) )
df_from_stream = pd.read_hdf( decrypt_stream('test.h5.enc',key), 'test' )
df_from_stream = pd.read_stata( decrypt_stream('test.dta.enc',key) )
Unfortunately I don't think I can shrink this code anymore and still have a complete example.
Again, my hope would be to have all 4 non-working lines above working (file and stream for hdf and stata) but I'm happy to accept an answer that works for either the hdf stream alone or the stata stream alone.
Also, I'm open to other encryption alternatives, I just used some existing pycrypto-based code that I found here on SO. My work explicitly requires 256-bit AES but beyond that I'm open so this solution needn't be based specifically on the pycrypto library or the specific code example above.
Info on my setup:
python: 3.4.3
pandas: 0.17.0 (anaconda 2.3.0 distribution)
mac os: 10.11.3
The biggest issue is the padding/unpadding method. It assumes that the null character can't be part of the actual content. Since stata/hdf files are binary, it's safer to pad using the number of extra bytes we use, encoded as a character. This number will be used during unpadding.
Also for this time being, read_hdf doesn't support reading from a file like object, even if the API documentation claims so. If we restrict ourselves to the stata format, the following code will perform what you need:
import pandas as pd
import io
from Crypto import Random
from Crypto.Cipher import AES
def pad(s):
n = AES.block_size - len(s) % AES.block_size
return s + n * chr(n)
def unpad(s):
return s[:-ord(s[-1])]
def encrypt(message, key, key_size=256):
message = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
def decrypt(ciphertext, key):
iv = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext[AES.block_size:])
return unpad(plaintext)
def encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_stream(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
cipherbyte = io.BytesIO()
cipherbyte.write(dec)
cipherbyte.seek(0)
return cipherbyte
key = 'this is an example key'[:16]
df = pd.DataFrame({
'x': [1,2],
'y': [3,4]
})
df.to_stata('test.dta')
encrypt_file('test.dta', key)
print pd.read_stata(decrypt_stream('test.dta.enc', key))
Output:
index x y
0 0 1 3
1 1 2 4
In python 3 you can use the following pad, unpad versions:
def pad(s):
n = AES.block_size - len(s) % AES.block_size
return s + bytearray([n] * n)
def unpad(s):
return s[:-s[-1]]
What worked for me in the case of .h5 format and the cryptography library was:
from cryptography.fernet import Fernet
def read_h5_file(new_file:str, decrypted: bytes, verbose=False):
with open(new_file, 'wb') as f:
f.write(decrypted)
print(f'Created {new_file}') if verbose else ''
df = pd.read_hdf(new_file)
os.remove(new_file)
print(f'Deleted {new_file}') if verbose else ''
return df
with open(path_to_file, 'rb') as f:
data = f.read()
fernet = Fernet(key)
decrypted = fernet.decrypt(data)
new_file = './example_path/example.h5'
df = read_h5_file(new_file, decrypted, verbose=verbose)
So I created a .h5 file. Read its content. Return it with the function. Delete the decrypted file again.
Maybe this approach helps, as I didn't find any other or similar solution on this online.
I already have a working program, but the only thing that doesn't work is the decrypt_file() function I have. I can still copy the encrypted text from the file and put it in my decrypt() function and have it work, but when I try to use my supposed-to-be handy decrypt_file() function it throws an error. Now I know 99.999% sure that my encrypt() and decrypt() functions are fine, but there is something with the bytes and strings conversion when I read and encode the text file that throws an error; I just can't find the hangup. Please help!
My Program:
from Crypto import Random
from Crypto.Cipher import AES
def encrypt(message, key=None, key_size=256):
def pad(s):
x = AES.block_size - len(s) % AES.block_size
return s + ((bytes([x])) * x)
padded_message = pad(message)
if key is None:
key = Random.new().read(key_size // 8)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(padded_message)
def decrypt(ciphertext, key):
unpad = lambda s: s[:-s[-1]]
iv = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext))[AES.block_size:]
return plaintext
def encrypt_file(file_name, key):
f = open(file_name, 'r')
plaintext = f.read()
plaintext = plaintext.encode('utf-8')
enc = encrypt(plaintext, key)
f.close()
f = open(file_name, 'w')
f.write(str(enc))
f.close()
def decrypt_file(file_name, key):
def pad(s):
x = AES.block_size - len(s) % AES.block_size
return s + ((str(bytes([x]))) * x)
f = open(file_name, 'r')
plaintext = f.read()
x = AES.block_size - len(plaintext) % AES.block_size
plaintext += ((bytes([x]))) * x
dec = decrypt(plaintext, key)
f.close()
f = open(file_name, 'w')
f.write(str(dec))
f.close()
key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
encrypt_file('to_enc.txt', key)
The text file I encrypted:
b';c\xb0\xe6Wv5!\xa3\xdd\xf0\xb1\xfd2\x90B\x10\xdf\x00\x82\x83\x9d\xbc2\x91\xa7i M\x13\xdc\xa7'
My error when attempting decrypt_file:
Traceback (most recent call last):
File "C:\Python33\testing\test\crypto.py", line 56, in <module>
decrypt_file('to_enc.txt', key)
File "C:\Python33\testing\test\crypto.py", line 45, in decrypt_file
plaintext += ((bytes([x]))) * x
TypeError: Can't convert 'bytes' object to str implicitly
[Finished in 1.5s]
When I replace line 45 with: plaintext += ((str(bytes([x])))) * x, this is the error I get:
Traceback (most recent call last):
File "C:\Python33\testing\test\crypto.py", line 56, in <module>
decrypt_file('to_enc.txt', key)
File "C:\Python33\testing\test\crypto.py", line 46, in decrypt_file
dec = decrypt(plaintext, key)
File "C:\Python33\testing\test\crypto.py", line 23, in decrypt
plaintext = unpad(cipher.decrypt(ciphertext))[AES.block_size:]
File "C:\Python33\lib\site-packages\Crypto\Cipher\blockalgo.py", line 295, in decrypt
return self._cipher.decrypt(ciphertext)
ValueError: Input strings must be a multiple of 16 in length
[Finished in 1.4s with exit code 1]
I took a closer look at your code, and saw that there were several problems with it. First one is that the crypto functions with with bytes, not text. So it's better to just keep the data as a byte string. This is done simply by putting a 'b' character in the mode. This way you can get rid of all the encoding and bytes conversion you were trying to do.
I rewrote the whole code also using newer Python idioms. Here it is.
#!/usr/bin/python3
from Crypto import Random
from Crypto.Cipher import AES
def pad(s):
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)
def encrypt(message, key, key_size=256):
message = pad(message)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
def decrypt(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 encrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
plaintext = fo.read()
enc = encrypt(plaintext, key)
with open(file_name + ".enc", 'wb') as fo:
fo.write(enc)
def decrypt_file(file_name, key):
with open(file_name, 'rb') as fo:
ciphertext = fo.read()
dec = decrypt(ciphertext, key)
with open(file_name[:-4], 'wb') as fo:
fo.write(dec)
key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
encrypt_file('to_enc.txt', key)
#decrypt_file('to_enc.txt.enc', key)
In Python 3 (which you are clearly using) the default mode for files you open is text, not binary. When you read from the file, you get strings rather than byte arrays. That does not go along with encryption.
In your code, you should replace:
open(file_name, 'r')
with:
open(file_name, 'rb')
The same for when you open the file for writing. At that point, you can get rid of all the various occurrences where you convert from string to binary and vice versa.
For instance, this can go away:
plaintext = plaintext.encode('utf-8')
I just found pycrypto today, and I've been working on my AES encryption class. Unfortunately it only half-works. self.h.md5 outputs md5 hash in hex format, and is 32byte.
This is the output. It seems to decrypt the message, but it puts random characters after decryption, in this case \n\n\n... I think I have a problem with block size of self.data, anyone know how to fix this?
Jans-MacBook-Pro:test2 jan$ ../../bin/python3 data.py
b'RLfGmn5jf5WTJphnmW0hXG7IaIYcCRpjaTTqwXR6yiJCUytnDib+GQYlFORm+jIctest
1 2 3 4 5 endtest\n\n\n\n\n\n\n\n\n\n'
from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from os import urandom
class Encryption():
def __init__(self):
self.h = Hash()
def values(self, data, key):
self.data = data
self.key = key
self.mode = AES.MODE_CBC
self.iv = urandom(16)
if not self.key:
self.key = Cfg_Encrypt_Key
self.key = self.h.md5(self.key, True)
def encrypt(self, data, key):
self.values(data, key)
return b64encode(self.iv + AES.new(self.key, self.mode, self.iv).encrypt(self.data))
def decrypt(self, data, key):
self.values(data, key)
self.iv = b64decode(self.data)[:16]
return AES.new(self.key, self.mode, self.iv).decrypt(b64decode(self.data)[16:])
To be honest, the characters "\n\n\n\n\n\n\n\n\n\n" don't look that random to me. ;-)
You are using AES in CBC mode. That requires length of plaintext and ciphertext to be always a multiple of 16 bytes. With the code you show, you should actually see an exception being raised when data passed to encrypt() does not fulfill such condition. It looks like you added enough new line characters ('\n' to whatever the input is until the plaintext happened to be aligned.
Apart from that, there are two common ways to solve the alignment issue:
Switch from CBC (AES.MODE_CBC) to CFB (AES.MODE_CFB). With the default segment_size used by PyCrypto, you will not have any restriction on plaintext and ciphertext lengths.
Keep CBC and use a padding scheme like PKCS#7, that is:
before encrypting a plaintext of X bytes, append to the back as many bytes you need to to reach the next 16 byte boundary. All padding bytes have the same value: the number of bytes that you are adding:
length = 16 - (len(data) % 16)
data += bytes([length])*length
That's Python 3 style. In Python 2, you would have:
length = 16 - (len(data) % 16)
data += chr(length)*length
after decrypting, remove from the back of the plaintext as many bytes as indicated by padding:
data = data[:-data[-1]]
Even though I understand in your case it is just a class exercise, I would like to point out that it is insecure to send data without any form of authentication (e.g. a MAC).
You can use a fix character as long as you remember the length of your initial payload, so you don't "throw" useful end bytes away.
Try this:
import base64
from Crypto.Cipher import AES
def encrypt(payload, salt, key):
return AES.new(key, AES.MODE_CBC, salt).encrypt(r_pad(payload))
def decrypt(payload, salt, key, length):
return AES.new(key, AES.MODE_CBC, salt).decrypt(payload)[:length]
def r_pad(payload, block_size=16):
length = block_size - (len(payload) % block_size)
return payload + chr(length) * length
print(decrypt(encrypt("some cyphertext", "b" * 16, "b" * 16), "b" * 16, "b" * 16, len("some cyphertext")))
from hashlib import md5
from Crypto.Cipher import AES
from Crypto import Random
import base64
def derive_key_and_iv(password, salt, key_length, iv_length):
d = d_i = ''
while len(d) < key_length + iv_length:
d_i = md5(d_i + password + salt).digest()
d += d_i
return d[:key_length], d[key_length:key_length+iv_length]
def encrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
salt = Random.new().read(bs - len('Salted__'))
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
#print in_file
in_file = file(in_file, 'rb')
out_file = file(out_file, 'wb')
out_file.write('Salted__' + salt)
finished = False
while not finished:
chunk = in_file.read(1024 * bs)
if len(chunk) == 0 or len(chunk) % bs != 0:
padding_length = bs - (len(chunk) % bs)
chunk += padding_length * chr(padding_length)
finished = True
out_file.write(cipher.encrypt(chunk))
in_file.close()
out_file.close()
def decrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
in_file = file(in_file, 'rb')
out_file = file(out_file, 'wb')
salt = in_file.read(bs)[len('Salted__'):]
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
next_chunk = ''
finished = False
while not finished:
chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs))
if len(next_chunk) == 0:
padding_length = ord(chunk[-1])
if padding_length < 1 or padding_length > bs:
raise ValueError("bad decrypt pad (%d)" % padding_length)
# all the pad-bytes must be the same
if chunk[-padding_length:] != (padding_length * chr(padding_length)):
# this is similar to the bad decrypt:evp_enc.c from openssl program
raise ValueError("bad decrypt")
chunk = chunk[:-padding_length]
finished = True
out_file.write(chunk)
in_file.close()
out_file.close()
def encode(in_file, out_file):
in_file = file(in_file, 'rb')
out_file = file(out_file, 'wb')
data = in_file.read()
out_file.write(base64.b64encode(data))
in_file.close()
out_file.close()
def decode(in_file, out_file):
in_file = file(in_file, 'rb')
out_file = file(out_file, 'wb')
data = in_file.read()
out_file.write(base64.b64decode(data))
in_file.close()
out_file.close()
AES.new().encrypt() and .decrypt() take as both input and output strings whose length is a multiple of 16. You have to fix it in one way or another. For example you can store the real length at the start, and use that to truncate the decrypted string.
Note also that while it's the only restriction for AES, other modules (notably in Crypto.PublicKey) have additional restrictions that comes from their mathematical implementation and that shouldn't (in my opinion) be visible to the end user, but are. For example Crypto.PublicKey.ElGamal will encrypt any short string, but if it starts with null characters, they are lost upon decryption.