예제 #1
0
 def test_decrypt_all(self):
     for testVector in testVectors:
         with self.subTest(testVector=testVector):
             c = FF3Cipher(testVector['key'], testVector['tweak'],
                           testVector['radix'])
             s = c.decrypt(testVector['ciphertext'])
             self.assertEqual(s, testVector['plaintext'])
예제 #2
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'])
예제 #3
0
 def test_encrypt_tweak56(self):
     # 56-bit tweak
     tweak = "D8E7920AFA330A"
     ciphertext = "477064185124354662"
     testVector = testVectors[0]
     c = FF3Cipher(testVector['key'], tweak)
     s = c.encrypt(testVector['plaintext'])
     self.assertEqual(s, ciphertext)
     x = c.decrypt(s)
     self.assertEqual(x, testVector['plaintext'])
예제 #4
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)
예제 #5
0
 def test_encrypt_boundaries(self):
     c = FF3Cipher("EF4359D8D580AA4F7F036D6F04FC6A94", "D8E7920AFA330A73")
     # test max length 56 digit string with default radix 10
     plaintext = "12345678901234567890123456789012345678901234567890123456"
     ct = c.encrypt(plaintext)
     pt = c.decrypt(ct)
     self.assertEqual(plaintext, pt)
     # test max length 40 alphanumeric string with radix 26
     c = FF3Cipher("EF4359D8D580AA4F7F036D6F04FC6A94", "D8E7920AFA330A73",
                   26)
     plaintext = "0123456789abcdefghijklmn"
     ct = c.encrypt(plaintext)
     pt = c.decrypt(ct)
     self.assertEqual(plaintext, pt)
     # test max length 36 alphanumeric string with radix 36
     c = FF3Cipher("EF4359D8D580AA4F7F036D6F04FC6A94", "D8E7920AFA330A73",
                   36)
     plaintext = "abcdefghijklmnopqrstuvwxyz0123456789"
     ct = c.encrypt(plaintext)
     pt = c.decrypt(ct)
     self.assertEqual(plaintext, pt)
예제 #6
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)
예제 #7
0
def test_encrypt(plaintexts):
    key = "EF4359D8D580AA4F7F036D6F04FC6A94"
    tweak = "D8E7920AFA330A73"
    for pt in plaintexts:
        c = FF3Cipher(key, tweak, 62)
        s = c.encrypt(pt)
예제 #8
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
예제 #9
0
def initialize_fpe(key, tweak, radix=10):
    Cipher.instance = FF3Cipher(key, tweak, radix)
예제 #10
0
def encrypt():
    c = FF3Cipher(sys.argv[1], sys.argv[2])
    print(c.encrypt(sys.argv[3]))