Skipping Elif Statement?
Solution 1:
Ok, let's fix a few things that are wrong with your code. First the most obvious one - your padding would break on Python 3.5+ (and your user 'menu' would break on 2.x) because infile.read()
would give you bytes
array so trying to add a string formed by chunk += ' ' * (16 - (len(chunk) % 16))
would result in an error. You would need to convert your whitespace pad to bytes
array first: chunk += b' ' * (16 - (len(chunk) % 16))
But whitespace padding like this is a bad idea - when you're later decrypting your file how will you know how much, if any, padding you've added? You need to store this somewhere - and you do in the 'header' via the filesize
value, telling a potential attacker how exactly big is your file and how much padding was added opening you to a padding oracle attack (which is possible with the bellow code so do not use it for passing messages without adding a proper MAC to it).
There are plenty of robust padding schemes that you can use - I personally prefer PKCS#7 which is simply padding your uneven block or adding a whole new block with n
number of bytes with the value of n
- that way, after decryption, you can pick the last byte from your block and know exactly how many bytes were padded so you can strip them. So, replace your encryption portion with:
defencrypt(key, filename):
outputfile = filename + "(encrypted)"
chunksize = 1024 * AES.block_size # use the cipher's defined block size as a multiplier
IV = bytes([random.randint(0, 0xFF) for _ inrange(AES.block_size)]) # bytes immediately
encryptor = AES.new(key, AES.MODE_CBC, IV)
withopen(filename, 'rb') as infile:
withopen(outputfile, 'wb') as outfile:
outfile.write(IV) # write the IV
padded = Falsewhilenot padded: # loop until the last block is padded
chunk = infile.read(chunksize)
chunk_len = len(chunk)
# if no more data or the data is shorter than the required block sizeif chunk_len == 0or chunk_len % AES.block_size != 0:
padding = AES.block_size - (chunk_len % AES.block_size)
chunk += bytes([padding]) * padding
# on Python 2.x replace with: chunk += chr(padding_len) * padding_len
padded = True
outfile.write(encryptor.encrypt(chunk))
I've also changed your chunksize
to match the block size you're using (multiples of AES.block_size
) - it just happens that 64 is a multiple of 16 but you should pay attention to those things.
Now that we have the encryption sorted out, the decryption is all this but in reversal - decrypt all blocks, read the last byte of the last block and remove n
amount of bytes from behind matching the value of the last byte:
defdecrypt(key, filename):
outputfile = filename[:-11] + "(decrypted)"
chunksize = 1024 * AES.block_size # use the cipher's defined block size as a multiplierwithopen(filename, 'rb') as infile:
IV = infile.read(AES.block_size)
decryptor = AES.new(key, AES.MODE_CBC, IV)
withopen(outputfile, 'wb') as outfile:
old_chunk = b''# stores last chunk, needed for reading data with a delay
stripped = Falsewhilenot stripped: # delayed loop until the last block is stripped
chunk = decryptor.decrypt(infile.read(chunksize)) # decrypt as we readiflen(chunk) == 0: # no more data
padding = old_chunk[-1] # pick the padding value from the last byteif old_chunk[-padding:] != bytes([padding]) * padding:
raise ValueError("Invalid padding...")
old_chunk = old_chunk[:-padding] # strip the padding
stripped = True
outfile.write(old_chunk) # write down the 'last' chunk
old_chunk = chunk # set the new chunk for checking in the next loop
Post a Comment for "Skipping Elif Statement?"