pyca/cryptography — pull request #396 by reaperhulk (2014-01-03 04:30:34+00:00)
Title: CBC, CFB, OFB IDEA vectors built from the AES MMT tests

IDEA and CAST5 (CAST-128) are two ciphers that have known ECB vectors, but no source for vectors for modes like CBC, OFB, and CFB. This PR is a proposal for building our own vector set.

Building our own vectors means we make one important assumption about the implementation used to generate it (in this case, OpenSSL): that the underlying implementation is correct. I believe this is a reasonable statement until proven otherwise. At the very least these vectors will show us if any other backend we choose to implement disagrees with OpenSSL's implementation as well as allowing us to expose modes currently available in shipping OpenSSL.

The vectors are generated by iterating over the AES MMT CBC/OFB/CFB tests with the following script (shown set up for IDEA CFB). Since IDEA is a 64-bit block size the IVs from the AES vectors are truncated.
```python
import binascii

from cryptography.hazmat.backends.openssl.backend import backend
from cryptography.hazmat.primitives.ciphers import base, algorithms, modes

def encrypt(key, iv, plaintext):
cipher = base.Cipher(
algorithms.IDEA(binascii.unhexlify(key)),
modes.CFB(binascii.unhexlify(iv)),
backend
)
encryptor = cipher.encryptor()
ct = encryptor.update(binascii.unhexlify(plaintext))
ct += encryptor.finalize()
return binascii.hexlify(ct)

vector_file = open(
"tests/hazmat/primitives/vectors/ciphers/AES/CFB/CFB128MMT128.rsp",
"r"
)

count = 0
output = []
key = None
iv = None
plaintext = None
ct = None
for line in vector_file:
line = line.strip()
if line.startswith("KEY"):
if count != 0:
output.append("CIPHERTEXT = {}".format(encrypt(key, iv, plaintext)))
output.append("\nCOUNT = {}".format(count))
count += 1
name, key = line.split(" = ")
output.append("KEY = {}".format(key))
elif line.startswith("IV"):
name, iv = line.split(" = ")
output.append("IV = {}".format(iv[0:16]))
elif line.startswith("PLAINTEXT"):
name, plaintext = line.split(" = ")
output.append("PLAINTEXT = {}".format(plaintext))

output.append("CIPHERTEXT = {}".format(encrypt(key, iv, plaintext)))
print("\n".join(output))
```

This approach will also work for resolving #393.