avitase
avitase

Reputation: 144

pycrypto does not reproduce NIST test vectors for AES (CFB mode)

This small python program should encrypt plain to cipher using AES in the CFB mode using a 128bit key

from Crypto.Cipher import AES

#            1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16
key   = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
iv    = b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
plain = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

aes = AES.new(key, AES.MODE_CFB, iv)
cipher = aes.encrypt(plain)

print(' '.join('{:2x}'.format(b) for b in cipher))

I took this key, IV and plain cipher combination from one of the NIST test vectors (CFB128VarTxt128.rsp). For this particular combination I expect the cipher:

3a d7 8e 72 6c 1e c0 2b 7e bf e9 2b 23 d9 ec 34

but pycrypto calculates

3a 81 e1 d4 b8 24 75 61 46 31 63 4b 5c 79 d6 bc

The first byte is correct, whereas the others do not match. I also tried different test vectors, but the result stays the same. All bytes, except for the first byte, do not match.

I am quite sure, that the NIST test vectors are valid since I used them before when using AES with Crypto++ and I am also pretty sure, that the implementation of pycrypto is correct since its output agrees with online tools such as this page. Obviously, it is me, who is using the tools in an incorrect way...

Does anyone have a clue, how to reproduce the NIST test vectors with pycrypto?

This is the NIST example

# CAVS 11.1
# Config info for aes_values
# AESVS VarTxt test data for CFB128
# State : Encrypt and Decrypt
# Key Length : 128
# Generated on Fri Apr 22 15:11:53 2011
...
COUNT = 0
KEY = 00000000000000000000000000000000
IV = 80000000000000000000000000000000
PLAINTEXT = 00000000000000000000000000000000
CIPHERTEXT = 3ad78e726c1ec02b7ebfe92b23d9ec34

Upvotes: 3

Views: 588

Answers (2)

President James K. Polk
President James K. Polk

Reputation: 41974

You are missing a keyword argument, segment_size, in your AES.new(...) call. This is the feedback size, and it defaults to 8. If your line of code is changed to

aes = AES.new(key, AES.MODE_CFB, iv, segment_size=128)

you get the correct result.

As stated in the docs:

segment_size (integer) - (Only MODE_CFB).The number of bits the plaintext and ciphertext are segmented in. It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.

Your results correspond to what would likely be labeled "CFB8" in NIST docs.

Upvotes: 4

PM 2Ring
PM 2Ring

Reputation: 55479

I also get the same results as you when using AES.MODE_CFB, but I get the results you expect when I use AES.MODE_CBC instead.

from Crypto.Cipher import AES

def show(b):
    print(*['{:02x}'.format(u) for u in b])

key   = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
iv    = b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
plain = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

crypto = AES.new(key, AES.MODE_CBC, iv)
cipher = crypto.encrypt(plain)
show(cipher)

# We need a fresh AES object to decrypt
crypto = AES.new(key, AES.MODE_CBC, iv)
decoded = crypto.decrypt(cipher)
show(decoded)

output

3a d7 8e 72 6c 1e c0 2b 7e bf e9 2b 23 d9 ec 34
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Upvotes: -1

Related Questions