Exemple #1
0
 def test_decrypt_acvp(self):
     for testVector in testVectors_ACVP_AES_FF3_1:
         with self.subTest(testVector=testVector):
             c = FF3Cipher.withCustomAlphabet(testVector['key'],
                                              testVector['tweak'],
                                              testVector['alphabet'])
             s = c.decrypt(testVector['ciphertext'])
             self.assertEqual(s, testVector['plaintext'])
Exemple #2
0
 def test_custom_alphabet(self):
     alphabet = "⁰¹²³⁴⁵⁶⁷⁸⁹"
     key = "EF4359D8D580AA4F7F036D6F04FC6A94"
     tweak = "D8E7920AFA330A73"
     plaintext = "⁸⁹⁰¹²¹²³⁴⁵⁶⁷⁸⁹⁰⁰⁰⁰"
     ciphertext = "⁷⁵⁰⁹¹⁸⁸¹⁴⁰⁵⁸⁶⁵⁴⁶⁰⁷"
     c = FF3Cipher.withCustomAlphabet(key, tweak, alphabet)
     s = c.encrypt(plaintext)
     self.assertEqual(s, ciphertext)
     x = c.decrypt(s)
     self.assertEqual(x, plaintext)
Exemple #3
0
    def test_german(self):
        """
        Test the German alphabet with a radix of 70.  German consists of the latin alphabet
        plus four additional letters, each of which have uppercase and lowercase letters
        """

        german_alphabet = string.digits + string.ascii_lowercase + string.ascii_uppercase + "ÄäÖöÜüẞß"
        key = "EF4359D8D580AA4F7F036D6F04FC6A94"
        tweak = "D8E7920AFA330A73"
        plaintext = "liebeGrüße"
        ciphertext = "5kÖQbairXo"
        c = FF3Cipher.withCustomAlphabet(key, tweak, alphabet=german_alphabet)
        s = c.encrypt(plaintext)
        self.assertEqual(s, ciphertext)
        x = c.decrypt(s)
        self.assertEqual(x, plaintext)
Exemple #4
0
    def test_whole_domain(self):
        test_cases = [
            # (radix, plaintext_len, alphabet (None means default))
            (2, 10, None),
            (3, 6, None),
            (10, 3, None),
            (17, 3, None),
            (62, 2, None),
            (3, 7, "ABC"),
        ]

        max_radix = max(radix for radix, plaintext_len, alphabet in test_cases)

        # Temporarily reduce DOMAIN_MIN to make testing fast
        domain_min_orig = FF3Cipher.DOMAIN_MIN
        FF3Cipher.DOMAIN_MIN = max_radix + 1

        key = "EF4359D8D580AA4F7F036D6F04FC6A94"
        tweak = "D8E7920AFA330A73"
        for radix, plaintext_len, alphabet in test_cases:
            if alphabet is None:
                c = FF3Cipher(key, tweak, radix=radix)
            else:
                c = FF3Cipher.withCustomAlphabet(key, tweak, alphabet=alphabet)
            self.subTest(radix=radix, plaintext_len=plaintext_len)

            # Integer representations of each possible plaintext
            plaintexts_as_ints = list(range(radix**plaintext_len))

            # String representations of each possible plaintext
            all_possible_plaintexts = [
                encode_int_r(i, alphabet=c.alphabet, length=plaintext_len)
                for i in plaintexts_as_ints
            ]

            # Check that plaintexts decode correctly
            self.assertEqual([
                decode_int_r(plaintext, c.alphabet)
                for plaintext in all_possible_plaintexts
            ], plaintexts_as_ints)

            # Check that there are no duplicate plaintexts
            self.assertEqual(len(set(all_possible_plaintexts)),
                             len(all_possible_plaintexts))

            # Check that all plaintexts have the expected length
            self.assertTrue(
                all(
                    len(plaintext) == plaintext_len
                    for plaintext in all_possible_plaintexts))

            all_possible_ciphertexts = [
                c.encrypt(plaintext) for plaintext in all_possible_plaintexts
            ]

            # Check that encryption is format-preserving
            self.assertEqual(set(all_possible_plaintexts),
                             set(all_possible_ciphertexts))

            all_decrypted_ciphertexts = [
                c.decrypt(ciphertext)
                for ciphertext in all_possible_ciphertexts
            ]

            # Check that encryption and decryption are inverses
            self.assertEqual(all_possible_plaintexts,
                             all_decrypted_ciphertexts)

            # Note: it would be mathematically redundant to also check first decrypting
            # and then encrypting, since permutations have only two-sided inverses.

        # Restore original DOMAIN_MIN value
        FF3Cipher.DOMAIN_MIN = domain_min_orig