diff options
| -rw-r--r-- | cryptography/primitives/block/ciphers.py | 12 | ||||
| -rw-r--r-- | docs/primitives/symmetric-encryption.rst | 19 | ||||
| -rw-r--r-- | tests/primitives/test_nist.py | 93 | 
3 files changed, 124 insertions, 0 deletions
diff --git a/cryptography/primitives/block/ciphers.py b/cryptography/primitives/block/ciphers.py index cf54aa35..f204dbe9 100644 --- a/cryptography/primitives/block/ciphers.py +++ b/cryptography/primitives/block/ciphers.py @@ -32,3 +32,15 @@ class AES(object):      @property      def key_size(self):          return len(self.key) * 8 + + +class TripleDES(object): +    name = "3DES" +    block_size = 64 +    # TODO: is there a better way to represent the fact that the effective key +    # size is 56 bits? +    key_sizes = set([64, 128, 192]) + +    def __init__(self, key): +        super(TripleDES, self).__init__() +        self.key = key diff --git a/docs/primitives/symmetric-encryption.rst b/docs/primitives/symmetric-encryption.rst index 1b8d1d73..ce3b13e8 100644 --- a/docs/primitives/symmetric-encryption.rst +++ b/docs/primitives/symmetric-encryption.rst @@ -52,6 +52,25 @@ Ciphers                        This must be kept secret. +Insecure Ciphers +---------------- + +.. class:: cryptography.primitives.block.ciphers.TripleDES(key) + +    Triple DES (Data Encryption Standard), sometimes refered to as 3DES, is a +    block cipher standardized by NIST. Triple DES should be considered to be +    cryptographically broken and should not be used for new applications, old +    applications should strongly consider moving away from it. + +    :param bytes key: The secret key, either ``64``, ``128``, or ``192`` bits +                      (note that DES functionally uses ``56``, ``112``, or +                      ``168`` bits of the key, there is a parity byte in each +                      component of the key), in some materials these are +                      referred to as being up to three separate keys (each +                      ``56`` bits long), they can simply be concatenated to +                      produce the full key. This must be kept secret. + +  Modes  ~~~~~ diff --git a/tests/primitives/test_nist.py b/tests/primitives/test_nist.py index 8bef118e..e736d4d1 100644 --- a/tests/primitives/test_nist.py +++ b/tests/primitives/test_nist.py @@ -86,3 +86,96 @@ class TestAES_CBC(object):          actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext))          actual_ciphertext += cipher.finalize()          assert binascii.hexlify(actual_ciphertext) == ciphertext + + +class TestTripleDES_CBC(object): +    @parameterize_encrypt_test( +        "3DES", "KAT", +        ["keys", "iv", "plaintext", "ciphertext"], +        [ +            "TCBCinvperm.rsp", +            "TCBCpermop.rsp", +            "TCBCsubtab.rsp", +            "TCBCvarkey.rsp", +            "TCBCvartext.rsp", +        ] +    ) +    def test_KAT_1(self, keys, iv, plaintext, ciphertext): +        cipher = BlockCipher( +            ciphers.TripleDES(binascii.unhexlify(keys)), +            modes.CBC(binascii.unhexlify(iv)), +        ) +        actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) +        actual_ciphertext += cipher.finalize() +        assert binascii.hexlify(actual_ciphertext) == ciphertext + +    @parameterize_encrypt_test( +        "3DES", "KAT", +        ["keys", "iv1", "iv2", "iv3", "plaintext", "ciphertext3"], +        [ +            "TCBCIpermop.rsp", +            "TCBCIsubtab.rsp", +            "TCBCIvarkey.rsp", +            "TCBCIvartext.rsp", +        ] +    ) +    def test_KAT_2(self, keys, iv1, iv2, iv3, plaintext, ciphertext3): +        cipher = BlockCipher( +            ciphers.TripleDES(binascii.unhexlify(keys)), +            modes.CBC(binascii.unhexlify(iv1 + iv2 + iv3)), +        ) +        actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) +        actual_ciphertext += cipher.finalize() +        assert binascii.hexlify(actual_ciphertext) == ciphertext3 + +    @parameterize_encrypt_test( +        "3DES", "KAT", +        ["keys", "iv1", "iv2", "iv3", "plaintext1", "ciphertext3"], +        [ +            "TCBCIinvperm.rsp", +        ] +    ) +    def test_KAT_3(self, keys, iv1, iv2, iv3, plaintext1, ciphertext3): +        cipher = BlockCipher( +            ciphers.TripleDES(binascii.unhexlify(keys)), +            modes.CBC(binascii.unhexlify(iv1 + iv2 + iv3)), +        ) +        actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext1)) +        actual_ciphertext += cipher.finalize() +        assert binascii.hexlify(actual_ciphertext) == ciphertext3 + +    @parameterize_encrypt_test( +        "3DES", "MMT", +        ["key1", "key2", "key3", "iv1", "iv2", "iv3", "plaintext", "ciphertext"], +        [ +            "TCBCIMMT1.rsp", +            "TCBCIMMT2.rsp", +            "TCBCIMMT3.rsp", +        ] +    ) +    def test_MMT_1(self, key1, key2, key3, iv1, iv2, iv3, plaintext, ciphertext): +        cipher = BlockCipher( +            ciphers.TripleDES(binascii.unhexlify(key1 + key2 + key3)), +            modes.CBC(binascii.unhexlify(iv1 + iv2 + iv3)), +        ) +        actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) +        actual_ciphertext += cipher.finalize() +        assert binascii.hexlify(actual_ciphertext) == ciphertext + +    @parameterize_encrypt_test( +        "3DES", "MMT", +        ["key1", "key2", "key3", "iv", "plaintext", "ciphertext"], +        [ +            "TCBCMMT1.rsp", +            "TCBCMMT2.rsp", +            "TCBCMMT3.rsp", +        ] +    ) +    def test_MMT_2(self, key1, key2, key3, iv, plaintext, ciphertext): +        cipher = BlockCipher( +            ciphers.TripleDES(binascii.unhexlify(key1 + key2 + key3)), +            modes.CBC(binascii.unhexlify(iv)), +        ) +        actual_ciphertext = cipher.encrypt(binascii.unhexlify(plaintext)) +        actual_ciphertext += cipher.finalize() +        assert binascii.hexlify(actual_ciphertext) == ciphertext  | 
