diff options
-rw-r--r-- | cryptography/bindings/openssl/api.py | 13 | ||||
-rw-r--r-- | cryptography/primitives/block/modes.py | 9 | ||||
-rw-r--r-- | cryptography/primitives/interfaces.py | 22 | ||||
-rw-r--r-- | docs/primitives/symmetric-encryption.rst | 13 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | tests/bindings/test_openssl.py | 2 | ||||
-rw-r--r-- | tests/primitives/test_nist.py | 47 |
7 files changed, 103 insertions, 5 deletions
diff --git a/cryptography/bindings/openssl/api.py b/cryptography/bindings/openssl/api.py index 54a74d03..917c1846 100644 --- a/cryptography/bindings/openssl/api.py +++ b/cryptography/bindings/openssl/api.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +from cryptography.primitives import interfaces + import cffi @@ -72,11 +74,14 @@ class API(object): ) evp_cipher = self._lib.EVP_get_cipherbyname(ciphername.encode("ascii")) assert evp_cipher != self._ffi.NULL - # TODO: only use the key and initialization_vector as needed. Sometimes - # this needs to be a DecryptInit, when? + if isinstance(mode, interfaces.ModeWithInitializationVector): + iv_nonce = mode.initialization_vector + else: + iv_nonce = self._ffi.NULL + + # TODO: Sometimes this needs to be a DecryptInit, when? res = self._lib.EVP_EncryptInit_ex( - ctx, evp_cipher, self._ffi.NULL, cipher.key, - mode.initialization_vector + ctx, evp_cipher, self._ffi.NULL, cipher.key, iv_nonce ) assert res != 0 diff --git a/cryptography/primitives/block/modes.py b/cryptography/primitives/block/modes.py index de31f086..c722e739 100644 --- a/cryptography/primitives/block/modes.py +++ b/cryptography/primitives/block/modes.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +from cryptography.primitives import interfaces + class CBC(object): name = "CBC" @@ -20,3 +22,10 @@ class CBC(object): def __init__(self, initialization_vector): super(CBC, self).__init__() self.initialization_vector = initialization_vector + + +class ECB(object): + name = "ECB" + + +interfaces.ModeWithInitializationVector.register(CBC) diff --git a/cryptography/primitives/interfaces.py b/cryptography/primitives/interfaces.py new file mode 100644 index 00000000..6f74ccf7 --- /dev/null +++ b/cryptography/primitives/interfaces.py @@ -0,0 +1,22 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +class ModeWithInitializationVector(six.with_metaclass(abc.ABCMeta)): + pass diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 1b8d1d73..d0429d4b 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -67,3 +67,16 @@ Modes ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + + +Insecure Modes +-------------- + +.. warning:: Do not use. This is an insecure mode. +.. class:: cryptography.primitives.block.modes.ECB() + + ECB (Electronic Code Book) is the simplest mode of operation for block + ciphers. The data is separated into blocks and each block is encrypted + separately. This means identical plaintext blocks will always result in + identical encrypted blocks. Due to this property it is not recommended + for use. Really, don't use it. Just. Don't. @@ -21,9 +21,11 @@ with open("cryptography/__about__.py") as fp: CFFI_DEPENDENCY = "cffi>=0.6" +SIX_DEPENDENCY = "six>=1.4.1" install_requires = [ CFFI_DEPENDENCY, + SIX_DEPENDENCY ] setup_requires = [ diff --git a/tests/bindings/test_openssl.py b/tests/bindings/test_openssl.py index 1579f002..b23c4ccc 100644 --- a/tests/bindings/test_openssl.py +++ b/tests/bindings/test_openssl.py @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cryptography.bindings.openssl import api +from cryptography.bindings.openssl.api import api class TestOpenSSL(object): diff --git a/tests/primitives/test_nist.py b/tests/primitives/test_nist.py index 8bef118e..3dc8277a 100644 --- a/tests/primitives/test_nist.py +++ b/tests/primitives/test_nist.py @@ -86,3 +86,50 @@ class TestAES_CBC(object): actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) actual_ciphertext += cipher.finalize() assert binascii.hexlify(actual_ciphertext) == ciphertext + + +class TestAES_ECB(object): + @parameterize_encrypt_test( + "AES", "KAT", + ("key", "plaintext", "ciphertext"), + [ + "ECBGFSbox128.rsp", + "ECBGFSbox192.rsp", + "ECBGFSbox256.rsp", + "ECBKeySbox128.rsp", + "ECBKeySbox192.rsp", + "ECBKeySbox256.rsp", + "ECBVarKey128.rsp", + "ECBVarKey192.rsp", + "ECBVarKey256.rsp", + "ECBVarTxt128.rsp", + "ECBVarTxt192.rsp", + "ECBVarTxt256.rsp", + ] + ) + def test_KAT(self, key, plaintext, ciphertext): + cipher = BlockCipher( + ciphers.AES(binascii.unhexlify(key)), + modes.ECB() + ) + actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) + actual_ciphertext += cipher.finalize() + assert binascii.hexlify(actual_ciphertext) == ciphertext + + @parameterize_encrypt_test( + "AES", "MMT", + ("key", "plaintext", "ciphertext"), + [ + "ECBMMT128.rsp", + "ECBMMT192.rsp", + "ECBMMT256.rsp", + ] + ) + def test_MMT(self, key, plaintext, ciphertext): + cipher = BlockCipher( + ciphers.AES(binascii.unhexlify(key)), + modes.ECB() + ) + actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) + actual_ciphertext += cipher.finalize() + assert binascii.hexlify(actual_ciphertext) == ciphertext |