Python Implement AES in CBC encryption mode - python

I'm trying to complete this challenge online which asks to implement ourselves the AES CBC mode without using any library function that will do the job for me (ofc xD). I'm using python3.7 and PyCrypto for the AES modules (I'm a python beginner btw)
I'm at a point where I feel like I found the solution but it's not the case, I don't see what I'm doing wrong.
I'm entering this text: `
In september 2017 In september 2017 In september 2017 In september
2017
`
with this key:
YELLOW SUBMARINE
and with an 16 bytes long IV full of 0 (\x00)
but my ouput differs from the different websites I can find online or when using the AES CBC mode from the PyCrypto module
here's the small program that I made so far in order to generate my aes cbc encryption with comments:
#!/usr/bin/env python
from sys import argv
from Crypto.Cipher import AES
import codecs
def pad(plaintext):
padding_len = 16 - (len(plaintext) % 16)
print(padding_len)
if padding_len == 16:
return plaintext
padding = bytes([padding_len] * padding_len)
return plaintext + padding
def xor_for_char(input_bytes, key_input):
index = 0
output_bytes = b''
for byte in input_bytes:
if index >= len(key_input):
index = 0
output_bytes += bytes([byte ^ key_input[index]])
index += 1
return output_bytes
class AESCBCTool:
def __init__(self):
self.best_occurence = 0
self.best_line = 0
def encrypt_CBC(self, enc, key):
enc = pad(enc) # here I pad the text (PCKS#7 way)
nb_blocks = (int)(len(enc) / 16) #calculate the number of blocks I've to iter through
IV = bytearray(16)
cipher = AES.new(key, AES.MODE_ECB)
for i in range(nb_blocks):
enc2 = xor_for_char(enc[i * 16:(i + 1) * 16], IV) #xor a block with IV
IV = cipher.encrypt(enc2) # set the the IV based on the encryption of the xored text
print(codecs.decode(codecs.encode(IV, 'base64')).replace("\n", ""), end='') #print the encrypted text in base 64
def main(filepath):
f = open(filepath, "r")
if f.mode == 'r':
content = f.readlines()
tool = AESCBCTool()
for line_content in content:
tool.encrypt_CBC(bytes(line_content, "utf-8"), bytes("YELLOW SUBMARINE", "utf-8"))
f.close()
if __name__== "__main__":
try:
main(argv[1]) #this is the path to the file that contains the text
except Exception as e:
print(e)
exit(84)
exit(0)
here's my output:
0TKm+DjGff6fB/l0Z+M5TQ==8do1FSVvjbN2+MhAULmjHA==w5vZtuiL2SrtSLi2CkMBzQ==nvKLm7C7QDmSxk2PqV3NHQ==2+DSu4BqXskn8/znFCUCcQ==
meanwhile the output should be:
IS4p7kpY9g0a68AUzpKzazbtbP0h3nYZvhptuxNajBS3KIUHGI3fu79e4fw+E34miyn5dMBle8Tqn2DvHsromy7AupMy0zbtlqPwU5uHoyY=
Do you have any advice for me please?

Related

ValueError: IV must be 16 bytes long

I am trying to make a program to decrypt via python. The cipher used is AES-CBC.
But I get this error and I don't know how to fix it. Do you have any ideas?
Thanks in advance
#!/usr/bin/env python3
import base64
import binascii
from Crypto.Cipher import AES
key = "YELLOW SUBMARINE"
iv_dec = "a5f6ba42255643907a5bb3709840ca5b"
block_size = 16
pad_char = u"\00"
pad = lambda s: s + (block_size - len(s) % block_size) * pad_char
ciphertext = "412053617563657266756c206f662053656372657473"
# Decrypt
aes_dec = AES.new(str(key), AES.MODE_CBC, str(iv_dec))
decrypted = aes_dec.decrypt(ciphertext)
print ("Decrypted text: {} ".format(decrypted.rstrip(pad_char)))

Why is this AES CTR decryption not working as expected?

I'm trying to figure out what I'm doing wrong here. I'm doing the cryptography challenges over at CryptoPals.com and this particular one has me stumped. It asks for me to create my own implementation of CTR with the following parameters:
key=YELLOW SUBMARINE
nonce=0
format=64 bit unsigned little endian nonce,
64 bit little endian block count (byte count / 16)
I've actually done the challenge successfully but I can't figure out how to do it using a library. I wanted to compare the two. I've tried PyCrypto and I've tried cryptography.hazmat. They always produce a different result. I was hoping someone could spot what I was doing wrong.
This is my most recent attempt with Crypto.Cipher:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from Crypto.Cipher import AES
from Crypto.Util import Counter
import base64
class Custom_CTR:
def __init__(self, key):
self.aes_custom = Cipher(algorithms.AES(key), modes.ECB(), default_backend())
def custom_aes_128_ctr_keystream_generator(self, nonce, counter):
while True:
to_encrypt = (nonce.to_bytes(length=8, byteorder='little')
+ counter.to_bytes(length=8, byteorder='little'))
encryptor = self.aes_custom.encryptor()
keystream_block = encryptor.update(to_encrypt) + encryptor.finalize()
yield from keystream_block
counter += 1
def custom_aes_128_ctr_encrypt(self, nonce, counter, data):
result = b''
my_gen = self.custom_aes_128_ctr_keystream_generator(nonce, counter)
for i in range(len(data)):
result += bytes([next(my_gen) ^ data[i]])
return result
def pycrypto_aes_128_ctr_encrypt(key, data):
_ctr = Counter.new(128, initial_value=0, little_endian=True)
aes = AES.new(key, AES.MODE_CTR, counter=_ctr)
return aes.encrypt(data)
k = b'YELLOW SUBMARINE'
ctr = Custom_CTR(k)
enc = base64.b64decode(b'L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==')
print('custom ctr:', ctr.custom_aes_128_ctr_encrypt(0, 0, enc))
print('hazmat ctr:', pycrypto_aes_128_ctr_encrypt(k, enc))
Produces
custom ctr: b"Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby "
hazmat ctr: b"Yo, VIP Let's kic\x84q\x97A\xae\xdcZ#\xf2\xc4\xafc\xb1\xd8\xad8\xfb|\xb4\xd4\x17\x95\x9cX\x0ff\xb6\xf3\xb8\xb3Z\xfe\xff\x9b6"
Nevermind, I just solved it.
def pycrypto_aes_128_ctr_encrypt(key, data):
_ctr = Counter.new(64, initial_value=0, prefix=b'\x00'*8, little_endian=True)
aes = AES.new(key, AES.MODE_CTR, counter=_ctr)
return aes.encrypt(data)
Looks like this generates the parameters that I'm looking for. The counter is 8 bytes and the prefix (nonce) is 8 bytes.

same encryption between flutter and python [ AES ]

i want some example for encryption between python and flutter to encrypt request and response body between client and server
i found some example code for AES CRT encryption , but i cant see same result in flutter and python
can anybody help me ?
UPDATE :
Flutter crypt package not have counter parameter but python Crypto.Cipher package have counter parameter
this is sample code for python:
plaintext = '123'.encode('utf-8')
key = '12345678911234567891123456789123'.encode("utf-8")
iv = '12345'.encode('utf')
iv_int = int(binascii.hexlify(iv), 16)
ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
ciphertext = aes.encrypt(plaintext)
print('ctr = ' + str(ctr))
print('iv = ' + str(base64.b64encode(iv)))
print('iv_int = ' + str(iv_int))
print('plaintext = ' + str(plaintext))
print('key = ' + str(base64.b64encode(key)))
print('ciphertext = ' + str(base64.b64encode(ciphertext)))
this is sample code for flutter :
final plainText = '123';
final key = encrypt.Key.fromUtf8('12345678911234567891123456789123');
final iv = encrypt.IV.fromUtf8('12345');
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.ctr));
final encrypted = encrypter.encrypt(plainText, iv: iv);
final decrypted = encrypter.decrypt(encrypted, iv: iv);
print('key = ' + key.base64);
print('iv =' + iv.base64);
print('encrypted = ' + encrypted.base64);
I had the same issue and posted a very similar question. Fortunately, I found the error by myself.
Here is the link: Python AES CTR Mode only encrypts first two bytes
To summarize, the problem: Dart automatically uses the PKCS7 Padding when using AES Encryption, but Python does not anything like that.
So either you set the padding in your Dart code to null e.g.:
aes = AES.new(key, AES.MODE_CTR, counter=ctr, padding: null)
or you add a PKCS7 padding to your python code with like the following:
# The message has to in bytes format
def pkcs7padding(message):
pl = 16 - (len(message) % 16)
return message + bytearray([pl for i in range(pl)])
ciphertext = aes.encrypt(pkcs7padding(plaintext))

Why I am not able to decrypt what I encrypted with pycrypto?

Here's my code:
Encrypt:
from Crypto.Cipher import AES
import base64
def encryption (privateInfo):
BLOCK_SIZE = 16
PADDING = '{'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
secret = 'Fr3#k1nP#ssw0rd.'
print('encryption key:', secret)
cipher = AES.new(secret)
encoded = EncodeAES(cipher, privateInfo)
print('Encrypted string:', encoded)
encryption('secret')
The encrypted string is: b'QuCzNmwiVaq1uendvX7P+g=='
Decrypt:
from Crypto.Cipher import AES
import base64
def decryption(encryptedString):
PADDING = '{'
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
key = 'Fr3#k1nP#ssw0rd.'
cipher = AES.new(key)
decoded = DecodeAES(cipher, encryptedString)
print(decoded)
decryption("b'QuCzNmwiVaq1uendvX7P+g=='")
The result:
ValueError: Input strings must be a multiple of 16 in length
This is PyCrypto 2.6.1 on Python 3.4; I've installed VC++ 2010 Express as well.
What's really confusing me is that it works perfectly on Python 2.7
Any suggestion appreciated, but note that I'm new to Python.
After some research and a lot of coding, testing and improving, I made this code running on Python 3.4.4 and Windows 10:
import base64
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
PAD = "X"
def key_hash(key):
return SHA256.new(key.encode()).digest()
def encrypt(text, key):
while len(text) % 16 != 0:
text += PAD
cipher = AES.new(key_hash(key))
encrypted = cipher.encrypt(text.encode())
return base64.b64encode(encrypted).decode()
def decrypt(text, key):
cipher = AES.new(key_hash(key))
plain = cipher.decrypt(base64.b64decode(text))
return plain.decode().rstrip(PAD)
if __name__ == '__main__':
e = encrypt("This is my string.", "password")
p = decrypt(e, "password")
print("Encrypted:", e)
print("Plain:", p)
Output:
Encrypted: QjkhFlXG2tklZQgHorpAOFSTb2vYZLNb/eEUIvAsT1g=
Plain: This is my string.
If you have any questions/improvements/critics, feel free to comment!
Maybe because you have " around "b'QuCzNmwiVaq1uendvX7P+g=='".
Change
decryption("b'QuCzNmwiVaq1uendvX7P+g=='")
to
decryption(b'QuCzNmwiVaq1uendvX7P+g==')
and you should be all set.

why the AES result is different between Crypto and M2Crypto with Python?

i have two script in python , one is encrypt data using Crypto
from Crypto.Cipher import AES
from Crypto import Random
IV = 'c782dc4c098c66cb'
secrect_key = 'c286696d887c9aa0'
cipher = AES.new(secrect_key, AES.MODE_CFB, IV)
data = 'This is a 48-byte message (exactly 3 AES blocks)'
print repr(cipher.encrypt(data))
and the other using M2Crypto
import M2Crypto.EVP as EVP
import cStringIO
ENCRYPT_OP = 1
DECRYPT_OP = 0
def aes_encrypt(iv, secret_key, plain_text):
cipher = EVP.Cipher(alg='aes_128_cfb',
key=secret_key,
iv=iv,
op=ENCRYPT_OP)
input_buffer = cStringIO.StringIO(plain_text)
cipher_data1 = cipher.update(input_buffer.read())
cipher_data2 = cipher.final()
input_buffer.close()
output_buffer = cStringIO.StringIO()
output_buffer.write(cipher_data1)
output_buffer.write(cipher_data2)
cipher_text = output_buffer.getvalue()
output_buffer.close()
return cipher_text
IV = 'c782dc4c098c66cb' # 16 bytes
secrect_key = 'c286696d887c9aa0' # 16 bytes
data = 'This is a 48-byte message (exactly 3 AES blocks)'
cipher_text = aes_encrypt(IV, secrect_key, data)
print(repr(cipher_text))
i have pass the same argument to module, but i cannot get the same result, i don't know why.
and, is one of the result is vulnerability?

Categories

Resources