Reputation: 2348
I am trying to use pyaes
for AES encryption.
My below code is running perfectly.
text = 'Hello world !!!!'
encrypter = pyaes.AESModeOfOperationCBC('my_test_key_0001', 'my_test_vec_0001')
encrypted = base64.b64encode(encrypter.encrypt(text))
print(encrypted)
However, when I change the text value to
text = 'rO0ABXVyAAJbQqzzF/gGCFTgAgAAeHAAAAAI3z7LN2KbyKE='
It returns with error.
Traceback (most recent call last):
File "/home/path/cryptolib/test.py", line 54, in <module>
encrypted = base64.b64encode(encrypter.encrypt(text))
File "/home/path/pyaes/aes.py", line 389, in encrypt
raise ValueError('plaintext block must be 16 bytes')
ValueError: plaintext block must be 16 bytes
I am not expert on AES
so maybe missing basics.
I can not use pycrypto
because I am developing UDF
for redshift and according to my findings pycrypto
is not supported there.
Upvotes: 3
Views: 1857
Reputation: 49276
pyaes#AESModeOfOperationCBC
only allows the encryption of a text that is exactly one block (16 bytes) long. For longer texts BlockFeeder must be used:
import pyaes, base64
#Encryption
text = 'rO0ABXVyAAJbQqzzF/gGCFTgAgAAeHAAAAAI3z7LN2KbyKE='
encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC('my_test_key_0001', 'my_test_vec_0001'))
ciphertext = encrypter.feed(text)
ciphertext += encrypter.feed()
ciphertext = base64.b64encode(ciphertext)
#Decryption
decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC('my_test_key_0001', 'my_test_vec_0001'))
decrypted = decrypter.feed(base64.b64decode(ciphertext))
decrypted += decrypter.feed()
print('>' + decrypted + '<\n')
BlockFeeder also automatically perform the padding. Padding is the adding of data to the end of a message until the length corresponds to an integer multiple of the block length (generally important, but not relevant for your examples, since the length condition is already met).
EDIT:
Encrypter#feed(<plaindata>)
buffers the plaintext, encrypts the data except for the last block (if the last block is complete) or the last two blocks (if the last block is incomplete), and returns the encrypted data. The final Encrypter#feed()
call signals the end of the plaintext, triggers padding and encryption of the remainder, and returns the encrypted data. This can be
illustrated with the following code snippet:
import pyaes
#Encryption
encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC('my_test_key_0001', 'my_test_vec_0001'))
ciphertext = encrypter.feed ('0123456789ABCDEF') # 1. block buffered, ciphertext = ''
ciphertext += encrypter.feed('0123456789ABCDE') # 1. and incomplete 2. block buffered, ciphertext += ''
print("Current length of ciphertext: " + str(len(ciphertext)) + " Bytes\n")
ciphertext += encrypter.feed('F') # 1. block flushed, 2. block buffered, ciphertext += '<encrypted 1. block>'
print("Current length of ciphertext: " + str(len(ciphertext)) + " Bytes\n")
ciphertext += encrypter.feed('0123456789ABCDEF') # 2. block flushed, 3. block buffered, ciphertext += '<encrypted 2. block>'
print("Current length of ciphertext: " + str(len(ciphertext)) + " Bytes\n")
ciphertext += encrypter.feed('0123456') # 3. and incomplete 4. block buffered, ciphertext += ''
print("Current length of ciphertext: " + str(len(ciphertext)) + " Bytes\n")
ciphertext += encrypter.feed() # 3. and padded 4. block flushed, ciphertext += '<encrypted 3. and 4. padded block >'
print("Current length of ciphertext: " + str(len(ciphertext)) + " Bytes\n")
#Decryption
decrypter = pyaes.Decrypter(pyaes.AESModeOfOperationCBC('my_test_key_0001', 'my_test_vec_0001'))
decrypted = decrypter.feed(ciphertext)
decrypted += decrypter.feed()
print('>' + decrypted + '<\n')
In the example, the last block of plain text is incomplete. If the last block of the plain text is already complete, an additional complete block is padded. The padding used here is PKCS7.
Upvotes: 4