Commit e636051d authored by Daniel Hofmann's avatar Daniel Hofmann
Browse files

Test vectors for Py, refactor

parent ef7e7892
......@@ -14,7 +14,7 @@ import base64
from Crypto.Cipher import AES
def aes_config():
def _config():
parser = argparse.ArgumentParser(description='AES (in CBC mode) language interop tester')
parser.add_argument('-i', '--iv', dest='iv', default='{0}'.format(AES.block_size * '0'),
......@@ -29,57 +29,92 @@ def aes_config():
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
logging.basicConfig(level=logging.INFO, format='%(funcName)s: %(message)s')
return {'iv': args.iv, 'key': args.key, 'in': args.plaintext}
rv = {'iv': args.iv, 'key': args.key, 'in': args.plaintext}
logging.info(rv)
return rv
def aes_cipher(key, iv):
# returned cipher object is stateful
def _aes_cipher(key, iv):
logging.info({'key': key, 'iv': iv})
assert(len(iv) == AES.block_size), 'iv size mismatch'
assert(len(key) in AES.key_size), 'key size mismatch'
return AES.new(key, AES.MODE_CBC, iv)
def main():
cfg = aes_config()
logging.info('{0}'.format(cfg))
# PKCS#7 padding scheme, see:
# - 10.3/2 http://tools.ietf.org/html/rfc2315
# - http://stackoverflow.com/a/14205319
def _pkcs7(bs, x):
rv = x + (bs - len(x) % bs) * chr(bs - len(x) % bs)
logging.info({'blocksize': bs, 'raw': x, 'padded': rv})
assert(len(rv) % AES.block_size == 0), 'padded plaintext is not a multiple of block size'
return rv
aes = aes_cipher(cfg['key'], cfg['iv'])
# PKCS#7 padding, see: 10.3/2 http://tools.ietf.org/html/rfc2315, http://stackoverflow.com/a/14205319
pkcs7 = lambda bs, x: x + (bs - len(x) % bs) * chr(bs - len(x) % bs)
unpkcs7 = lambda x: x[0:-ord(x[-1])]
def _unpkcs7(x):
rv = x[0:-ord(x[-1])]
logging.info({'raw': x, 'unpadded': rv})
assert(_pkcs7(AES.block_size, rv) == x), 'unpadding does not reverse padding'
return rv
padded = pkcs7(AES.block_size, cfg['in'])
assert(len(padded) % AES.block_size == 0), 'padded plaintext is not a multiple of block size'
assert(unpkcs7(padded) == cfg['in']), 'unpadding does not reverse padding'
# encrypt: iv + aes(in + pkcs7_pad)
enc = cfg['iv'] + aes.encrypt(padded)
b64 = base64.b64encode(enc)
# iv + aes(in + pkcs7_pad)
def encrypt(key, iv, plaintext):
aes = _aes_cipher(key, iv)
padded = _pkcs7(AES.block_size, plaintext)
return iv + aes.encrypt(padded)
logging.info('{0}'.format({'padding': len(padded), 'base64': b64}))
print(b64)
# first AES.block_size is iv, rest is aes(in + pad)
def decrypt(key, ciphertext):
iv, padded = ciphertext[:AES.block_size], ciphertext[AES.block_size:]
aes = _aes_cipher(key, iv)
return _unpkcs7(aes.decrypt(padded))
# XXX: from here on: encryption validation
# decrypt: first AES.block_size is iv, rest is aes(in + pad)
raw = base64.b64decode(b64)
assert(len(raw) % AES.block_size == 0), 'encoded ciper text is not a multiple of block size'
# external (read: from the internet) test vector
def _selftest_nosalt():
key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'.decode('hex')
iv = '000102030405060708090A0B0C0D0E0F'.decode('hex')
plaintext = '6bc1bee22e409f96e93d7e117393172a'.decode('hex')
ciphertext = 'f58c4c04d6e5f1ba779eabfb5f7bfbd6485a5c81519cf378fa36d42b8547edc0'.decode('hex')
expected = iv + ciphertext
enc = encrypt(key, iv, plaintext)
logging.info({'expected': ciphertext, 'encrypted': enc})
assert(enc == expected), 'encryption does not match expected result'
dec = decrypt(key, enc)
logging.info({'expected': plaintext, 'decrypted': dec})
assert(dec == plaintext), 'encryption decryption round robin mismatch'
# TODO(daniel): openssl's 'Salted__' + salt prepended scheme, not implemented yet
def _selftest_salt():
pass
iv, padded = raw[:AES.block_size], raw[AES.block_size:]
assert(iv == cfg['iv']), 'decoded iv mismatch'
assert(iv + padded == enc), 'decoded cipher mismatch'
logging.info('{0}'.format({'key': cfg['key'], 'iv': iv}))
def main():
cfg = _config()
_selftest_nosalt()
_selftest_salt()
enc = encrypt(cfg['key'], cfg['iv'], cfg['in'])
b64 = base64.b64encode(enc)
aes = aes_cipher(cfg['key'], iv)
dec = unpkcs7(aes.decrypt(padded))
print(b64)
raw = base64.b64decode(b64)
dec = decrypt(cfg['key'], raw)
assert(cfg['in'] == dec), 'encryption decryption round robin mismatch'
if __name__ == '__main__':
main()
# vim: set tabstop=4 shiftwidth=4 expandtab:
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment