From d0ec60e7d671bb1f927cd711949d95441d947933 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 16 Oct 2013 08:46:50 -0500 Subject: [PATCH 1/5] AES Counter support * vectors from RFC 3686 * Documentation for the mode --- cryptography/bindings/openssl/api.py | 2 ++ cryptography/primitives/block/modes.py | 9 +++++++++ cryptography/primitives/interfaces.py | 4 ++++ docs/primitives/symmetric-encryption.rst | 13 +++++++++++++ tests/primitives/test_openssl_vectors.py | 12 ++++++++++++ .../primitives/vectors/OpenSSL/AES/aes-128-ctr.txt | 4 ++++ .../primitives/vectors/OpenSSL/AES/aes-192-ctr.txt | 4 ++++ .../primitives/vectors/OpenSSL/AES/aes-256-ctr.txt | 5 +++++ 8 files changed, 53 insertions(+) create mode 100644 tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt create mode 100644 tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt create mode 100644 tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index f1a2c087a753..79ec5eea1c72 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -103,6 +103,8 @@ def create_block_cipher_context(self, cipher, mode): 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 9cfbca640027..221e73934364 100644 --- a/cryptography/primitives/block/modes.py +++ b/cryptography/primitives/block/modes.py @@ -44,6 +44,15 @@ def __init__(self, initialization_vector): self.initialization_vector = initialization_vector +class CTR(object): + name = "CTR" + + def __init__(self, nonce): + super(CTR, self).__init__() + self.nonce = nonce + + interfaces.ModeWithInitializationVector.register(CBC) interfaces.ModeWithInitializationVector.register(OFB) interfaces.ModeWithInitializationVector.register(CFB) +interfaces.ModeWithNonce.register(CTR) diff --git a/cryptography/primitives/interfaces.py b/cryptography/primitives/interfaces.py index 6f74ccf7e20f..c1fc9910f647 100644 --- a/cryptography/primitives/interfaces.py +++ b/cryptography/primitives/interfaces.py @@ -20,3 +20,7 @@ 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 c4bbf0a59697..52bd6a40f99f 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -77,6 +77,19 @@ Modes reuse an ``initialization_vector`` with a given ``key``. +.. class:: cryptography.primitives.block.modes.CTR(nonce) + + CTR (Counter) is a mode of operation for block ciphers. It is considered + cryptographically strong. + + :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. It is critical to + never reuse a ``nonce`` with a given ``key``. Unlike + CBC, reusing a nonce compromises the security of + all data encrypted under the key (see: two time pad). + .. class:: cryptography.primitives.block.modes.OFB(initialization_vector) OFB (Output Feedback) is a mode of operation for block ciphers. It diff --git a/tests/primitives/test_openssl_vectors.py b/tests/primitives/test_openssl_vectors.py index 6e32eca634da..5b2be784a42a 100644 --- a/tests/primitives/test_openssl_vectors.py +++ b/tests/primitives/test_openssl_vectors.py @@ -59,3 +59,15 @@ class TestCamelliaCFB(object): only_if=lambda api: api.supports_cipher("camellia-128-cfb"), skip_message="Does not support Camellia CFB", ) + + +class TestAESCTR(object): + test_OpenSSL = generate_encrypt_test( + load_openssl_vectors_from_file, + "AES", + ["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"], + lambda key, iv: ciphers.AES(binascii.unhexlify(key)), + lambda key, iv: modes.CTR(binascii.unhexlify(iv)), + only_if=lambda api: api.supports_cipher("aes-128-ctr"), + skip_message="Does not support AES CTR", + ) diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt new file mode 100644 index 000000000000..f4ce15ebc7a0 --- /dev/null +++ b/tests/primitives/vectors/OpenSSL/AES/aes-128-ctr.txt @@ -0,0 +1,4 @@ +# AES Counter test vectors from RFC3686 +aes-128-ctr:AE6852F8121067CC4BF7A5765577F39E:00000030000000000000000000000001:53696E676C6520626C6F636B206D7367:E4095D4FB7A7B3792D6175A3261311B8:1 +aes-128-ctr:7E24067817FAE0D743D6CE1F32539163:006CB6DBC0543B59DA48D90B00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28:1 +aes-128-ctr:7691BE035E5020A8AC6E618529F9A0DC:00E0017B27777F3F4A1786F000000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F:1 diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt new file mode 100644 index 000000000000..9e166fc4b36b --- /dev/null +++ b/tests/primitives/vectors/OpenSSL/AES/aes-192-ctr.txt @@ -0,0 +1,4 @@ +# AES Counter test vectors from RFC3686 +aes-192-ctr:16AF5B145FC9F579C175F93E3BFB0EED863D06CCFDB78515:0000004836733C147D6D93CB00000001:53696E676C6520626C6F636B206D7367:4B55384FE259C9C84E7935A003CBE928:1 +aes-192-ctr:7C5CB2401B3DC33C19E7340819E0F69C678C3DB8E6F6A91A:0096B03B020C6EADC2CB500D00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:453243FC609B23327EDFAAFA7131CD9F8490701C5AD4A79CFC1FE0FF42F4FB00:1 +aes-192-ctr:02BF391EE8ECB159B959617B0965279BF59B60A786D3E0FE:0007BDFD5CBD60278DCC091200000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:96893FC55E5C722F540B7DD1DDF7E758D288BC95C69165884536C811662F2188ABEE0935:1 diff --git a/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt b/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt new file mode 100644 index 000000000000..d499875003dc --- /dev/null +++ b/tests/primitives/vectors/OpenSSL/AES/aes-256-ctr.txt @@ -0,0 +1,5 @@ +# AES Counter test vectors from RFC3686 +aes-256-ctr:776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104:00000060DB5672C97AA8F0B200000001:53696E676C6520626C6F636B206D7367:145AD01DBF824EC7560863DC71E3E0C0:1 +aes-256-ctr:F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884:00FAAC24C1585EF15A43D87500000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C:1 +aes-256-ctr:FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D:001CC5B751A51D70A1C1114800000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8:1 + From 389892f8ad5700b152d20948ded9c540b2cdaff8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 16 Oct 2013 13:20:50 -0500 Subject: [PATCH 2/5] update docs to roughly describe many time pad attack & link cbc --- docs/primitives/symmetric-encryption.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 52bd6a40f99f..9520d6eb99f3 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -87,8 +87,11 @@ Modes message). Must be the same number of bytes as the ``block_size`` of the cipher. It is critical to never reuse a ``nonce`` with a given ``key``. Unlike - CBC, reusing a nonce compromises the security of - all data encrypted under the key (see: two time pad). + :class:`~cryptography.primitives.block.modes.CBC`, + reusing a nonce compromises the security of all data + encrypted under the key. Specifically, + (pt1 xor keystream) xor (pt2 xor keystream) is + equivalent to (pt1 xor pt2). .. class:: cryptography.primitives.block.modes.OFB(initialization_vector) From 0ba2f9464693fe7ae0167eb47df9b1a96408ed9c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 17 Oct 2013 12:06:46 -0500 Subject: [PATCH 3/5] remove confusing explanation about reusing nonce in counter mode docs --- docs/primitives/symmetric-encryption.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 9520d6eb99f3..21421d16a85f 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -89,9 +89,7 @@ Modes never reuse a ``nonce`` with a given ``key``. Unlike :class:`~cryptography.primitives.block.modes.CBC`, reusing a nonce compromises the security of all data - encrypted under the key. Specifically, - (pt1 xor keystream) xor (pt2 xor keystream) is - equivalent to (pt1 xor pt2). + encrypted under the key. .. class:: cryptography.primitives.block.modes.OFB(initialization_vector) From 4506428ad913d183ad90c0fed668745a6d2aaf33 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 17 Oct 2013 13:41:53 -0500 Subject: [PATCH 4/5] ctr doc language take 3 --- docs/primitives/symmetric-encryption.rst | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 21421d16a85f..a1f8ba325a91 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -77,19 +77,25 @@ Modes reuse an ``initialization_vector`` with a given ``key``. + .. class:: cryptography.primitives.block.modes.CTR(nonce) + .. warning:: + + Counter mode is not recommended for use with block ciphers that have a + block size of less than 128-bits. + CTR (Counter) is a mode of operation for block ciphers. It is considered cryptographically strong. - :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. It is critical to - never reuse a ``nonce`` with a given ``key``. Unlike - :class:`~cryptography.primitives.block.modes.CBC`, - reusing a nonce compromises the security of all data - encrypted under the key. + :param bytes nonce: Recommended to be random. It is critical to never reuse + a ```nonce``` (or its subsequent incremented values) + with a given key. Any reuse of the nonce with the same + key compromises the security of every message encrypted + with that key. Must be the same number of bytes as the + ```block_size``` of the cipher with a given key. The + nonce does not need to be kept secret and may be + included alongside the ciphertext. .. class:: cryptography.primitives.block.modes.OFB(initialization_vector) From 89b3dd38c32b19853d24caa0f091a0dd78e54084 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 17 Oct 2013 14:02:45 -0500 Subject: [PATCH 5/5] additional doc work on ctr --- docs/primitives/symmetric-encryption.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index a1f8ba325a91..7899e67df4a9 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -88,14 +88,13 @@ Modes CTR (Counter) is a mode of operation for block ciphers. It is considered cryptographically strong. - :param bytes nonce: Recommended to be random. It is critical to never reuse - a ```nonce``` (or its subsequent incremented values) - with a given key. Any reuse of the nonce with the same - key compromises the security of every message encrypted - with that key. Must be the same number of bytes as the - ```block_size``` of the cipher with a given key. The - nonce does not need to be kept secret and may be - included alongside the ciphertext. + :param bytes nonce: Should be random bytes. It is critical to never reuse a + ``nonce`` with a given key. Any reuse of a nonce + with the same key compromises the security of every + message encrypted with that key. Must be the same + number of bytes as the ``block_size`` of the cipher + with a given key. The nonce does not need to be kept + secret and may be included alongside the ciphertext. .. class:: cryptography.primitives.block.modes.OFB(initialization_vector)