From 6f412a0fc35386ad980c5b3fa2bdb3c90436f3b6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 10 Sep 2013 21:30:50 -0500 Subject: add output feedback mode support + test vectors (aes) --- cryptography/primitives/block/modes.py | 9 ++++++ docs/primitives/symmetric-encryption.rst | 13 +++++++++ tests/primitives/test_nist.py | 47 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/cryptography/primitives/block/modes.py b/cryptography/primitives/block/modes.py index c722e739..70ef8178 100644 --- a/cryptography/primitives/block/modes.py +++ b/cryptography/primitives/block/modes.py @@ -28,4 +28,13 @@ class ECB(object): name = "ECB" +class OFB(object): + name = "OFB" + + def __init__(self, initialization_vector): + super(OFB, self).__init__() + self.initialization_vector = initialization_vector + + interfaces.ModeWithInitializationVector.register(CBC) +interfaces.ModeWithInitializationVector.register(OFB) diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index d0429d4b..7ec42a30 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -68,6 +68,19 @@ Modes reuse an ``initialization_vector`` with a given ``key``. +.. class:: cryptography.primitives.block.modes.OFB(initialization_vector) + + OFB (Output Feedback) is a mode of operation for block ciphers. It + transforms a block cipher into a stream cipher. + + :param bytes initialization_vector: Must be random bytes. They do not need + to be kept secret (they can be included + in a transmitted message). Must be the + same number of bytes as the + ``block_size`` of the cipher. Do not + reuse an ``initialization_vector`` with + a given ``key``. + Insecure Modes -------------- diff --git a/tests/primitives/test_nist.py b/tests/primitives/test_nist.py index 3dc8277a..0e16cc9c 100644 --- a/tests/primitives/test_nist.py +++ b/tests/primitives/test_nist.py @@ -133,3 +133,50 @@ class TestAES_ECB(object): actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) actual_ciphertext += cipher.finalize() assert binascii.hexlify(actual_ciphertext) == ciphertext + + +class TestAES_OFB(object): + @parameterize_encrypt_test( + "AES", "KAT", + ("key", "iv", "plaintext", "ciphertext"), + [ + "OFBGFSbox128.rsp", + "OFBGFSbox192.rsp", + "OFBGFSbox256.rsp", + "OFBKeySbox128.rsp", + "OFBKeySbox192.rsp", + "OFBKeySbox256.rsp", + "OFBVarKey128.rsp", + "OFBVarKey192.rsp", + "OFBVarKey256.rsp", + "OFBVarTxt128.rsp", + "OFBVarTxt192.rsp", + "OFBVarTxt256.rsp", + ] + ) + def test_KAT(self, key, iv, plaintext, ciphertext): + cipher = BlockCipher( + ciphers.AES(binascii.unhexlify(key)), + modes.OFB(binascii.unhexlify(iv)) + ) + actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) + actual_ciphertext += cipher.finalize() + assert binascii.hexlify(actual_ciphertext) == ciphertext + + @parameterize_encrypt_test( + "AES", "MMT", + ("key", "iv", "plaintext", "ciphertext"), + [ + "OFBMMT128.rsp", + "OFBMMT192.rsp", + "OFBMMT256.rsp", + ] + ) + def test_MMT(self, key, iv, plaintext, ciphertext): + cipher = BlockCipher( + ciphers.AES(binascii.unhexlify(key)), + modes.OFB(binascii.unhexlify(iv)) + ) + actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) + actual_ciphertext += cipher.finalize() + assert binascii.hexlify(actual_ciphertext) == ciphertext -- cgit v1.2.3 From c507412ec09e6fa502fbd8587824901e1cf9a935 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 10 Sep 2013 22:15:00 -0500 Subject: change OFB iv to nonce to reflect dstufft nomenclature pitch * Namely, we should try to call things IV if reuse leaks a small amount of data and nonce if reuse can result in a complete break. This can be somewhat ambiguous, but we'll track in #58 --- cryptography/bindings/openssl/api.py | 2 ++ cryptography/primitives/block/modes.py | 6 +++--- cryptography/primitives/interfaces.py | 4 ++++ docs/primitives/symmetric-encryption.rst | 14 ++++++-------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index 917c1846..af7fe438 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -76,6 +76,8 @@ class API(object): assert evp_cipher != self._ffi.NULL if isinstance(mode, interfaces.ModeWithInitializationVector): iv_nonce = mode.initialization_vector + elif isinstance(mode, interfaces.ModeWithNonce): + iv_nonce = mode.nonce else: iv_nonce = self._ffi.NULL diff --git a/cryptography/primitives/block/modes.py b/cryptography/primitives/block/modes.py index 70ef8178..62a1c2c9 100644 --- a/cryptography/primitives/block/modes.py +++ b/cryptography/primitives/block/modes.py @@ -31,10 +31,10 @@ class ECB(object): class OFB(object): name = "OFB" - def __init__(self, initialization_vector): + def __init__(self, nonce): super(OFB, self).__init__() - self.initialization_vector = initialization_vector + self.nonce = nonce interfaces.ModeWithInitializationVector.register(CBC) -interfaces.ModeWithInitializationVector.register(OFB) +interfaces.ModeWithNonce.register(OFB) diff --git a/cryptography/primitives/interfaces.py b/cryptography/primitives/interfaces.py index 6f74ccf7..c1fc9910 100644 --- a/cryptography/primitives/interfaces.py +++ b/cryptography/primitives/interfaces.py @@ -20,3 +20,7 @@ import six class ModeWithInitializationVector(six.with_metaclass(abc.ABCMeta)): pass + + +class ModeWithNonce(six.with_metaclass(abc.ABCMeta)): + pass diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 7ec42a30..587c94b4 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -68,18 +68,16 @@ Modes reuse an ``initialization_vector`` with a given ``key``. -.. class:: cryptography.primitives.block.modes.OFB(initialization_vector) +.. class:: cryptography.primitives.block.modes.OFB(nonce) OFB (Output Feedback) is a mode of operation for block ciphers. It transforms a block cipher into a stream cipher. - :param bytes initialization_vector: Must be random bytes. They do not need - to be kept secret (they can be included - in a transmitted message). Must be the - same number of bytes as the - ``block_size`` of the cipher. Do not - reuse an ``initialization_vector`` with - a given ``key``. + :param bytes nonce: Must be random bytes. They do not need to be kept + secret (they can be included in a transmitted message). + Must be the same number of bytes as the ``block_size`` + of the cipher. Reuse of a ``nonce`` with a given + ``key`` can allow recovery of the original plaintext. Insecure Modes -- cgit v1.2.3