From 95e1596db04fd55d777a1fccf031e86657ab1072 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 14 Mar 2019 11:06:41 +0100 Subject: [implem-python] Passage des clés et nonces par paramètres MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/genkat_aead.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'python/genkat_aead.py') diff --git a/python/genkat_aead.py b/python/genkat_aead.py index e9f9101..3a69d72 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -46,6 +46,9 @@ def generate_test_vectors(mode, keylen): directory, 'LWC_AEAD_KAT_{keylen}_120.txt'.format(keylen=keylen) ) + nonce = bytes(range(CRYPTO_NPUBBYTES)) + key = bytes(range(keylen//8)) + with open(output_path, 'w') as output: count = 1 @@ -56,16 +59,16 @@ def generate_test_vectors(mode, keylen): msg = bytes(range(mlen)) ad = bytes(range(adlen)) - print_bstr(output, 'Key', bytes(range(keylen//8))) - print_bstr(output, 'Nonce', bytes(range(CRYPTO_NPUBBYTES))) + print_bstr(output, 'Key', key) + print_bstr(output, 'Nonce', nonce) print_bstr(output, 'PT', msg) print_bstr(output, 'AD', ad) - ct, tag = lilliput.mainEnc(msg, ad, mode, keylen) + ct, tag = lilliput.mainEnc(msg, ad, key, nonce, mode, keylen) print_bstr(output, 'CT', ct+tag) - msg2 = lilliput.mainDec(ct, tag, ad, mode, keylen) + msg2 = lilliput.mainDec(ct, tag, ad, key, nonce, mode, keylen) if msg != msg2: raise DecryptionError(msg, msg2, mode, keylen) -- cgit v1.2.3 From d8eeb99d9106b93c0a30e3ab8849d7687d2a6f29 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 14 Mar 2019 11:15:35 +0100 Subject: [implem-python] Simplification du contrôle des paramètres MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Encore un peu de duplication sur les longueurs de clés valides. On y travaille. --- python/genkat_aead.py | 4 ++-- python/lilliput.py | 55 ++++++++++++++++++++------------------------- python/parameters_i_128.py | 6 ----- python/parameters_i_192.py | 6 ----- python/parameters_i_256.py | 6 ----- python/parameters_ii_128.py | 6 ----- python/parameters_ii_192.py | 6 ----- python/parameters_ii_256.py | 6 ----- 8 files changed, 26 insertions(+), 69 deletions(-) delete mode 100644 python/parameters_i_128.py delete mode 100644 python/parameters_i_192.py delete mode 100644 python/parameters_i_256.py delete mode 100644 python/parameters_ii_128.py delete mode 100644 python/parameters_ii_192.py delete mode 100644 python/parameters_ii_256.py (limited to 'python/genkat_aead.py') diff --git a/python/genkat_aead.py b/python/genkat_aead.py index 3a69d72..6d7ca51 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -64,11 +64,11 @@ def generate_test_vectors(mode, keylen): print_bstr(output, 'PT', msg) print_bstr(output, 'AD', ad) - ct, tag = lilliput.mainEnc(msg, ad, key, nonce, mode, keylen) + ct, tag = lilliput.mainEnc(msg, ad, key, nonce, mode) print_bstr(output, 'CT', ct+tag) - msg2 = lilliput.mainDec(ct, tag, ad, key, nonce, mode, keylen) + msg2 = lilliput.mainDec(ct, tag, ad, key, nonce, mode) if msg != msg2: raise DecryptionError(msg, msg2, mode, keylen) diff --git a/python/lilliput.py b/python/lilliput.py index 79f14e5..3fe41bf 100644 --- a/python/lilliput.py +++ b/python/lilliput.py @@ -1,34 +1,23 @@ import lilliput_ae_1 import lilliput_ae_2 -import parameters_i_128 as i_128 -import parameters_i_192 as i_192 -import parameters_i_256 as i_256 -import parameters_ii_128 as ii_128 -import parameters_ii_192 as ii_192 -import parameters_ii_256 as ii_256 - BLOCK_BYTES = 16 N_BYTES = 15 -def GetParameters(mode = 1, length = 128) : - if(mode == 1 and length == 128) : - return (i_128.KEY_BITS, i_128.TWEAK_BITS, i_128.ROUNDS) - - if(mode == 1 and length == 192) : - return (i_192.KEY_BITS, i_192.TWEAK_BITS, i_192.ROUNDS) +def _getParameters(mode=1, key_length=128) : + rounds = { + 128: 32, + 192: 36, + 256: 42 + } - if(mode == 1 and length == 256) : - return (i_256.KEY_BITS, i_256.TWEAK_BITS, i_256.ROUNDS) + tweak_lengths = { + 1: 192, + 2: 128 + } - if(mode == 2 and length == 128) : - return (ii_128.KEY_BITS, ii_128.TWEAK_BITS, ii_128.ROUNDS) + return tweak_lengths[mode], rounds[key_length] - if(mode == 2 and length == 192) : - return (ii_192.KEY_BITS, ii_192.TWEAK_BITS, ii_192.ROUNDS) - - if(mode == 2 and length == 256) : - return (ii_256.KEY_BITS, ii_256.TWEAK_BITS, ii_256.ROUNDS) def ArrayToBlockbytesMatrix(array) : length = len(array) @@ -53,18 +42,21 @@ def BlockbytesMatrixToBytes(matrix): ############################################ -def _checkInputs(key, length, nonce): - if len(key) != length//8: - raise ValueError('invalid key size: {} != {}'.format(len(key), length//8)) +def _checkInputs(key, nonce): + valid_key_lengths = (128, 192, 256) + + if len(key)*8 not in valid_key_lengths: + raise ValueError('invalid key size: {} not in {}'.format(len(key)*8, valid_key_lengths)) if len(nonce) != N_BYTES: raise ValueError('nonce must be {}-byte long'.format(N_BYTES)) -def mainEnc(plaintext, adata, key, nonce, mode=1, length=128): - _checkInputs(key, length, nonce) +def mainEnc(plaintext, adata, key, nonce, mode): + _checkInputs(key, nonce) - (key_bits, tweak_bits, rounds) = GetParameters(mode, length) + key_bits = len(key)*8 + tweak_bits, rounds = _getParameters(mode, key_bits) A = adata M = plaintext @@ -84,10 +76,11 @@ def mainEnc(plaintext, adata, key, nonce, mode=1, length=128): return BlockbytesMatrixToBytes(C), bytes(tag) -def mainDec(ciphertext, tag, adata, key, nonce, mode=1, length=128): - _checkInputs(key, length, nonce) +def mainDec(ciphertext, tag, adata, key, nonce, mode): + _checkInputs(key, nonce) - (key_bits, tweak_bits, rounds) = GetParameters(mode, length) + key_bits = len(key)*8 + tweak_bits, rounds = _getParameters(mode, key_bits) A = adata C = ciphertext diff --git a/python/parameters_i_128.py b/python/parameters_i_128.py deleted file mode 100644 index 7f0675a..0000000 --- a/python/parameters_i_128.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 128 -TWEAK_BITS = 192 -ROUNDS = 32 diff --git a/python/parameters_i_192.py b/python/parameters_i_192.py deleted file mode 100644 index c513331..0000000 --- a/python/parameters_i_192.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 192 -TWEAK_BITS = 192 -ROUNDS = 36 diff --git a/python/parameters_i_256.py b/python/parameters_i_256.py deleted file mode 100644 index ab81130..0000000 --- a/python/parameters_i_256.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 256 -TWEAK_BITS = 192 -ROUNDS = 42 diff --git a/python/parameters_ii_128.py b/python/parameters_ii_128.py deleted file mode 100644 index 8647a66..0000000 --- a/python/parameters_ii_128.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 128 -TWEAK_BITS = 128 -ROUNDS = 32 diff --git a/python/parameters_ii_192.py b/python/parameters_ii_192.py deleted file mode 100644 index d17d6ec..0000000 --- a/python/parameters_ii_192.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 192 -TWEAK_BITS = 128 -ROUNDS = 36 diff --git a/python/parameters_ii_256.py b/python/parameters_ii_256.py deleted file mode 100644 index 159c78f..0000000 --- a/python/parameters_ii_256.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Lilliput ae i 128 -""" -KEY_BITS = 256 -TWEAK_BITS = 128 -ROUNDS = 42 -- cgit v1.2.3 From a7abd1a33ca68e2e2db59332b612db69ffb31496 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 14 Mar 2019 16:30:27 +0100 Subject: [implem-python] Gestion de l'échec de déchiffrement dans genkat_aead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ce serait mieux si l'API renvoyait une exception… Un jour. --- python/genkat_aead.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'python/genkat_aead.py') diff --git a/python/genkat_aead.py b/python/genkat_aead.py index 6d7ca51..5bce05f 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -28,8 +28,8 @@ class DecryptionError(Exception): def __str__(self): return '({s.mode} / {s.keylen}) Expected {exp}; got {act}'.format( s=self, - exp=bstr(self.expected), - act=bstr(self.actual) + exp=bstr(self.expected) if self.expected is not None else 'NONE', + act=bstr(self.actual) if self.actual is not None else 'NONE' ) -- cgit v1.2.3 From 6d62f24fc34dae3c28f1b1cfed664bde3edbb1ec Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 14 Mar 2019 17:17:50 +0100 Subject: [implem-python] Ajustement de l'API externe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilisation d'une enum, pour que les valeurs possibles soient explicites. Renommage des points d'entrée pour qu'ils soient uniformes et interchangeables. Transformation du tag en liste plus bas pour que lilliput.py ne se soucie pas des détails d'implémentation des fonctions en-dessous. --- python/genkat_aead.py | 16 +++++++++++----- python/lilliput.py | 41 +++++++++++++++++------------------------ python/lilliput_ae_1.py | 5 +++-- python/lilliput_ae_2.py | 5 +++-- 4 files changed, 34 insertions(+), 33 deletions(-) (limited to 'python/genkat_aead.py') diff --git a/python/genkat_aead.py b/python/genkat_aead.py index 5bce05f..daa48f8 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -import lilliput +from lilliput import encrypt, decrypt, LilliputAeMode from os import makedirs, path @@ -10,6 +10,12 @@ MAX_ADATA_LENGTH = 32 CRYPTO_NPUBBYTES = 120//8 +MODE_SUFFIXES = { + LilliputAeMode.lilliput_1: 'i', + LilliputAeMode.lilliput_2: 'ii' +} + + def bstr(buf): return ''.join('{:02X}'.format(b) for b in buf) @@ -37,7 +43,7 @@ def generate_test_vectors(mode, keylen): print('generating for', mode, keylen) directory = 'crypto_aead/lilliputae{mode}{keylen}v1'.format( - mode=mode*'i', keylen=keylen + mode=MODE_SUFFIXES[mode], keylen=keylen ) makedirs(directory, exist_ok=True) @@ -64,11 +70,11 @@ def generate_test_vectors(mode, keylen): print_bstr(output, 'PT', msg) print_bstr(output, 'AD', ad) - ct, tag = lilliput.mainEnc(msg, ad, key, nonce, mode) + ct, tag = encrypt(msg, ad, key, nonce, mode) print_bstr(output, 'CT', ct+tag) - msg2 = lilliput.mainDec(ct, tag, ad, key, nonce, mode) + msg2 = decrypt(ct, tag, ad, key, nonce, mode) if msg != msg2: raise DecryptionError(msg, msg2, mode, keylen) @@ -79,6 +85,6 @@ def generate_test_vectors(mode, keylen): if __name__ == '__main__': - for mode in 1, 2: + for mode in LilliputAeMode: for keylen in 128, 192, 256: generate_test_vectors(mode, keylen) diff --git a/python/lilliput.py b/python/lilliput.py index f9c1b09..90a0ed1 100644 --- a/python/lilliput.py +++ b/python/lilliput.py @@ -1,40 +1,33 @@ +from enum import Enum + import lilliput_ae_1 import lilliput_ae_2 from constants import NONCE_BYTES -def _checkInputs(key, nonce): +class LilliputAeMode(Enum): + lilliput_1 = lilliput_ae_1 + lilliput_2 = lilliput_ae_2 + + +def _checkInputs(key, mode, nonce): valid_key_lengths = (128, 192, 256) if len(key)*8 not in valid_key_lengths: raise ValueError('invalid key size: {} not in {}'.format(len(key)*8, valid_key_lengths)) + if mode.name not in LilliputAeMode.__members__: + raise ValueError('invalid mode: use a member of the LilliputAeMode enumeration') + if len(nonce) != NONCE_BYTES: raise ValueError('nonce must be {}-byte long'.format(NONCE_BYTES)) -def mainEnc(plaintext, adata, key, nonce, mode): - _checkInputs(key, nonce) - - A = adata - M = plaintext - N = nonce - - if(mode == 1) : - return lilliput_ae_1.OCB3Enc(A, M, N, key) - if(mode == 2) : - return lilliput_ae_2.SCT2Enc(A, M, N, key) - - -def mainDec(ciphertext, tag, adata, key, nonce, mode): - _checkInputs(key, nonce) +def encrypt(plaintext, adata, key, nonce, mode): + _checkInputs(key, mode, nonce) + return mode.value.encrypt(adata, plaintext, nonce, key) - A = adata - C = ciphertext - N = nonce - tag = list(tag) - if(mode == 1) : - return lilliput_ae_1.OCB3Dec(A, C, N, tag, key) - if(mode == 2) : - return lilliput_ae_2.SCT2Dec(A, C, N, tag, key) +def decrypt(ciphertext, tag, adata, key, nonce, mode): + _checkInputs(key, mode, nonce) + return mode.value.decrypt(adata, ciphertext, nonce, tag, key) diff --git a/python/lilliput_ae_1.py b/python/lilliput_ae_1.py index 9de753c..8b618d9 100644 --- a/python/lilliput_ae_1.py +++ b/python/lilliput_ae_1.py @@ -129,7 +129,7 @@ def TreatMessageDec(C, N, key) : ################################################################################ -def OCB3Enc(A, M, N, key) : +def encrypt(A, M, N, key) : K = list(key) Auth = BuildAuth(TWEAK_BITS, A, K) @@ -139,8 +139,9 @@ def OCB3Enc(A, M, N, key) : return BlockbytesMatrixToBytes(C), bytes(tag) -def OCB3Dec(A, C, N, tag, key) : +def decrypt(A, C, N, tag, key) : K = list(key) + tag = list(tag) Auth = BuildAuth(TWEAK_BITS, A, K) (Final, M) = TreatMessageDec(C, N, K) diff --git a/python/lilliput_ae_2.py b/python/lilliput_ae_2.py index cb1d1c4..f455f43 100644 --- a/python/lilliput_ae_2.py +++ b/python/lilliput_ae_2.py @@ -98,7 +98,7 @@ def MessageEncryption(M, N, tag, key) : return C ################################################################################ -def SCT2Enc(A, M, N, key) : +def encrypt(A, M, N, key) : K = list(key) Auth = BuildAuth(TWEAK_BITS, A, K) @@ -108,8 +108,9 @@ def SCT2Enc(A, M, N, key) : return BlockbytesMatrixToBytes(C), bytes(tag) -def SCT2Dec(A, C, N, tag, key) : +def decrypt(A, C, N, tag, key) : K = list(key) + tag = list(tag) M = BlockbytesMatrixToBytes( MessageEncryption(C, N, tag, K) -- cgit v1.2.3 From aaf0d2c49f343e909dc69b487056ca31238ffabf Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 21 Mar 2019 16:04:16 +0100 Subject: [implem-python] Nettoyage PEP8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - espaces avant ':' - espaces en trop après ',' - parenthèses dans les if - levée d'exception plutôt que 'return None' implicite Simplification de genkat_aead.py grâce à l'exception levée par le module. --- python/constants.py | 66 ++++++++++++++++++++++++----------------------- python/genkat_aead.py | 26 ++----------------- python/helpers.py | 23 +++++++++++++---- python/lilliput_ae_1.py | 31 ++++++++++++---------- python/lilliput_ae_2.py | 49 +++++++++++++++++++---------------- python/lilliput_tbc.py | 54 +++++++++++++++++++------------------- python/multiplications.py | 12 ++++----- 7 files changed, 131 insertions(+), 130 deletions(-) (limited to 'python/genkat_aead.py') diff --git a/python/constants.py b/python/constants.py index 764febb..c61dfe0 100644 --- a/python/constants.py +++ b/python/constants.py @@ -3,35 +3,37 @@ BLOCK_BYTES = BLOCK_BITS//8 NONCE_BYTES = 15 -Sbox = [32, 0, 178, 133, 59, 53, 166, 164, - 48, 228, 106, 44, 255, 89, 226, 14, - 248, 30, 122, 128, 21, 189, 62, 177, - 232, 243, 162, 194, 218, 81, 42, 16, - 33, 1, 35, 120, 92, 36, 39, 181, - 55, 199, 43, 31, 174, 10, 119, 95, - 111, 9, 157, 129, 4, 90, 41, 220, - 57, 156, 5, 87, 151, 116, 121, 23, - 68, 198, 230, 233, 221, 65, 242, 138, - 84, 202, 110, 74, 225, 173, 182, 136, - 28, 152, 126, 206, 99, 73, 58, 93, - 12, 239, 246, 52, 86, 37, 46, 214, - 103, 117, 85, 118, 184, 210, 97, 217, - 113, 139, 205, 11, 114, 108, 49, 75, - 105, 253, 123, 109, 96, 60, 47, 98, - 63, 34, 115, 19, 201, 130, 127, 83, - 50, 18, 160, 124, 2, 135, 132, 134, - 147, 78, 104, 70, 141, 195, 219, 236, - 155, 183, 137, 146, 167, 190, 61, 216, - 234, 80, 145, 241, 51, 56, 224, 169, - 163, 131, 161, 27, 207, 6, 149, 7, - 158, 237, 185, 245, 76, 192, 244, 45, - 22, 250, 180, 3, 38, 179, 144, 79, - 171, 101, 252, 254, 20, 247, 227, 148, - 238, 172, 140, 26, 222, 203, 40, 64, - 125, 200, 196, 72, 107, 223, 165, 82, - 229, 251, 215, 100, 249, 240, 211, 94, - 102, 150, 143, 29, 69, 54, 204, 197, - 77, 159, 191, 15, 209, 8, 235, 67, - 66, 25, 231, 153, 168, 142, 88, 193, - 154, 212, 24, 71, 170, 175, 188, 91, - 213, 17, 208, 176, 112, 187, 13, 186] +Sbox = [ + 0x20, 0x00, 0xb2, 0x85, 0x3b, 0x35, 0xa6, 0xa4, + 0x30, 0xe4, 0x6a, 0x2c, 0xff, 0x59, 0xe2, 0x0e, + 0xf8, 0x1e, 0x7a, 0x80, 0x15, 0xbd, 0x3e, 0xb1, + 0xe8, 0xf3, 0xa2, 0xc2, 0xda, 0x51, 0x2a, 0x10, + 0x21, 0x01, 0x23, 0x78, 0x5c, 0x24, 0x27, 0xb5, + 0x37, 0xc7, 0x2b, 0x1f, 0xae, 0x0a, 0x77, 0x5f, + 0x6f, 0x09, 0x9d, 0x81, 0x04, 0x5a, 0x29, 0xdc, + 0x39, 0x9c, 0x05, 0x57, 0x97, 0x74, 0x79, 0x17, + 0x44, 0xc6, 0xe6, 0xe9, 0xdd, 0x41, 0xf2, 0x8a, + 0x54, 0xca, 0x6e, 0x4a, 0xe1, 0xad, 0xb6, 0x88, + 0x1c, 0x98, 0x7e, 0xce, 0x63, 0x49, 0x3a, 0x5d, + 0x0c, 0xef, 0xf6, 0x34, 0x56, 0x25, 0x2e, 0xd6, + 0x67, 0x75, 0x55, 0x76, 0xb8, 0xd2, 0x61, 0xd9, + 0x71, 0x8b, 0xcd, 0x0b, 0x72, 0x6c, 0x31, 0x4b, + 0x69, 0xfd, 0x7b, 0x6d, 0x60, 0x3c, 0x2f, 0x62, + 0x3f, 0x22, 0x73, 0x13, 0xc9, 0x82, 0x7f, 0x53, + 0x32, 0x12, 0xa0, 0x7c, 0x02, 0x87, 0x84, 0x86, + 0x93, 0x4e, 0x68, 0x46, 0x8d, 0xc3, 0xdb, 0xec, + 0x9b, 0xb7, 0x89, 0x92, 0xa7, 0xbe, 0x3d, 0xd8, + 0xea, 0x50, 0x91, 0xf1, 0x33, 0x38, 0xe0, 0xa9, + 0xa3, 0x83, 0xa1, 0x1b, 0xcf, 0x06, 0x95, 0x07, + 0x9e, 0xed, 0xb9, 0xf5, 0x4c, 0xc0, 0xf4, 0x2d, + 0x16, 0xfa, 0xb4, 0x03, 0x26, 0xb3, 0x90, 0x4f, + 0xab, 0x65, 0xfc, 0xfe, 0x14, 0xf7, 0xe3, 0x94, + 0xee, 0xac, 0x8c, 0x1a, 0xde, 0xcb, 0x28, 0x40, + 0x7d, 0xc8, 0xc4, 0x48, 0x6b, 0xdf, 0xa5, 0x52, + 0xe5, 0xfb, 0xd7, 0x64, 0xf9, 0xf0, 0xd3, 0x5e, + 0x66, 0x96, 0x8f, 0x1d, 0x45, 0x36, 0xcc, 0xc5, + 0x4d, 0x9f, 0xbf, 0x0f, 0xd1, 0x08, 0xeb, 0x43, + 0x42, 0x19, 0xe7, 0x99, 0xa8, 0x8e, 0x58, 0xc1, + 0x9a, 0xd4, 0x18, 0x47, 0xaa, 0xaf, 0xbc, 0x5b, + 0xd5, 0x11, 0xd0, 0xb0, 0x70, 0xbb, 0x0d, 0xba +] diff --git a/python/genkat_aead.py b/python/genkat_aead.py index daa48f8..8b38d9b 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -16,27 +16,8 @@ MODE_SUFFIXES = { } -def bstr(buf): - return ''.join('{:02X}'.format(b) for b in buf) - - def print_bstr(output, label, buf): - print('{l} = {b}'.format(l=label, b=bstr(buf)), file=output) - - -class DecryptionError(Exception): - def __init__(self, expected, actual, mode, keylen): - self.expected = expected - self.actual = actual - self.mode = mode - self.keylen = keylen - - def __str__(self): - return '({s.mode} / {s.keylen}) Expected {exp}; got {act}'.format( - s=self, - exp=bstr(self.expected) if self.expected is not None else 'NONE', - act=bstr(self.actual) if self.actual is not None else 'NONE' - ) + print('{l} = {b}'.format(l=label, b=buf.hex().upper()), file=output) def generate_test_vectors(mode, keylen): @@ -74,10 +55,7 @@ def generate_test_vectors(mode, keylen): print_bstr(output, 'CT', ct+tag) - msg2 = decrypt(ct, tag, ad, key, nonce, mode) - - if msg != msg2: - raise DecryptionError(msg, msg2, mode, keylen) + decrypt(ct, tag, ad, key, nonce, mode) count+=1 diff --git a/python/helpers.py b/python/helpers.py index 45c48c9..b02bea4 100644 --- a/python/helpers.py +++ b/python/helpers.py @@ -2,20 +2,20 @@ from constants import BLOCK_BITS, BLOCK_BYTES from lilliput_tbc import LilliputTBCEnc -def ArrayToBlockbytesMatrix(array) : +def ArrayToBlockbytesMatrix(array): length = len(array) pad = 0 - if(length % BLOCK_BYTES == 0) : + if length % BLOCK_BYTES == 0: number_blocks = int(length / BLOCK_BYTES) - else : + else: number_blocks = int((length + (BLOCK_BYTES - (length % BLOCK_BYTES))) / BLOCK_BYTES) pad = 1 matrix = [[0] * BLOCK_BYTES for block in range(0, number_blocks - pad)] - if(pad == 1) : + if pad == 1: matrix.append([0] * (length % BLOCK_BYTES)) - for byte in range(0, length) : + for byte in range(0, length): matrix[int(byte / BLOCK_BYTES)][byte % BLOCK_BYTES] = array[byte] return matrix @@ -85,3 +85,16 @@ def BuildAuth(t, A, key): Auth = XorState(Auth, enc) return Auth + + +class TagValidationError(Exception): + def __init__(self, announced, computed): + msg = '\n'.join(( + 'Invalid tag:', + announced.hex().upper()+' (announced)', + computed.hex().upper()+' (computed)' + )) + + super().__init__(msg) + self._announced = announced + self._computed = computed diff --git a/python/lilliput_ae_1.py b/python/lilliput_ae_1.py index 8b618d9..9aad3a6 100644 --- a/python/lilliput_ae_1.py +++ b/python/lilliput_ae_1.py @@ -11,6 +11,7 @@ from helpers import ( BlockbytesMatrixToBytes, BuildAuth, Padding10LSB, + TagValidationError, XorState ) @@ -19,23 +20,23 @@ TWEAK_BITS = 192 TWEAK_BYTES = TWEAK_BITS//8 -def LowPart(array, number_bits) : +def LowPart(array, number_bits): shifted = 0 - for byte in range(0, len(array)) : + for byte in range(0, len(array)): shifted |= (array[byte] << (8 * byte)) mask = 0 - for bit in range(0, number_bits) : + for bit in range(0, number_bits): mask |= (0x1 << bit) lower_part = shifted & mask will_padd = 0 - if (number_bits % 8) != 0 : + if number_bits % 8 != 0: will_padd = 1 - lower_part_byte = [0 for byte in range(0, int(number_bits / 8) + will_padd)] - for byte in range(0, int(number_bits / 8) + will_padd) : + lower_part_byte = [0 for byte in range(0, int(number_bits / 8) + will_padd)] + for byte in range(0, int(number_bits / 8) + will_padd): lower_part_byte[byte] = lower_part & 0xff lower_part = lower_part >> 8 @@ -50,13 +51,13 @@ class _MessageTweak(Enum): def TweakMessage(N, j, padding): - tweak = [0 for byte in range(0, TWEAK_BYTES)] - for byte in range(NONCE_BYTES-1, -1, -1) : + tweak = [0 for byte in range(0, TWEAK_BYTES)] + for byte in range(NONCE_BYTES-1, -1, -1): tweak[byte + (TWEAK_BYTES-NONCE_BYTES)] |= (N[byte] & 0xf0) >> 4 tweak[byte + (TWEAK_BYTES-NONCE_BYTES-1)] |= (N[byte] & 0x0f) << 4 tweak[TWEAK_BYTES-NONCE_BYTES-1] |= ((j >> 64) & 0xf) - for byte in range(TWEAK_BYTES-NONCE_BYTES-2, -1, -1) : + for byte in range(TWEAK_BYTES-NONCE_BYTES-2, -1, -1): tweak[byte] = (j >> (8 * byte)) & 0xff tweak[-1] |= padding.value<<4 @@ -96,7 +97,7 @@ def TreatMessageEnc(M, N, key): return (Final, C) -def TreatMessageDec(C, N, key) : +def TreatMessageDec(C, N, key): checksum = [0 for byte in range(0, BLOCK_BYTES)] l = len(C)//BLOCK_BYTES @@ -129,7 +130,7 @@ def TreatMessageDec(C, N, key) : ################################################################################ -def encrypt(A, M, N, key) : +def encrypt(A, M, N, key): K = list(key) Auth = BuildAuth(TWEAK_BITS, A, K) @@ -139,7 +140,7 @@ def encrypt(A, M, N, key) : return BlockbytesMatrixToBytes(C), bytes(tag) -def decrypt(A, C, N, tag, key) : +def decrypt(A, C, N, tag, key): K = list(key) tag = list(tag) @@ -147,5 +148,7 @@ def decrypt(A, C, N, tag, key) : (Final, M) = TreatMessageDec(C, N, K) tag2 = XorState(Auth, Final) - if(tag == tag2) : - return BlockbytesMatrixToBytes(M) + if tag != tag2: + raise TagValidationError(tag, tag2) + + return BlockbytesMatrixToBytes(M) diff --git a/python/lilliput_ae_2.py b/python/lilliput_ae_2.py index 624fd93..3f72020 100644 --- a/python/lilliput_ae_2.py +++ b/python/lilliput_ae_2.py @@ -3,12 +3,13 @@ """ import lilliput_tbc as ltbc -from constants import BLOCK_BITS, BLOCK_BYTES +from constants import BLOCK_BYTES from helpers import ( ArrayToBlockbytesMatrix, BlockbytesMatrixToBytes, BuildAuth, Padding10LSB, + TagValidationError, XorState ) @@ -18,30 +19,31 @@ TWEAK_BYTES = TWEAK_BITS//8 def TweakTag(j, padded): - tweak = [0 for byte in range(0, TWEAK_BYTES)] + tweak = [0 for byte in range(0, TWEAK_BYTES)] - tweak[TWEAK_BYTES - 1] |= ((j >> 120) & 0xf) - for byte in range(TWEAK_BYTES - 2, -1, -1) : - tweak[byte] = (j >> (8 * byte)) & 0xff + tweak[TWEAK_BYTES - 1] |= ((j >> 120) & 0xf) + for byte in range(TWEAK_BYTES - 2, -1, -1): + tweak[byte] = (j >> (8 * byte)) & 0xff - if padded: - tweak[TWEAK_BYTES - 1] |= 0x40 + if padded: + tweak[TWEAK_BYTES - 1] |= 0x40 + + return tweak - return tweak -def TweakTagEnd(N) : - tweak = [0 for byte in range(0, TWEAK_BYTES)] +def TweakTagEnd(N): + tweak = [0 for byte in range(0, TWEAK_BYTES)] - for byte in range(0, TWEAK_BYTES - 1) : + for byte in range(0, TWEAK_BYTES - 1): tweak[byte] = N[byte] tweak[TWEAK_BYTES - 1] = 0x10 return tweak -def AddTagJ(tag, j) : +def AddTagJ(tag, j): array_j = [0 for byte in range(0, TWEAK_BYTES)] - for byte in range(0, TWEAK_BYTES) : + for byte in range(0, TWEAK_BYTES): array_j[byte] = (j >> (byte * 8)) xorr = XorState(tag, array_j) @@ -51,19 +53,19 @@ def AddTagJ(tag, j) : return xorr -def MesssageAuthTag(M, N, Auth, key) : +def MesssageAuthTag(M, N, Auth, key): l = len(M)//BLOCK_BYTES padding_bytes = len(M)%BLOCK_BYTES tag = list(Auth) M = ArrayToBlockbytesMatrix(M) - for j in range(0, l) : + for j in range(0, l): tweak = TweakTag(j, False) encryption = ltbc.LilliputTBCEnc(tweak, key, M[j]) tag = XorState(tag, encryption) - if padding_bytes > 0 : + if padding_bytes > 0: tweak = TweakTag(l, True) m_padded = Padding10LSB(M[l], 8*padding_bytes) encryption = ltbc.LilliputTBCEnc(tweak, key, m_padded) @@ -76,14 +78,14 @@ def MesssageAuthTag(M, N, Auth, key) : return tag -def MessageEncryption(M, N, tag, key) : +def MessageEncryption(M, N, tag, key): l = len(M)//BLOCK_BYTES padding_bytes = len(M)%BLOCK_BYTES M = ArrayToBlockbytesMatrix(M) C = [] - for j in range(0, l) : + for j in range(0, l): tweak = AddTagJ(tag, j) padded_nonce = list(N) + [0x00] encryption = ltbc.LilliputTBCEnc(tweak, key, padded_nonce) @@ -97,8 +99,9 @@ def MessageEncryption(M, N, tag, key) : return C + ################################################################################ -def encrypt(A, M, N, key) : +def encrypt(A, M, N, key): K = list(key) Auth = BuildAuth(TWEAK_BITS, A, K) @@ -108,7 +111,7 @@ def encrypt(A, M, N, key) : return BlockbytesMatrixToBytes(C), bytes(tag) -def decrypt(A, C, N, tag, key) : +def decrypt(A, C, N, tag, key): K = list(key) tag = list(tag) @@ -118,5 +121,7 @@ def decrypt(A, C, N, tag, key) : Auth = BuildAuth(TWEAK_BITS, A, K) tag2 = MesssageAuthTag(M, N, Auth, K) - if tag == tag2: - return M + if tag != tag2: + raise TagValidationError(tag, tag2) + + return M diff --git a/python/lilliput_tbc.py b/python/lilliput_tbc.py index 418d083..9dc7df2 100644 --- a/python/lilliput_tbc.py +++ b/python/lilliput_tbc.py @@ -10,7 +10,7 @@ permutationInv = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7] ################################################################################ -def BuildTweakey(tweak, key) : +def BuildTweakey(tweak, key): return tweak+key ############################# @@ -18,7 +18,7 @@ def BuildTweakey(tweak, key) : def _lane(TK, j): return TK[j*8:(j+1)*8] -def RoundTweakeySchedule(tweakey) : +def RoundTweakeySchedule(tweakey): p = len(tweakey)//8 multiplied_lanes = ( @@ -45,7 +45,7 @@ def TweakeyScheduleWhole(tweakey, r): TKs = [tweakey] RTKs = [SubTweakeyExtract(TKs[0], 0)] - for i in range(1, r) : + for i in range(1, r): TKs.append(RoundTweakeySchedule(TKs[i-1])) RTKs.append(SubTweakeyExtract(TKs[i], i)) @@ -54,69 +54,69 @@ def TweakeyScheduleWhole(tweakey, r): ################################################################################ -def NonLinearLayer(state, subtweakey) : +def NonLinearLayer(state, subtweakey): variables_xored = [0 for byte in range(0, 8)] - for byte in range(0,8) : + for byte in range(0,8): variables_xored[byte] = state[byte] ^ subtweakey[byte] variables_sboxed = [0 for byte in range(0, 8)] - for byte in range(0, 8) : + for byte in range(0, 8): variables_sboxed[byte] = Sbox[variables_xored[byte]] state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0,BLOCK_BYTES) : + for byte in range(0,BLOCK_BYTES): state_output[byte] = state[byte] - for byte in range(0, 8) : + for byte in range(0, 8): state_output[15 - byte] ^= variables_sboxed[byte] return state_output -def LinearLayer(state) : +def LinearLayer(state): state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state_output[byte] = state[byte] - for byte in range(1, 8) : + for byte in range(1, 8): state_output[15] ^= state[byte] - for byte in range(9, 15) : + for byte in range(9, 15): state_output[byte] ^= state[7] return state_output -def PermutationLayerEnc(state) : +def PermutationLayerEnc(state): state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state_output[byte] = state[permutation[byte]] return state_output -def PermutationLayerDec(state) : +def PermutationLayerDec(state): state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state_output[byte] = state[permutationInv[byte]] return state_output -def OneRoundEGFNEnc(state, subtweakey) : +def OneRoundEGFNEnc(state, subtweakey): state_non_linear = NonLinearLayer(state, subtweakey) state_linear = LinearLayer(state_non_linear) state_permutation = PermutationLayerEnc(state_linear) return state_permutation -def LastRoundEGFN(state, subtweakey) : +def LastRoundEGFN(state, subtweakey): state_non_linear = NonLinearLayer(state, subtweakey) state_linear = LinearLayer(state_non_linear) return state_linear -def OneRoundEGFNDec(state, subtweakey) : +def OneRoundEGFNDec(state, subtweakey): state_non_linear = NonLinearLayer(state, subtweakey) state_linear = LinearLayer(state_non_linear) state_permutation = PermutationLayerDec(state_linear) @@ -136,20 +136,20 @@ def _rounds(key_bytes): ################################################################################ # Lilliput TBC -def LilliputTBCEnc(tweak, key, message) : +def LilliputTBCEnc(tweak, key, message): r = _rounds(len(key)) tweakey = BuildTweakey(tweak, key) RTKs = TweakeyScheduleWhole(tweakey, r) state = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state[byte] = message[byte] - for i in range(0, r-1) : + for i in range(0, r-1): state_output = OneRoundEGFNEnc(state, RTKs[i]) - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state[byte] = state_output[byte] state_output = LastRoundEGFN(state, RTKs[r-1]) @@ -157,20 +157,20 @@ def LilliputTBCEnc(tweak, key, message) : return state_output -def LilliputTBCDec(tweak, key, cipher) : +def LilliputTBCDec(tweak, key, cipher): r = _rounds(len(key)) tweakey = BuildTweakey(tweak, key) RTKs = TweakeyScheduleWhole(tweakey, r) state = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state[byte] = cipher[byte] - for i in range(0, r-1) : + for i in range(0, r-1): state_output = OneRoundEGFNDec(state, RTKs[r-i-1]) - for byte in range(0, BLOCK_BYTES) : + for byte in range(0, BLOCK_BYTES): state[byte] = state_output[byte] state_output = LastRoundEGFN(state, RTKs[0]) diff --git a/python/multiplications.py b/python/multiplications.py index 7babd50..c5f1e44 100644 --- a/python/multiplications.py +++ b/python/multiplications.py @@ -1,6 +1,6 @@ # Multiply by matrix M -def _multiplyM(lane) : +def _multiplyM(lane): multiplied_lane = [lane[(byte-1) % 8] for byte in range(0, 8)] multiplied_lane[2] ^= ((lane[6] << 2) & 0xff) @@ -9,7 +9,7 @@ def _multiplyM(lane) : return multiplied_lane -def _multiplyM2(lane) : +def _multiplyM2(lane): multiplied_lane = [lane[(byte-2) % 8] for byte in range(0, 8)] multiplied_lane[2] ^= ((lane[5] << 2) & 0xff) @@ -35,7 +35,7 @@ def _multiplyM2(lane) : return multiplied_lane -def _multiplyM3(lane) : +def _multiplyM3(lane): multiplied_lane = [lane[(byte-3) % 8] for byte in range(0, 8)] multiplied_lane[2] ^= ((lane[4] << 2) & 0xff) ^ ((lane[5] << 5) & 0xff) @@ -86,7 +86,7 @@ def _multiplyM3(lane) : return multiplied_lane -def _multiplyMR(lane) : +def _multiplyMR(lane): multiplied_lane = [lane[(byte+1) % 8] for byte in range(0, 8)] multiplied_lane[2] ^= ((lane[4] >> 3) & 0xff) @@ -96,7 +96,7 @@ def _multiplyMR(lane) : return multiplied_lane -def _multiplyMR2(lane) : +def _multiplyMR2(lane): multiplied_lane = [lane[(byte+2) % 8] for byte in range(0, 8)] multiplied_lane[1] ^= ((lane[4] >> 3) & 0xff) @@ -120,7 +120,7 @@ def _multiplyMR2(lane) : return multiplied_lane -def _multiplyMR3(lane) : +def _multiplyMR3(lane): multiplied_lane = [lane[(byte+3) % 8] for byte in range(0, 8)] multiplied_lane[0] ^= ((lane[4] >> 3) & 0xff) -- cgit v1.2.3 From ba01ba773731cb2c906beb6855dfea588dc8cf09 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Fri, 22 Mar 2019 14:48:47 +0100 Subject: [implem-python] Création de la surcouche "crypto_aead" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il ne reste plus qu'à générer les dossiers lilliputae*/add_python et les fichiers parameters.py correspondants, et on peut ajouter le tout à l'archive à soumettre au NIST. --- python/.gitignore | 2 ++ python/compare.sh | 8 ++++---- python/crypto_aead.py | 18 ++++++++++++++++++ python/generate-vectors.sh | 27 +++++++++++++++++++++++++++ python/genkat_aead.py | 43 ++++++++++++------------------------------- python/lilliput/__init__.py | 26 ++++++++++++-------------- python/lilliput/constants.py | 1 + 7 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 python/.gitignore create mode 100644 python/crypto_aead.py create mode 100755 python/generate-vectors.sh (limited to 'python/genkat_aead.py') diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000..d9aa5d4 --- /dev/null +++ b/python/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +results \ No newline at end of file diff --git a/python/compare.sh b/python/compare.sh index 7a9cdc7..41f27b6 100755 --- a/python/compare.sh +++ b/python/compare.sh @@ -5,11 +5,11 @@ set -eux -mkdir -p crypto_aead_ref +mkdir -p results/crypto_aead_ref for d in ../../SOUMISSION_NIST/REFERENCE_IMPLEMENTATION/crypto_aead/lilliputaei* do - mkdir -p crypto_aead_ref/$(basename $d) - cp $d/LWC*.txt crypto_aead_ref/$(basename $d)/ + mkdir -p results/crypto_aead_ref/$(basename $d) + cp $d/LWC*.txt results/crypto_aead_ref/$(basename $d)/ done -diff -ru crypto_aead_ref crypto_aead +diff -ru results/crypto_aead_ref results/crypto_aead diff --git a/python/crypto_aead.py b/python/crypto_aead.py new file mode 100644 index 0000000..792369c --- /dev/null +++ b/python/crypto_aead.py @@ -0,0 +1,18 @@ +import lilliput +from lilliput.constants import NONCE_BYTES as NPUBBYTES, TAG_BYTES + +# Import KEYBYTES to expose it to genkat_aead. +# Import MODE to provide it to lilliput. +from parameters import KEYBYTES, MODE + + +def encrypt(m, ad, npub, k): + c, tag = lilliput.encrypt(m, ad, k, npub, MODE) + return c+tag + + +def decrypt(c, ad, npub, k): + clen = len(c)-TAG_BYTES + ctext = c[:clen] + tag = c[clen:] + return lilliput.decrypt(ctext, tag, ad, k, npub, MODE) diff --git a/python/generate-vectors.sh b/python/generate-vectors.sh new file mode 100755 index 0000000..90b5840 --- /dev/null +++ b/python/generate-vectors.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -eu + +rm -rf results + +mkdir -p results/crypto_aead/lilliputae{i,ii}{128,192,256}v1 + +declare -A names=([1]=lilliputaei [2]=lilliputaeii) + +for mode in 1 2 +do + for keylen in 128 192 256 + do + echo generating for ${mode} ${keylen} + + cat < results/parameters.py +MODE = ${mode} +KEYBYTES = $((keylen/8)) +EOF + + PYTHONPATH=results ./genkat_aead.py + + dest=results/crypto_aead/${names[${mode}]}${keylen}v1 + mv LWC_AEAD_KAT_${keylen}_120.txt ${dest} + done +done diff --git a/python/genkat_aead.py b/python/genkat_aead.py index 8b38d9b..01bed6f 100755 --- a/python/genkat_aead.py +++ b/python/genkat_aead.py @@ -1,40 +1,23 @@ #!/usr/bin/env python3 -from lilliput import encrypt, decrypt, LilliputAeMode -from os import makedirs, path +import crypto_aead MAX_MESSAGE_LENGTH = 32 MAX_ADATA_LENGTH = 32 -CRYPTO_NPUBBYTES = 120//8 - - -MODE_SUFFIXES = { - LilliputAeMode.lilliput_1: 'i', - LilliputAeMode.lilliput_2: 'ii' -} - def print_bstr(output, label, buf): print('{l} = {b}'.format(l=label, b=buf.hex().upper()), file=output) -def generate_test_vectors(mode, keylen): - print('generating for', mode, keylen) - - directory = 'crypto_aead/lilliputae{mode}{keylen}v1'.format( - mode=MODE_SUFFIXES[mode], keylen=keylen - ) - - makedirs(directory, exist_ok=True) - - output_path = path.join( - directory, 'LWC_AEAD_KAT_{keylen}_120.txt'.format(keylen=keylen) +def generate_test_vectors(): + output_path = 'LWC_AEAD_KAT_{key}_{npub}.txt'.format( + key=crypto_aead.KEYBYTES*8, npub=crypto_aead.NPUBBYTES*8 ) - nonce = bytes(range(CRYPTO_NPUBBYTES)) - key = bytes(range(keylen//8)) + npub = bytes(range(crypto_aead.NPUBBYTES)) + key = bytes(range(crypto_aead.KEYBYTES)) with open(output_path, 'w') as output: @@ -47,22 +30,20 @@ def generate_test_vectors(mode, keylen): ad = bytes(range(adlen)) print_bstr(output, 'Key', key) - print_bstr(output, 'Nonce', nonce) + print_bstr(output, 'Nonce', npub) print_bstr(output, 'PT', msg) print_bstr(output, 'AD', ad) - ct, tag = encrypt(msg, ad, key, nonce, mode) + ct = crypto_aead.encrypt(msg, ad, npub, key) - print_bstr(output, 'CT', ct+tag) + print_bstr(output, 'CT', ct) - decrypt(ct, tag, ad, key, nonce, mode) + crypto_aead.decrypt(ct, ad, npub, key) - count+=1 + count += 1 print(file=output) if __name__ == '__main__': - for mode in LilliputAeMode: - for keylen in 128, 192, 256: - generate_test_vectors(mode, keylen) + generate_test_vectors() diff --git a/python/lilliput/__init__.py b/python/lilliput/__init__.py index 43179f8..5fbc0de 100644 --- a/python/lilliput/__init__.py +++ b/python/lilliput/__init__.py @@ -1,33 +1,31 @@ -from enum import Enum - from . import lilliput_ae_1 from . import lilliput_ae_2 from .constants import NONCE_BYTES -class LilliputAeMode(Enum): - lilliput_1 = lilliput_ae_1 - lilliput_2 = lilliput_ae_2 +_AE_MODES = { + 1: lilliput_ae_1, + 2: lilliput_ae_2 +} -def _checkInputs(key, mode, nonce): +def _check_inputs(key, mode, nonce): valid_key_lengths = (128, 192, 256) - if len(key)*8 not in valid_key_lengths: raise ValueError('invalid key size: {} not in {}'.format(len(key)*8, valid_key_lengths)) - if mode.name not in LilliputAeMode.__members__: - raise ValueError('invalid mode: use a member of the LilliputAeMode enumeration') + if mode not in _AE_MODES: + raise ValueError('invalid mode: {} not in {}'.format(mode, tuple(_AE_MODES))) if len(nonce) != NONCE_BYTES: - raise ValueError('nonce must be {}-byte long'.format(NONCE_BYTES)) + raise ValueError('invalid nonce size: expecting {}, have {}'.format(NONCE_BYTES, len(nonce))) def encrypt(plaintext, adata, key, nonce, mode): - _checkInputs(key, mode, nonce) - return mode.value.encrypt(adata, plaintext, nonce, key) + _check_inputs(key, mode, nonce) + return _AE_MODES[mode].encrypt(adata, plaintext, nonce, key) def decrypt(ciphertext, tag, adata, key, nonce, mode): - _checkInputs(key, mode, nonce) - return mode.value.decrypt(adata, ciphertext, nonce, tag, key) + _check_inputs(key, mode, nonce) + return _AE_MODES[mode].decrypt(adata, ciphertext, nonce, tag, key) diff --git a/python/lilliput/constants.py b/python/lilliput/constants.py index c61dfe0..0c9b89f 100644 --- a/python/lilliput/constants.py +++ b/python/lilliput/constants.py @@ -1,6 +1,7 @@ BLOCK_BITS = 128 BLOCK_BYTES = BLOCK_BITS//8 NONCE_BYTES = 15 +TAG_BYTES = 16 Sbox = [ -- cgit v1.2.3 From e83abe9fdbab07e6df80443240d4d649303a3dd4 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Fri, 22 Mar 2019 16:41:34 +0100 Subject: [implem-python] Déplacement dans le dossier SOUMISSION_NIST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Et ajout d'un métascript pour vérifier la conformité. Il ne reste plus qu'à… (bis) --- .gitignore | 1 + python/.gitignore | 2 - python/compare.sh | 15 --- python/crypto_aead.py | 18 --- python/generate-vectors.sh | 27 ----- python/genkat_aead.py | 49 -------- python/lilliput/__init__.py | 31 ----- python/lilliput/constants.py | 40 ------- python/lilliput/helpers.py | 92 -------------- python/lilliput/lilliput_ae_1.py | 155 ------------------------ python/lilliput/lilliput_ae_2.py | 127 -------------------- python/lilliput/multiplications.py | 186 ----------------------------- python/lilliput/tbc.py | 178 --------------------------- src/add_python/lilliput/__init__.py | 31 +++++ src/add_python/lilliput/constants.py | 40 +++++++ src/add_python/lilliput/helpers.py | 92 ++++++++++++++ src/add_python/lilliput/lilliput_ae_1.py | 155 ++++++++++++++++++++++++ src/add_python/lilliput/lilliput_ae_2.py | 127 ++++++++++++++++++++ src/add_python/lilliput/multiplications.py | 186 +++++++++++++++++++++++++++++ src/add_python/lilliput/tbc.py | 178 +++++++++++++++++++++++++++ test/python.sh | 11 ++ test/python/compare.sh | 17 +++ test/python/crypto_aead.py | 18 +++ test/python/generate-vectors.sh | 31 +++++ test/python/genkat_aead.py | 49 ++++++++ 25 files changed, 936 insertions(+), 920 deletions(-) delete mode 100644 python/.gitignore delete mode 100755 python/compare.sh delete mode 100644 python/crypto_aead.py delete mode 100755 python/generate-vectors.sh delete mode 100755 python/genkat_aead.py delete mode 100644 python/lilliput/__init__.py delete mode 100644 python/lilliput/constants.py delete mode 100644 python/lilliput/helpers.py delete mode 100644 python/lilliput/lilliput_ae_1.py delete mode 100644 python/lilliput/lilliput_ae_2.py delete mode 100644 python/lilliput/multiplications.py delete mode 100644 python/lilliput/tbc.py create mode 100644 src/add_python/lilliput/__init__.py create mode 100644 src/add_python/lilliput/constants.py create mode 100644 src/add_python/lilliput/helpers.py create mode 100644 src/add_python/lilliput/lilliput_ae_1.py create mode 100644 src/add_python/lilliput/lilliput_ae_2.py create mode 100644 src/add_python/lilliput/multiplications.py create mode 100644 src/add_python/lilliput/tbc.py create mode 100755 test/python.sh create mode 100755 test/python/compare.sh create mode 100644 test/python/crypto_aead.py create mode 100755 test/python/generate-vectors.sh create mode 100755 test/python/genkat_aead.py (limited to 'python/genkat_aead.py') diff --git a/.gitignore b/.gitignore index 7477fbe..bf4a44b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ crypto_aead results +__pycache__ *.tgz diff --git a/python/.gitignore b/python/.gitignore deleted file mode 100644 index d9aa5d4..0000000 --- a/python/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -__pycache__ -results \ No newline at end of file diff --git a/python/compare.sh b/python/compare.sh deleted file mode 100755 index 41f27b6..0000000 --- a/python/compare.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# TODO: make sure reference crypto_aead exists -# TODO: cleanup previous vectors and run genkat_aead.py - -set -eux - -mkdir -p results/crypto_aead_ref -for d in ../../SOUMISSION_NIST/REFERENCE_IMPLEMENTATION/crypto_aead/lilliputaei* -do - mkdir -p results/crypto_aead_ref/$(basename $d) - cp $d/LWC*.txt results/crypto_aead_ref/$(basename $d)/ -done - -diff -ru results/crypto_aead_ref results/crypto_aead diff --git a/python/crypto_aead.py b/python/crypto_aead.py deleted file mode 100644 index 792369c..0000000 --- a/python/crypto_aead.py +++ /dev/null @@ -1,18 +0,0 @@ -import lilliput -from lilliput.constants import NONCE_BYTES as NPUBBYTES, TAG_BYTES - -# Import KEYBYTES to expose it to genkat_aead. -# Import MODE to provide it to lilliput. -from parameters import KEYBYTES, MODE - - -def encrypt(m, ad, npub, k): - c, tag = lilliput.encrypt(m, ad, k, npub, MODE) - return c+tag - - -def decrypt(c, ad, npub, k): - clen = len(c)-TAG_BYTES - ctext = c[:clen] - tag = c[clen:] - return lilliput.decrypt(ctext, tag, ad, k, npub, MODE) diff --git a/python/generate-vectors.sh b/python/generate-vectors.sh deleted file mode 100755 index 90b5840..0000000 --- a/python/generate-vectors.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -eu - -rm -rf results - -mkdir -p results/crypto_aead/lilliputae{i,ii}{128,192,256}v1 - -declare -A names=([1]=lilliputaei [2]=lilliputaeii) - -for mode in 1 2 -do - for keylen in 128 192 256 - do - echo generating for ${mode} ${keylen} - - cat < results/parameters.py -MODE = ${mode} -KEYBYTES = $((keylen/8)) -EOF - - PYTHONPATH=results ./genkat_aead.py - - dest=results/crypto_aead/${names[${mode}]}${keylen}v1 - mv LWC_AEAD_KAT_${keylen}_120.txt ${dest} - done -done diff --git a/python/genkat_aead.py b/python/genkat_aead.py deleted file mode 100755 index 01bed6f..0000000 --- a/python/genkat_aead.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -import crypto_aead - - -MAX_MESSAGE_LENGTH = 32 -MAX_ADATA_LENGTH = 32 - - -def print_bstr(output, label, buf): - print('{l} = {b}'.format(l=label, b=buf.hex().upper()), file=output) - - -def generate_test_vectors(): - output_path = 'LWC_AEAD_KAT_{key}_{npub}.txt'.format( - key=crypto_aead.KEYBYTES*8, npub=crypto_aead.NPUBBYTES*8 - ) - - npub = bytes(range(crypto_aead.NPUBBYTES)) - key = bytes(range(crypto_aead.KEYBYTES)) - - with open(output_path, 'w') as output: - - count = 1 - for mlen in range(MAX_MESSAGE_LENGTH+1): - for adlen in range(MAX_ADATA_LENGTH+1): - print('Count = {c}'.format(c=count), file=output) - - msg = bytes(range(mlen)) - ad = bytes(range(adlen)) - - print_bstr(output, 'Key', key) - print_bstr(output, 'Nonce', npub) - print_bstr(output, 'PT', msg) - print_bstr(output, 'AD', ad) - - ct = crypto_aead.encrypt(msg, ad, npub, key) - - print_bstr(output, 'CT', ct) - - crypto_aead.decrypt(ct, ad, npub, key) - - count += 1 - - print(file=output) - - -if __name__ == '__main__': - generate_test_vectors() diff --git a/python/lilliput/__init__.py b/python/lilliput/__init__.py deleted file mode 100644 index 5fbc0de..0000000 --- a/python/lilliput/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -from . import lilliput_ae_1 -from . import lilliput_ae_2 -from .constants import NONCE_BYTES - - -_AE_MODES = { - 1: lilliput_ae_1, - 2: lilliput_ae_2 -} - - -def _check_inputs(key, mode, nonce): - valid_key_lengths = (128, 192, 256) - if len(key)*8 not in valid_key_lengths: - raise ValueError('invalid key size: {} not in {}'.format(len(key)*8, valid_key_lengths)) - - if mode not in _AE_MODES: - raise ValueError('invalid mode: {} not in {}'.format(mode, tuple(_AE_MODES))) - - if len(nonce) != NONCE_BYTES: - raise ValueError('invalid nonce size: expecting {}, have {}'.format(NONCE_BYTES, len(nonce))) - - -def encrypt(plaintext, adata, key, nonce, mode): - _check_inputs(key, mode, nonce) - return _AE_MODES[mode].encrypt(adata, plaintext, nonce, key) - - -def decrypt(ciphertext, tag, adata, key, nonce, mode): - _check_inputs(key, mode, nonce) - return _AE_MODES[mode].decrypt(adata, ciphertext, nonce, tag, key) diff --git a/python/lilliput/constants.py b/python/lilliput/constants.py deleted file mode 100644 index 0c9b89f..0000000 --- a/python/lilliput/constants.py +++ /dev/null @@ -1,40 +0,0 @@ -BLOCK_BITS = 128 -BLOCK_BYTES = BLOCK_BITS//8 -NONCE_BYTES = 15 -TAG_BYTES = 16 - - -Sbox = [ - 0x20, 0x00, 0xb2, 0x85, 0x3b, 0x35, 0xa6, 0xa4, - 0x30, 0xe4, 0x6a, 0x2c, 0xff, 0x59, 0xe2, 0x0e, - 0xf8, 0x1e, 0x7a, 0x80, 0x15, 0xbd, 0x3e, 0xb1, - 0xe8, 0xf3, 0xa2, 0xc2, 0xda, 0x51, 0x2a, 0x10, - 0x21, 0x01, 0x23, 0x78, 0x5c, 0x24, 0x27, 0xb5, - 0x37, 0xc7, 0x2b, 0x1f, 0xae, 0x0a, 0x77, 0x5f, - 0x6f, 0x09, 0x9d, 0x81, 0x04, 0x5a, 0x29, 0xdc, - 0x39, 0x9c, 0x05, 0x57, 0x97, 0x74, 0x79, 0x17, - 0x44, 0xc6, 0xe6, 0xe9, 0xdd, 0x41, 0xf2, 0x8a, - 0x54, 0xca, 0x6e, 0x4a, 0xe1, 0xad, 0xb6, 0x88, - 0x1c, 0x98, 0x7e, 0xce, 0x63, 0x49, 0x3a, 0x5d, - 0x0c, 0xef, 0xf6, 0x34, 0x56, 0x25, 0x2e, 0xd6, - 0x67, 0x75, 0x55, 0x76, 0xb8, 0xd2, 0x61, 0xd9, - 0x71, 0x8b, 0xcd, 0x0b, 0x72, 0x6c, 0x31, 0x4b, - 0x69, 0xfd, 0x7b, 0x6d, 0x60, 0x3c, 0x2f, 0x62, - 0x3f, 0x22, 0x73, 0x13, 0xc9, 0x82, 0x7f, 0x53, - 0x32, 0x12, 0xa0, 0x7c, 0x02, 0x87, 0x84, 0x86, - 0x93, 0x4e, 0x68, 0x46, 0x8d, 0xc3, 0xdb, 0xec, - 0x9b, 0xb7, 0x89, 0x92, 0xa7, 0xbe, 0x3d, 0xd8, - 0xea, 0x50, 0x91, 0xf1, 0x33, 0x38, 0xe0, 0xa9, - 0xa3, 0x83, 0xa1, 0x1b, 0xcf, 0x06, 0x95, 0x07, - 0x9e, 0xed, 0xb9, 0xf5, 0x4c, 0xc0, 0xf4, 0x2d, - 0x16, 0xfa, 0xb4, 0x03, 0x26, 0xb3, 0x90, 0x4f, - 0xab, 0x65, 0xfc, 0xfe, 0x14, 0xf7, 0xe3, 0x94, - 0xee, 0xac, 0x8c, 0x1a, 0xde, 0xcb, 0x28, 0x40, - 0x7d, 0xc8, 0xc4, 0x48, 0x6b, 0xdf, 0xa5, 0x52, - 0xe5, 0xfb, 0xd7, 0x64, 0xf9, 0xf0, 0xd3, 0x5e, - 0x66, 0x96, 0x8f, 0x1d, 0x45, 0x36, 0xcc, 0xc5, - 0x4d, 0x9f, 0xbf, 0x0f, 0xd1, 0x08, 0xeb, 0x43, - 0x42, 0x19, 0xe7, 0x99, 0xa8, 0x8e, 0x58, 0xc1, - 0x9a, 0xd4, 0x18, 0x47, 0xaa, 0xaf, 0xbc, 0x5b, - 0xd5, 0x11, 0xd0, 0xb0, 0x70, 0xbb, 0x0d, 0xba -] diff --git a/python/lilliput/helpers.py b/python/lilliput/helpers.py deleted file mode 100644 index 8677f06..0000000 --- a/python/lilliput/helpers.py +++ /dev/null @@ -1,92 +0,0 @@ -from .constants import BLOCK_BITS, BLOCK_BYTES -from . import tbc - - -def ArrayToBlockbytesMatrix(array): - vector = list(array) - - blocks_nb = len(vector)//BLOCK_BYTES - - block_starts = ( - i*BLOCK_BYTES for i in range(blocks_nb) - ) - - matrix = [ - vector[start:start+BLOCK_BYTES] for start in block_starts - ] - - padding_len = len(vector)%BLOCK_BYTES - - if padding_len > 0: - padding = vector[-padding_len:] - matrix.append(padding) - - return matrix - - -def BlockbytesMatrixToBytes(matrix): - return bytes(byte for block in matrix for byte in block) - - -def XorState(state1, state2): - return [s1^s2 for (s1, s2) in zip(state1, state2)] - - -def Padding10LSB(X): - zeroes = [0] * (BLOCK_BYTES-len(X)-1) - return zeroes + [0b10000000] + X - - -def _tweakAssociatedData(t, i, padded): - t_bytes = t//8 - tweak = [0]*(t_bytes) - - mask = 0xff - for byte in range(t_bytes-1): - tweak[byte] = (i & mask) >> (byte * 8) - mask = mask << 8 - - mask = (0xf << (8 * t_bytes-1)) - tweak[-1] = (i & mask) >> ((t_bytes-1)*8) - if not padded: - tweak[-1] |= 0x20 - else: - tweak[-1] |= 0x60 - - return tweak - - -def BuildAuth(t, A, key): - Auth = [0 for byte in range(0, BLOCK_BYTES)] - l_a = len(A)//BLOCK_BYTES - need_padding = len(A)%BLOCK_BYTES > 0 - - A = ArrayToBlockbytesMatrix(A) - - for i in range(0, l_a): - tweak = _tweakAssociatedData(t, i, padded=False) - enc = tbc.encrypt(tweak, key, A[i]) - Auth = XorState(Auth, enc) - - if not need_padding: - return Auth - - tweak = _tweakAssociatedData(t, l_a, padded=True) - ad_padded = Padding10LSB(A[l_a]) - enc = tbc.encrypt(tweak, key, ad_padded) - Auth = XorState(Auth, enc) - - return Auth - - -class TagValidationError(Exception): - def __init__(self, announced, computed): - msg = '\n'.join(( - 'Invalid tag:', - announced.hex().upper()+' (announced)', - computed.hex().upper()+' (computed)' - )) - - super().__init__(msg) - self._announced = announced - self._computed = computed diff --git a/python/lilliput/lilliput_ae_1.py b/python/lilliput/lilliput_ae_1.py deleted file mode 100644 index 0da2a95..0000000 --- a/python/lilliput/lilliput_ae_1.py +++ /dev/null @@ -1,155 +0,0 @@ -""" - OCB 3 for lilliput ae i -""" - -from enum import Enum - -from .constants import BLOCK_BYTES, NONCE_BYTES -from .helpers import ( - ArrayToBlockbytesMatrix, - BlockbytesMatrixToBytes, - BuildAuth, - Padding10LSB, - TagValidationError, - XorState -) -from . import tbc - - -TWEAK_BITS = 192 -TWEAK_BYTES = TWEAK_BITS//8 - - -def LowPart(array, number_bits): - shifted = 0 - for byte in range(0, len(array)): - shifted |= (array[byte] << (8 * byte)) - - mask = 0 - for bit in range(0, number_bits): - mask |= (0x1 << bit) - - lower_part = shifted & mask - - will_pad = 0 - if number_bits % 8 != 0: - will_pad = 1 - - lower_part_byte = [] - nb_bytes = number_bits//8 + will_pad - for byte in range(nb_bytes): - lower_part_byte.append(lower_part & 0xff) - lower_part = lower_part >> 8 - - return lower_part_byte - - -class _MessageTweak(Enum): - BLOCK = 0b000 - NO_PADDING = 0b0001 - PAD = 0b0100 - FINAL = 0b0101 - - -def TweakMessage(N, j, padding): - tweak = [0 for byte in range(0, TWEAK_BYTES)] - for byte in range(NONCE_BYTES-1, -1, -1): - tweak[byte + (TWEAK_BYTES-NONCE_BYTES)] |= (N[byte] & 0xf0) >> 4 - tweak[byte + (TWEAK_BYTES-NONCE_BYTES-1)] |= (N[byte] & 0x0f) << 4 - - tweak[TWEAK_BYTES-NONCE_BYTES-1] |= ((j >> 64) & 0xf) - for byte in range(TWEAK_BYTES-NONCE_BYTES-2, -1, -1): - tweak[byte] = (j >> (8 * byte)) & 0xff - - tweak[-1] |= padding.value<<4 - - return tweak - - -def TreatMessageEnc(M, N, key): - checksum = [0 for byte in range(0, BLOCK_BYTES)] - - l = len(M)//BLOCK_BYTES - padding_bytes = len(M)%BLOCK_BYTES - - M = ArrayToBlockbytesMatrix(M) - C = [] - - for j in range(0, l): - checksum = XorState(checksum, M[j]) - tweak = TweakMessage(N, j, _MessageTweak.BLOCK) - C.append(tbc.encrypt(tweak, key, M[j])) - - if padding_bytes == 0: - tweak = TweakMessage(N, l, _MessageTweak.NO_PADDING) - Final = tbc.encrypt(tweak, key, checksum) - - else: - m_padded = Padding10LSB(M[l]) - checksum = XorState(checksum, m_padded) - tweak = TweakMessage(N, l, _MessageTweak.PAD) - pad = tbc.encrypt(tweak, key, [0 for byte in range(0, BLOCK_BYTES)]) - - lower_part = LowPart(pad, padding_bytes*8) - C.append(XorState(M[l], lower_part)) - tweak_final = TweakMessage(N, l+1, _MessageTweak.FINAL) - Final = tbc.encrypt(tweak_final, key, checksum) - - return (Final, C) - - -def TreatMessageDec(C, N, key): - checksum = [0 for byte in range(0, BLOCK_BYTES)] - - l = len(C)//BLOCK_BYTES - padding_bytes = len(C)%BLOCK_BYTES - - C = ArrayToBlockbytesMatrix(C) - M = [] - - for j in range(0, l): - tweak = TweakMessage(N, j, _MessageTweak.BLOCK) - M.append(tbc.decrypt(tweak, key, C[j])) - checksum = XorState(checksum, M[j]) - - if padding_bytes == 0: - tweak = TweakMessage(N, l, _MessageTweak.NO_PADDING) - Final = tbc.encrypt(tweak, key, checksum) - - else: - tweak = TweakMessage(N, l, _MessageTweak.PAD) - pad = tbc.encrypt(tweak, key, [0 for byte in range(0, BLOCK_BYTES)]) - lower_part = LowPart(pad, padding_bytes*8) - M.append(XorState(C[l], lower_part)) - - m_padded = Padding10LSB(M[l]) - checksum = XorState(checksum, m_padded) - tweak_final = TweakMessage(N, l+1, _MessageTweak.FINAL) - Final = tbc.encrypt(tweak_final, key, checksum) - - return (Final, M) - - -################################################################################ -def encrypt(A, M, N, key): - K = list(key) - - Auth = BuildAuth(TWEAK_BITS, A, K) - (Final, C) = TreatMessageEnc(M, N, K) - tag = XorState(Auth, Final) - - return BlockbytesMatrixToBytes(C), bytes(tag) - - -def decrypt(A, C, N, tag, key): - K = list(key) - tag = list(tag) - - Auth = BuildAuth(TWEAK_BITS, A, K) - (Final, M) = TreatMessageDec(C, N, K) - tag2 = XorState(Auth, Final) - - if tag != tag2: - raise TagValidationError(tag, tag2) - - return BlockbytesMatrixToBytes(M) diff --git a/python/lilliput/lilliput_ae_2.py b/python/lilliput/lilliput_ae_2.py deleted file mode 100644 index 61aa86e..0000000 --- a/python/lilliput/lilliput_ae_2.py +++ /dev/null @@ -1,127 +0,0 @@ -""" - SCT 2 for lilliput ae 2 -""" - -from .constants import BLOCK_BYTES -from .helpers import ( - ArrayToBlockbytesMatrix, - BlockbytesMatrixToBytes, - BuildAuth, - Padding10LSB, - TagValidationError, - XorState -) -from . import tbc - - -TWEAK_BITS = 128 -TWEAK_BYTES = TWEAK_BITS//8 - - -def TweakTag(j, padded): - tweak = [0 for byte in range(0, TWEAK_BYTES)] - - tweak[TWEAK_BYTES - 1] |= ((j >> 120) & 0xf) - for byte in range(TWEAK_BYTES - 2, -1, -1): - tweak[byte] = (j >> (8 * byte)) & 0xff - - if padded: - tweak[TWEAK_BYTES - 1] |= 0x40 - - return tweak - - -def TweakTagEnd(N): - tweak = [0 for byte in range(0, TWEAK_BYTES)] - - for byte in range(0, TWEAK_BYTES - 1): - tweak[byte] = N[byte] - tweak[TWEAK_BYTES - 1] = 0x10 - - return tweak - - -def AddTagJ(tag, j): - array_j = [0 for byte in range(0, TWEAK_BYTES)] - for byte in range(0, TWEAK_BYTES): - array_j[byte] = (j >> (byte * 8)) - - xorr = XorState(tag, array_j) - - xorr[TWEAK_BYTES - 1] |= 0x80 - - return xorr - - -def MesssageAuthTag(M, N, Auth, key): - l = len(M)//BLOCK_BYTES - need_padding = len(M)%BLOCK_BYTES > 0 - - tag = list(Auth) - M = ArrayToBlockbytesMatrix(M) - - for j in range(0, l): - tweak = TweakTag(j, False) - encryption = tbc.encrypt(tweak, key, M[j]) - tag = XorState(tag, encryption) - - if need_padding: - tweak = TweakTag(l, True) - m_padded = Padding10LSB(M[l]) - encryption = tbc.encrypt(tweak, key, m_padded) - tag = XorState(tag, encryption) - - tweak = TweakTagEnd(N) - encryption = tbc.encrypt(tweak, key, tag) - tag = encryption - - return tag - - -def MessageEncryption(M, N, tag, key): - l = len(M)//BLOCK_BYTES - need_padding = len(M)%BLOCK_BYTES > 0 - - M = ArrayToBlockbytesMatrix(M) - C = [] - - for j in range(0, l): - tweak = AddTagJ(tag, j) - padded_nonce = list(N) + [0x00] - encryption = tbc.encrypt(tweak, key, padded_nonce) - C.append(XorState(M[j], encryption)) - - if need_padding: - tweak = AddTagJ(tag, l) - padded_nonce = list(N) + [0x00] - encryption = tbc.encrypt(tweak, key, padded_nonce) - C.append(XorState(M[l], encryption)) - - return C - - -################################################################################ -def encrypt(A, M, N, key): - K = list(key) - - Auth = BuildAuth(TWEAK_BITS, A, K) - tag = MesssageAuthTag(M, N, Auth, K) - C = MessageEncryption(M, N, tag, K) - - return BlockbytesMatrixToBytes(C), bytes(tag) - - -def decrypt(A, C, N, tag, key): - K = list(key) - tag = list(tag) - - M = BlockbytesMatrixToBytes( - MessageEncryption(C, N, tag, K) - ) - Auth = BuildAuth(TWEAK_BITS, A, K) - tag2 = MesssageAuthTag(M, N, Auth, K) - - if tag != tag2: - raise TagValidationError(tag, tag2) - - return M diff --git a/python/lilliput/multiplications.py b/python/lilliput/multiplications.py deleted file mode 100644 index c5f1e44..0000000 --- a/python/lilliput/multiplications.py +++ /dev/null @@ -1,186 +0,0 @@ - -# Multiply by matrix M -def _multiplyM(lane): - multiplied_lane = [lane[(byte-1) % 8] for byte in range(0, 8)] - - multiplied_lane[2] ^= ((lane[6] << 2) & 0xff) - multiplied_lane[4] ^= ((lane[4] >> 3) & 0xff) - multiplied_lane[5] ^= ((lane[5] << 3) & 0xff) - - return multiplied_lane - -def _multiplyM2(lane): - multiplied_lane = [lane[(byte-2) % 8] for byte in range(0, 8)] - - multiplied_lane[2] ^= ((lane[5] << 2) & 0xff) - multiplied_lane[3] ^= ((lane[6] << 2) & 0xff) - multiplied_lane[4] ^= ((lane[3] >> 3) & 0xff) ^ ((lane[4] >> 6) & 0xff) - multiplied_lane[5] ^= ((lane[5] << 6) & 0xff) - multiplied_lane[6] ^= ((lane[5] << 3) & 0xff) - - # binary matrix M1 - multi_mat_l4_m1 = 0 - l4 = lane[4] - multi_mat_l4_m1 ^= ((l4 & 0x8) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x10) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x20) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x40) >> 3) ^ ((l4 & 0x1) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x80) >> 3) ^ ((l4 & 0x2) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x04) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x08) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x10) << 3) - - multiplied_lane[5] ^= multi_mat_l4_m1 - - return multiplied_lane - - -def _multiplyM3(lane): - multiplied_lane = [lane[(byte-3) % 8] for byte in range(0, 8)] - - multiplied_lane[2] ^= ((lane[4] << 2) & 0xff) ^ ((lane[5] << 5) & 0xff) - multiplied_lane[3] ^= ((lane[5] << 2) & 0xff) - multiplied_lane[4] ^= ((lane[2] >> 3) & 0xff) ^ ((lane[3] >> 6) & 0xff) ^ ((lane[6] << 2) & 0xff) - multiplied_lane[6] ^= ((lane[5] << 6) & 0xff) - multiplied_lane[7] ^= ((lane[5] << 3) & 0xff) - - # binary matrix M1 - multi_mat_l3_m1 = 0 - l3 = lane[3] - multi_mat_l3_m1 ^= ((l3 & 0x8) >> 3) - multi_mat_l3_m1 ^= ((l3 & 0x10) >> 3) - multi_mat_l3_m1 ^= ((l3 & 0x20) >> 3) - multi_mat_l3_m1 ^= ((l3 & 0x40) >> 3) ^ ((l3 & 0x1) << 3) - multi_mat_l3_m1 ^= ((l3 & 0x80) >> 3) ^ ((l3 & 0x2) << 3) - multi_mat_l3_m1 ^= ((l3 & 0x04) << 3) - multi_mat_l3_m1 ^= ((l3 & 0x08) << 3) - multi_mat_l3_m1 ^= ((l3 & 0x10) << 3) - - # binary matrix M1 - multi_mat_l4_m1 = 0 - l4 = lane[4] - multi_mat_l4_m1 ^= ((l4 & 0x8) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x10) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x20) >> 3) - multi_mat_l4_m1 ^= ((l4 & 0x40) >> 3) ^ ((l4 & 0x1) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x80) >> 3) ^ ((l4 & 0x2) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x04) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x08) << 3) - multi_mat_l4_m1 ^= ((l4 & 0x10) << 3) - - # binary matrix M2 - multi_mat_l4_m2 = 0 - l4 = lane[4] - multi_mat_l4_m2 ^= ((l4 & 0x40) >> 6) - multi_mat_l4_m2 ^= ((l4 & 0x80) >> 6) - multi_mat_l4_m2 ^= (l4 & 0x08) - multi_mat_l4_m2 ^= (l4 & 0x10) - multi_mat_l4_m2 ^= (l4 & 0x20) - multi_mat_l4_m2 ^= (l4 & 0x40) ^ ((l4 & 0x1) << 6) - multi_mat_l4_m2 ^= (l4 & 0x80) ^ ((l4 & 0x2) << 6) - - - multiplied_lane[5] ^= multi_mat_l3_m1 ^ multi_mat_l4_m2 - multiplied_lane[6] ^= multi_mat_l4_m1 - - return multiplied_lane - - -def _multiplyMR(lane): - multiplied_lane = [lane[(byte+1) % 8] for byte in range(0, 8)] - - multiplied_lane[2] ^= ((lane[4] >> 3) & 0xff) - multiplied_lane[4] ^= ((lane[6] << 3) & 0xff) - multiplied_lane[5] ^= ((lane[3] << 2) & 0xff) - - return multiplied_lane - - -def _multiplyMR2(lane): - multiplied_lane = [lane[(byte+2) % 8] for byte in range(0, 8)] - - multiplied_lane[1] ^= ((lane[4] >> 3) & 0xff) - multiplied_lane[2] ^= ((lane[5] >> 3) & 0xff) - multiplied_lane[3] ^= ((lane[6] << 3) & 0xff) - multiplied_lane[4] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) - multiplied_lane[5] ^= ((lane[4] << 2) & 0xff) - - - # binary matrix m3 - multi_mat_l6_m3 = 0 - l6 = lane[6] - multi_mat_l6_m3 ^= (l6 & 0x1) - multi_mat_l6_m3 ^= (l6 & 0x2) - multi_mat_l6_m3 ^= (l6 & 0x4) - multi_mat_l6_m3 ^= (l6 & 0x8) - multi_mat_l6_m3 ^= (l6 & 0x10) - - - multiplied_lane[2] ^= multi_mat_l6_m3 - - return multiplied_lane - -def _multiplyMR3(lane): - multiplied_lane = [lane[(byte+3) % 8] for byte in range(0, 8)] - - multiplied_lane[0] ^= ((lane[4] >> 3) & 0xff) - multiplied_lane[1] ^= ((lane[5] >> 3) & 0xff) - multiplied_lane[3] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) - multiplied_lane[4] ^= ((lane[0] << 3) & 0xff) ^ ((lane[4] << 2) & 0xff) - multiplied_lane[5] ^= ((lane[5] << 2) & 0xff) ^ ((lane[6] << 5) & 0xff) - - # binary matrix m3 - multi_mat_l6_m3 = 0 - l6 = lane[6] - multi_mat_l6_m3 ^= (l6 & 0x1) - multi_mat_l6_m3 ^= (l6 & 0x2) - multi_mat_l6_m3 ^= (l6 & 0x4) - multi_mat_l6_m3 ^= (l6 & 0x8) - multi_mat_l6_m3 ^= (l6 & 0x10) - - # binary matrix m3 - multi_mat_l7_m3 = 0 - l7 = lane[7] - multi_mat_l7_m3 ^= (l7 & 0x1) - multi_mat_l7_m3 ^= (l7 & 0x2) - multi_mat_l7_m3 ^= (l7 & 0x4) - multi_mat_l7_m3 ^= (l7 & 0x8) - multi_mat_l7_m3 ^= (l7 & 0x10) - - # binary matrix m4 - multi_mat_l3_m4 = 0 - l3 = lane[3] - multi_mat_l3_m4 ^= ((l3 & 0x2) >> 1) - multi_mat_l3_m4 ^= ((l3 & 0x4) >> 1) - multi_mat_l3_m4 ^= ((l3 & 0x8) >> 1) - multi_mat_l3_m4 ^= ((l3 & 0x10) >> 1) - multi_mat_l3_m4 ^= ((l3 & 0x20) >> 1) - - # binary matrix m1 for MR - multi_mat_l6_m1 = 0 - l6 = lane[6] - multi_mat_l6_m1 ^= ((l6 & 0x8) >> 3) - multi_mat_l6_m1 ^= ((l6 & 0x10) >> 3) - multi_mat_l6_m1 ^= ((l6 & 0x20) >> 3) - multi_mat_l6_m1 ^= ((l6 & 0x40) >> 3) ^ ((l6 & 0x1) << 3) - multi_mat_l6_m1 ^= ((l6 & 0x80) >> 3) ^ ((l6 & 0x2) << 3) - multi_mat_l6_m1 ^= ((l6 & 0x4) << 3) - multi_mat_l6_m1 ^= ((l6 & 0x8) << 3) - multi_mat_l6_m1 ^= ((l6 & 0x10) << 3) - - - multiplied_lane[1] ^= multi_mat_l6_m3 - multiplied_lane[2] ^= multi_mat_l3_m4 ^ multi_mat_l6_m1 ^ multi_mat_l7_m3 - - return multiplied_lane - - -ALPHAS = ( - list, # Identity. - _multiplyM, - _multiplyM2, - _multiplyM3, - _multiplyMR, - _multiplyMR2, - _multiplyMR3 -) diff --git a/python/lilliput/tbc.py b/python/lilliput/tbc.py deleted file mode 100644 index 5291994..0000000 --- a/python/lilliput/tbc.py +++ /dev/null @@ -1,178 +0,0 @@ -""" - Lilliput TBC -""" -from .constants import BLOCK_BYTES, Sbox -from .multiplications import ALPHAS - - -permutation = [14, 11, 12, 10, 8, 9, 13, 15, 3, 1, 4, 5, 6, 0, 2, 7] -permutationInv = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7] - -################################################################################ - -def BuildTweakey(tweak, key): - return tweak+key - -############################# - -def _lane(TK, j): - return TK[j*8:(j+1)*8] - -def RoundTweakeySchedule(tweakey): - p = len(tweakey)//8 - - multiplied_lanes = ( - ALPHAS[j](_lane(tweakey, j)) for j in range(p) - ) - - return [byte for lane in multiplied_lanes for byte in lane] - - -def SubTweakeyExtract(tweakey, Ci): - RTKi = [0]*8 - - for j, byte in enumerate(tweakey): - RTKi[j%8] ^= byte - - RTKi[0] ^= Ci - - return RTKi - - -def TweakeyScheduleWhole(tweakey, r): - # store main tweakey in TKs[0] - # and corresponding round tweakey in RTKs[0] - TKs = [tweakey] - RTKs = [SubTweakeyExtract(TKs[0], 0)] - - for i in range(1, r): - TKs.append(RoundTweakeySchedule(TKs[i-1])) - RTKs.append(SubTweakeyExtract(TKs[i], i)) - - return RTKs - - -################################################################################ - -def NonLinearLayer(state, subtweakey): - - variables_xored = [0 for byte in range(0, 8)] - for byte in range(0,8): - variables_xored[byte] = state[byte] ^ subtweakey[byte] - - variables_sboxed = [0 for byte in range(0, 8)] - for byte in range(0, 8): - variables_sboxed[byte] = Sbox[variables_xored[byte]] - - state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0,BLOCK_BYTES): - state_output[byte] = state[byte] - for byte in range(0, 8): - state_output[15 - byte] ^= variables_sboxed[byte] - - return state_output - - -def LinearLayer(state): - state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES): - state_output[byte] = state[byte] - - for byte in range(1, 8): - state_output[15] ^= state[byte] - - for byte in range(9, 15): - state_output[byte] ^= state[7] - - return state_output - - -def PermutationLayerEnc(state): - state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES): - state_output[byte] = state[permutation[byte]] - - return state_output - -def PermutationLayerDec(state): - state_output = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES): - state_output[byte] = state[permutationInv[byte]] - - return state_output - - -def OneRoundEGFNEnc(state, subtweakey): - state_non_linear = NonLinearLayer(state, subtweakey) - state_linear = LinearLayer(state_non_linear) - state_permutation = PermutationLayerEnc(state_linear) - - return state_permutation - -def LastRoundEGFN(state, subtweakey): - state_non_linear = NonLinearLayer(state, subtweakey) - state_linear = LinearLayer(state_non_linear) - - return state_linear - - -def OneRoundEGFNDec(state, subtweakey): - state_non_linear = NonLinearLayer(state, subtweakey) - state_linear = LinearLayer(state_non_linear) - state_permutation = PermutationLayerDec(state_linear) - - return state_permutation - - -def _rounds(key_bytes): - rounds = { - 128: 32, - 192: 36, - 256: 42 - } - return rounds[key_bytes*8] - - -################################################################################ -# Lilliput TBC - -def encrypt(tweak, key, message): - r = _rounds(len(key)) - - tweakey = BuildTweakey(tweak, key) - RTKs = TweakeyScheduleWhole(tweakey, r) - - state = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES): - state[byte] = message[byte] - - for i in range(0, r-1): - state_output = OneRoundEGFNEnc(state, RTKs[i]) - - for byte in range(0, BLOCK_BYTES): - state[byte] = state_output[byte] - - state_output = LastRoundEGFN(state, RTKs[r-1]) - - return state_output - - -def decrypt(tweak, key, cipher): - r = _rounds(len(key)) - - tweakey = BuildTweakey(tweak, key) - RTKs = TweakeyScheduleWhole(tweakey, r) - - state = [0 for byte in range(0, BLOCK_BYTES)] - for byte in range(0, BLOCK_BYTES): - state[byte] = cipher[byte] - - for i in range(0, r-1): - state_output = OneRoundEGFNDec(state, RTKs[r-i-1]) - - for byte in range(0, BLOCK_BYTES): - state[byte] = state_output[byte] - - state_output = LastRoundEGFN(state, RTKs[0]) - - return state_output diff --git a/src/add_python/lilliput/__init__.py b/src/add_python/lilliput/__init__.py new file mode 100644 index 0000000..5fbc0de --- /dev/null +++ b/src/add_python/lilliput/__init__.py @@ -0,0 +1,31 @@ +from . import lilliput_ae_1 +from . import lilliput_ae_2 +from .constants import NONCE_BYTES + + +_AE_MODES = { + 1: lilliput_ae_1, + 2: lilliput_ae_2 +} + + +def _check_inputs(key, mode, nonce): + valid_key_lengths = (128, 192, 256) + if len(key)*8 not in valid_key_lengths: + raise ValueError('invalid key size: {} not in {}'.format(len(key)*8, valid_key_lengths)) + + if mode not in _AE_MODES: + raise ValueError('invalid mode: {} not in {}'.format(mode, tuple(_AE_MODES))) + + if len(nonce) != NONCE_BYTES: + raise ValueError('invalid nonce size: expecting {}, have {}'.format(NONCE_BYTES, len(nonce))) + + +def encrypt(plaintext, adata, key, nonce, mode): + _check_inputs(key, mode, nonce) + return _AE_MODES[mode].encrypt(adata, plaintext, nonce, key) + + +def decrypt(ciphertext, tag, adata, key, nonce, mode): + _check_inputs(key, mode, nonce) + return _AE_MODES[mode].decrypt(adata, ciphertext, nonce, tag, key) diff --git a/src/add_python/lilliput/constants.py b/src/add_python/lilliput/constants.py new file mode 100644 index 0000000..0c9b89f --- /dev/null +++ b/src/add_python/lilliput/constants.py @@ -0,0 +1,40 @@ +BLOCK_BITS = 128 +BLOCK_BYTES = BLOCK_BITS//8 +NONCE_BYTES = 15 +TAG_BYTES = 16 + + +Sbox = [ + 0x20, 0x00, 0xb2, 0x85, 0x3b, 0x35, 0xa6, 0xa4, + 0x30, 0xe4, 0x6a, 0x2c, 0xff, 0x59, 0xe2, 0x0e, + 0xf8, 0x1e, 0x7a, 0x80, 0x15, 0xbd, 0x3e, 0xb1, + 0xe8, 0xf3, 0xa2, 0xc2, 0xda, 0x51, 0x2a, 0x10, + 0x21, 0x01, 0x23, 0x78, 0x5c, 0x24, 0x27, 0xb5, + 0x37, 0xc7, 0x2b, 0x1f, 0xae, 0x0a, 0x77, 0x5f, + 0x6f, 0x09, 0x9d, 0x81, 0x04, 0x5a, 0x29, 0xdc, + 0x39, 0x9c, 0x05, 0x57, 0x97, 0x74, 0x79, 0x17, + 0x44, 0xc6, 0xe6, 0xe9, 0xdd, 0x41, 0xf2, 0x8a, + 0x54, 0xca, 0x6e, 0x4a, 0xe1, 0xad, 0xb6, 0x88, + 0x1c, 0x98, 0x7e, 0xce, 0x63, 0x49, 0x3a, 0x5d, + 0x0c, 0xef, 0xf6, 0x34, 0x56, 0x25, 0x2e, 0xd6, + 0x67, 0x75, 0x55, 0x76, 0xb8, 0xd2, 0x61, 0xd9, + 0x71, 0x8b, 0xcd, 0x0b, 0x72, 0x6c, 0x31, 0x4b, + 0x69, 0xfd, 0x7b, 0x6d, 0x60, 0x3c, 0x2f, 0x62, + 0x3f, 0x22, 0x73, 0x13, 0xc9, 0x82, 0x7f, 0x53, + 0x32, 0x12, 0xa0, 0x7c, 0x02, 0x87, 0x84, 0x86, + 0x93, 0x4e, 0x68, 0x46, 0x8d, 0xc3, 0xdb, 0xec, + 0x9b, 0xb7, 0x89, 0x92, 0xa7, 0xbe, 0x3d, 0xd8, + 0xea, 0x50, 0x91, 0xf1, 0x33, 0x38, 0xe0, 0xa9, + 0xa3, 0x83, 0xa1, 0x1b, 0xcf, 0x06, 0x95, 0x07, + 0x9e, 0xed, 0xb9, 0xf5, 0x4c, 0xc0, 0xf4, 0x2d, + 0x16, 0xfa, 0xb4, 0x03, 0x26, 0xb3, 0x90, 0x4f, + 0xab, 0x65, 0xfc, 0xfe, 0x14, 0xf7, 0xe3, 0x94, + 0xee, 0xac, 0x8c, 0x1a, 0xde, 0xcb, 0x28, 0x40, + 0x7d, 0xc8, 0xc4, 0x48, 0x6b, 0xdf, 0xa5, 0x52, + 0xe5, 0xfb, 0xd7, 0x64, 0xf9, 0xf0, 0xd3, 0x5e, + 0x66, 0x96, 0x8f, 0x1d, 0x45, 0x36, 0xcc, 0xc5, + 0x4d, 0x9f, 0xbf, 0x0f, 0xd1, 0x08, 0xeb, 0x43, + 0x42, 0x19, 0xe7, 0x99, 0xa8, 0x8e, 0x58, 0xc1, + 0x9a, 0xd4, 0x18, 0x47, 0xaa, 0xaf, 0xbc, 0x5b, + 0xd5, 0x11, 0xd0, 0xb0, 0x70, 0xbb, 0x0d, 0xba +] diff --git a/src/add_python/lilliput/helpers.py b/src/add_python/lilliput/helpers.py new file mode 100644 index 0000000..8677f06 --- /dev/null +++ b/src/add_python/lilliput/helpers.py @@ -0,0 +1,92 @@ +from .constants import BLOCK_BITS, BLOCK_BYTES +from . import tbc + + +def ArrayToBlockbytesMatrix(array): + vector = list(array) + + blocks_nb = len(vector)//BLOCK_BYTES + + block_starts = ( + i*BLOCK_BYTES for i in range(blocks_nb) + ) + + matrix = [ + vector[start:start+BLOCK_BYTES] for start in block_starts + ] + + padding_len = len(vector)%BLOCK_BYTES + + if padding_len > 0: + padding = vector[-padding_len:] + matrix.append(padding) + + return matrix + + +def BlockbytesMatrixToBytes(matrix): + return bytes(byte for block in matrix for byte in block) + + +def XorState(state1, state2): + return [s1^s2 for (s1, s2) in zip(state1, state2)] + + +def Padding10LSB(X): + zeroes = [0] * (BLOCK_BYTES-len(X)-1) + return zeroes + [0b10000000] + X + + +def _tweakAssociatedData(t, i, padded): + t_bytes = t//8 + tweak = [0]*(t_bytes) + + mask = 0xff + for byte in range(t_bytes-1): + tweak[byte] = (i & mask) >> (byte * 8) + mask = mask << 8 + + mask = (0xf << (8 * t_bytes-1)) + tweak[-1] = (i & mask) >> ((t_bytes-1)*8) + if not padded: + tweak[-1] |= 0x20 + else: + tweak[-1] |= 0x60 + + return tweak + + +def BuildAuth(t, A, key): + Auth = [0 for byte in range(0, BLOCK_BYTES)] + l_a = len(A)//BLOCK_BYTES + need_padding = len(A)%BLOCK_BYTES > 0 + + A = ArrayToBlockbytesMatrix(A) + + for i in range(0, l_a): + tweak = _tweakAssociatedData(t, i, padded=False) + enc = tbc.encrypt(tweak, key, A[i]) + Auth = XorState(Auth, enc) + + if not need_padding: + return Auth + + tweak = _tweakAssociatedData(t, l_a, padded=True) + ad_padded = Padding10LSB(A[l_a]) + enc = tbc.encrypt(tweak, key, ad_padded) + Auth = XorState(Auth, enc) + + return Auth + + +class TagValidationError(Exception): + def __init__(self, announced, computed): + msg = '\n'.join(( + 'Invalid tag:', + announced.hex().upper()+' (announced)', + computed.hex().upper()+' (computed)' + )) + + super().__init__(msg) + self._announced = announced + self._computed = computed diff --git a/src/add_python/lilliput/lilliput_ae_1.py b/src/add_python/lilliput/lilliput_ae_1.py new file mode 100644 index 0000000..0da2a95 --- /dev/null +++ b/src/add_python/lilliput/lilliput_ae_1.py @@ -0,0 +1,155 @@ +""" + OCB 3 for lilliput ae i +""" + +from enum import Enum + +from .constants import BLOCK_BYTES, NONCE_BYTES +from .helpers import ( + ArrayToBlockbytesMatrix, + BlockbytesMatrixToBytes, + BuildAuth, + Padding10LSB, + TagValidationError, + XorState +) +from . import tbc + + +TWEAK_BITS = 192 +TWEAK_BYTES = TWEAK_BITS//8 + + +def LowPart(array, number_bits): + shifted = 0 + for byte in range(0, len(array)): + shifted |= (array[byte] << (8 * byte)) + + mask = 0 + for bit in range(0, number_bits): + mask |= (0x1 << bit) + + lower_part = shifted & mask + + will_pad = 0 + if number_bits % 8 != 0: + will_pad = 1 + + lower_part_byte = [] + nb_bytes = number_bits//8 + will_pad + for byte in range(nb_bytes): + lower_part_byte.append(lower_part & 0xff) + lower_part = lower_part >> 8 + + return lower_part_byte + + +class _MessageTweak(Enum): + BLOCK = 0b000 + NO_PADDING = 0b0001 + PAD = 0b0100 + FINAL = 0b0101 + + +def TweakMessage(N, j, padding): + tweak = [0 for byte in range(0, TWEAK_BYTES)] + for byte in range(NONCE_BYTES-1, -1, -1): + tweak[byte + (TWEAK_BYTES-NONCE_BYTES)] |= (N[byte] & 0xf0) >> 4 + tweak[byte + (TWEAK_BYTES-NONCE_BYTES-1)] |= (N[byte] & 0x0f) << 4 + + tweak[TWEAK_BYTES-NONCE_BYTES-1] |= ((j >> 64) & 0xf) + for byte in range(TWEAK_BYTES-NONCE_BYTES-2, -1, -1): + tweak[byte] = (j >> (8 * byte)) & 0xff + + tweak[-1] |= padding.value<<4 + + return tweak + + +def TreatMessageEnc(M, N, key): + checksum = [0 for byte in range(0, BLOCK_BYTES)] + + l = len(M)//BLOCK_BYTES + padding_bytes = len(M)%BLOCK_BYTES + + M = ArrayToBlockbytesMatrix(M) + C = [] + + for j in range(0, l): + checksum = XorState(checksum, M[j]) + tweak = TweakMessage(N, j, _MessageTweak.BLOCK) + C.append(tbc.encrypt(tweak, key, M[j])) + + if padding_bytes == 0: + tweak = TweakMessage(N, l, _MessageTweak.NO_PADDING) + Final = tbc.encrypt(tweak, key, checksum) + + else: + m_padded = Padding10LSB(M[l]) + checksum = XorState(checksum, m_padded) + tweak = TweakMessage(N, l, _MessageTweak.PAD) + pad = tbc.encrypt(tweak, key, [0 for byte in range(0, BLOCK_BYTES)]) + + lower_part = LowPart(pad, padding_bytes*8) + C.append(XorState(M[l], lower_part)) + tweak_final = TweakMessage(N, l+1, _MessageTweak.FINAL) + Final = tbc.encrypt(tweak_final, key, checksum) + + return (Final, C) + + +def TreatMessageDec(C, N, key): + checksum = [0 for byte in range(0, BLOCK_BYTES)] + + l = len(C)//BLOCK_BYTES + padding_bytes = len(C)%BLOCK_BYTES + + C = ArrayToBlockbytesMatrix(C) + M = [] + + for j in range(0, l): + tweak = TweakMessage(N, j, _MessageTweak.BLOCK) + M.append(tbc.decrypt(tweak, key, C[j])) + checksum = XorState(checksum, M[j]) + + if padding_bytes == 0: + tweak = TweakMessage(N, l, _MessageTweak.NO_PADDING) + Final = tbc.encrypt(tweak, key, checksum) + + else: + tweak = TweakMessage(N, l, _MessageTweak.PAD) + pad = tbc.encrypt(tweak, key, [0 for byte in range(0, BLOCK_BYTES)]) + lower_part = LowPart(pad, padding_bytes*8) + M.append(XorState(C[l], lower_part)) + + m_padded = Padding10LSB(M[l]) + checksum = XorState(checksum, m_padded) + tweak_final = TweakMessage(N, l+1, _MessageTweak.FINAL) + Final = tbc.encrypt(tweak_final, key, checksum) + + return (Final, M) + + +################################################################################ +def encrypt(A, M, N, key): + K = list(key) + + Auth = BuildAuth(TWEAK_BITS, A, K) + (Final, C) = TreatMessageEnc(M, N, K) + tag = XorState(Auth, Final) + + return BlockbytesMatrixToBytes(C), bytes(tag) + + +def decrypt(A, C, N, tag, key): + K = list(key) + tag = list(tag) + + Auth = BuildAuth(TWEAK_BITS, A, K) + (Final, M) = TreatMessageDec(C, N, K) + tag2 = XorState(Auth, Final) + + if tag != tag2: + raise TagValidationError(tag, tag2) + + return BlockbytesMatrixToBytes(M) diff --git a/src/add_python/lilliput/lilliput_ae_2.py b/src/add_python/lilliput/lilliput_ae_2.py new file mode 100644 index 0000000..61aa86e --- /dev/null +++ b/src/add_python/lilliput/lilliput_ae_2.py @@ -0,0 +1,127 @@ +""" + SCT 2 for lilliput ae 2 +""" + +from .constants import BLOCK_BYTES +from .helpers import ( + ArrayToBlockbytesMatrix, + BlockbytesMatrixToBytes, + BuildAuth, + Padding10LSB, + TagValidationError, + XorState +) +from . import tbc + + +TWEAK_BITS = 128 +TWEAK_BYTES = TWEAK_BITS//8 + + +def TweakTag(j, padded): + tweak = [0 for byte in range(0, TWEAK_BYTES)] + + tweak[TWEAK_BYTES - 1] |= ((j >> 120) & 0xf) + for byte in range(TWEAK_BYTES - 2, -1, -1): + tweak[byte] = (j >> (8 * byte)) & 0xff + + if padded: + tweak[TWEAK_BYTES - 1] |= 0x40 + + return tweak + + +def TweakTagEnd(N): + tweak = [0 for byte in range(0, TWEAK_BYTES)] + + for byte in range(0, TWEAK_BYTES - 1): + tweak[byte] = N[byte] + tweak[TWEAK_BYTES - 1] = 0x10 + + return tweak + + +def AddTagJ(tag, j): + array_j = [0 for byte in range(0, TWEAK_BYTES)] + for byte in range(0, TWEAK_BYTES): + array_j[byte] = (j >> (byte * 8)) + + xorr = XorState(tag, array_j) + + xorr[TWEAK_BYTES - 1] |= 0x80 + + return xorr + + +def MesssageAuthTag(M, N, Auth, key): + l = len(M)//BLOCK_BYTES + need_padding = len(M)%BLOCK_BYTES > 0 + + tag = list(Auth) + M = ArrayToBlockbytesMatrix(M) + + for j in range(0, l): + tweak = TweakTag(j, False) + encryption = tbc.encrypt(tweak, key, M[j]) + tag = XorState(tag, encryption) + + if need_padding: + tweak = TweakTag(l, True) + m_padded = Padding10LSB(M[l]) + encryption = tbc.encrypt(tweak, key, m_padded) + tag = XorState(tag, encryption) + + tweak = TweakTagEnd(N) + encryption = tbc.encrypt(tweak, key, tag) + tag = encryption + + return tag + + +def MessageEncryption(M, N, tag, key): + l = len(M)//BLOCK_BYTES + need_padding = len(M)%BLOCK_BYTES > 0 + + M = ArrayToBlockbytesMatrix(M) + C = [] + + for j in range(0, l): + tweak = AddTagJ(tag, j) + padded_nonce = list(N) + [0x00] + encryption = tbc.encrypt(tweak, key, padded_nonce) + C.append(XorState(M[j], encryption)) + + if need_padding: + tweak = AddTagJ(tag, l) + padded_nonce = list(N) + [0x00] + encryption = tbc.encrypt(tweak, key, padded_nonce) + C.append(XorState(M[l], encryption)) + + return C + + +################################################################################ +def encrypt(A, M, N, key): + K = list(key) + + Auth = BuildAuth(TWEAK_BITS, A, K) + tag = MesssageAuthTag(M, N, Auth, K) + C = MessageEncryption(M, N, tag, K) + + return BlockbytesMatrixToBytes(C), bytes(tag) + + +def decrypt(A, C, N, tag, key): + K = list(key) + tag = list(tag) + + M = BlockbytesMatrixToBytes( + MessageEncryption(C, N, tag, K) + ) + Auth = BuildAuth(TWEAK_BITS, A, K) + tag2 = MesssageAuthTag(M, N, Auth, K) + + if tag != tag2: + raise TagValidationError(tag, tag2) + + return M diff --git a/src/add_python/lilliput/multiplications.py b/src/add_python/lilliput/multiplications.py new file mode 100644 index 0000000..c5f1e44 --- /dev/null +++ b/src/add_python/lilliput/multiplications.py @@ -0,0 +1,186 @@ + +# Multiply by matrix M +def _multiplyM(lane): + multiplied_lane = [lane[(byte-1) % 8] for byte in range(0, 8)] + + multiplied_lane[2] ^= ((lane[6] << 2) & 0xff) + multiplied_lane[4] ^= ((lane[4] >> 3) & 0xff) + multiplied_lane[5] ^= ((lane[5] << 3) & 0xff) + + return multiplied_lane + +def _multiplyM2(lane): + multiplied_lane = [lane[(byte-2) % 8] for byte in range(0, 8)] + + multiplied_lane[2] ^= ((lane[5] << 2) & 0xff) + multiplied_lane[3] ^= ((lane[6] << 2) & 0xff) + multiplied_lane[4] ^= ((lane[3] >> 3) & 0xff) ^ ((lane[4] >> 6) & 0xff) + multiplied_lane[5] ^= ((lane[5] << 6) & 0xff) + multiplied_lane[6] ^= ((lane[5] << 3) & 0xff) + + # binary matrix M1 + multi_mat_l4_m1 = 0 + l4 = lane[4] + multi_mat_l4_m1 ^= ((l4 & 0x8) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x10) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x20) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x40) >> 3) ^ ((l4 & 0x1) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x80) >> 3) ^ ((l4 & 0x2) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x04) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x08) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x10) << 3) + + multiplied_lane[5] ^= multi_mat_l4_m1 + + return multiplied_lane + + +def _multiplyM3(lane): + multiplied_lane = [lane[(byte-3) % 8] for byte in range(0, 8)] + + multiplied_lane[2] ^= ((lane[4] << 2) & 0xff) ^ ((lane[5] << 5) & 0xff) + multiplied_lane[3] ^= ((lane[5] << 2) & 0xff) + multiplied_lane[4] ^= ((lane[2] >> 3) & 0xff) ^ ((lane[3] >> 6) & 0xff) ^ ((lane[6] << 2) & 0xff) + multiplied_lane[6] ^= ((lane[5] << 6) & 0xff) + multiplied_lane[7] ^= ((lane[5] << 3) & 0xff) + + # binary matrix M1 + multi_mat_l3_m1 = 0 + l3 = lane[3] + multi_mat_l3_m1 ^= ((l3 & 0x8) >> 3) + multi_mat_l3_m1 ^= ((l3 & 0x10) >> 3) + multi_mat_l3_m1 ^= ((l3 & 0x20) >> 3) + multi_mat_l3_m1 ^= ((l3 & 0x40) >> 3) ^ ((l3 & 0x1) << 3) + multi_mat_l3_m1 ^= ((l3 & 0x80) >> 3) ^ ((l3 & 0x2) << 3) + multi_mat_l3_m1 ^= ((l3 & 0x04) << 3) + multi_mat_l3_m1 ^= ((l3 & 0x08) << 3) + multi_mat_l3_m1 ^= ((l3 & 0x10) << 3) + + # binary matrix M1 + multi_mat_l4_m1 = 0 + l4 = lane[4] + multi_mat_l4_m1 ^= ((l4 & 0x8) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x10) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x20) >> 3) + multi_mat_l4_m1 ^= ((l4 & 0x40) >> 3) ^ ((l4 & 0x1) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x80) >> 3) ^ ((l4 & 0x2) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x04) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x08) << 3) + multi_mat_l4_m1 ^= ((l4 & 0x10) << 3) + + # binary matrix M2 + multi_mat_l4_m2 = 0 + l4 = lane[4] + multi_mat_l4_m2 ^= ((l4 & 0x40) >> 6) + multi_mat_l4_m2 ^= ((l4 & 0x80) >> 6) + multi_mat_l4_m2 ^= (l4 & 0x08) + multi_mat_l4_m2 ^= (l4 & 0x10) + multi_mat_l4_m2 ^= (l4 & 0x20) + multi_mat_l4_m2 ^= (l4 & 0x40) ^ ((l4 & 0x1) << 6) + multi_mat_l4_m2 ^= (l4 & 0x80) ^ ((l4 & 0x2) << 6) + + + multiplied_lane[5] ^= multi_mat_l3_m1 ^ multi_mat_l4_m2 + multiplied_lane[6] ^= multi_mat_l4_m1 + + return multiplied_lane + + +def _multiplyMR(lane): + multiplied_lane = [lane[(byte+1) % 8] for byte in range(0, 8)] + + multiplied_lane[2] ^= ((lane[4] >> 3) & 0xff) + multiplied_lane[4] ^= ((lane[6] << 3) & 0xff) + multiplied_lane[5] ^= ((lane[3] << 2) & 0xff) + + return multiplied_lane + + +def _multiplyMR2(lane): + multiplied_lane = [lane[(byte+2) % 8] for byte in range(0, 8)] + + multiplied_lane[1] ^= ((lane[4] >> 3) & 0xff) + multiplied_lane[2] ^= ((lane[5] >> 3) & 0xff) + multiplied_lane[3] ^= ((lane[6] << 3) & 0xff) + multiplied_lane[4] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) + multiplied_lane[5] ^= ((lane[4] << 2) & 0xff) + + + # binary matrix m3 + multi_mat_l6_m3 = 0 + l6 = lane[6] + multi_mat_l6_m3 ^= (l6 & 0x1) + multi_mat_l6_m3 ^= (l6 & 0x2) + multi_mat_l6_m3 ^= (l6 & 0x4) + multi_mat_l6_m3 ^= (l6 & 0x8) + multi_mat_l6_m3 ^= (l6 & 0x10) + + + multiplied_lane[2] ^= multi_mat_l6_m3 + + return multiplied_lane + +def _multiplyMR3(lane): + multiplied_lane = [lane[(byte+3) % 8] for byte in range(0, 8)] + + multiplied_lane[0] ^= ((lane[4] >> 3) & 0xff) + multiplied_lane[1] ^= ((lane[5] >> 3) & 0xff) + multiplied_lane[3] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) + multiplied_lane[4] ^= ((lane[0] << 3) & 0xff) ^ ((lane[4] << 2) & 0xff) + multiplied_lane[5] ^= ((lane[5] << 2) & 0xff) ^ ((lane[6] << 5) & 0xff) + + # binary matrix m3 + multi_mat_l6_m3 = 0 + l6 = lane[6] + multi_mat_l6_m3 ^= (l6 & 0x1) + multi_mat_l6_m3 ^= (l6 & 0x2) + multi_mat_l6_m3 ^= (l6 & 0x4) + multi_mat_l6_m3 ^= (l6 & 0x8) + multi_mat_l6_m3 ^= (l6 & 0x10) + + # binary matrix m3 + multi_mat_l7_m3 = 0 + l7 = lane[7] + multi_mat_l7_m3 ^= (l7 & 0x1) + multi_mat_l7_m3 ^= (l7 & 0x2) + multi_mat_l7_m3 ^= (l7 & 0x4) + multi_mat_l7_m3 ^= (l7 & 0x8) + multi_mat_l7_m3 ^= (l7 & 0x10) + + # binary matrix m4 + multi_mat_l3_m4 = 0 + l3 = lane[3] + multi_mat_l3_m4 ^= ((l3 & 0x2) >> 1) + multi_mat_l3_m4 ^= ((l3 & 0x4) >> 1) + multi_mat_l3_m4 ^= ((l3 & 0x8) >> 1) + multi_mat_l3_m4 ^= ((l3 & 0x10) >> 1) + multi_mat_l3_m4 ^= ((l3 & 0x20) >> 1) + + # binary matrix m1 for MR + multi_mat_l6_m1 = 0 + l6 = lane[6] + multi_mat_l6_m1 ^= ((l6 & 0x8) >> 3) + multi_mat_l6_m1 ^= ((l6 & 0x10) >> 3) + multi_mat_l6_m1 ^= ((l6 & 0x20) >> 3) + multi_mat_l6_m1 ^= ((l6 & 0x40) >> 3) ^ ((l6 & 0x1) << 3) + multi_mat_l6_m1 ^= ((l6 & 0x80) >> 3) ^ ((l6 & 0x2) << 3) + multi_mat_l6_m1 ^= ((l6 & 0x4) << 3) + multi_mat_l6_m1 ^= ((l6 & 0x8) << 3) + multi_mat_l6_m1 ^= ((l6 & 0x10) << 3) + + + multiplied_lane[1] ^= multi_mat_l6_m3 + multiplied_lane[2] ^= multi_mat_l3_m4 ^ multi_mat_l6_m1 ^ multi_mat_l7_m3 + + return multiplied_lane + + +ALPHAS = ( + list, # Identity. + _multiplyM, + _multiplyM2, + _multiplyM3, + _multiplyMR, + _multiplyMR2, + _multiplyMR3 +) diff --git a/src/add_python/lilliput/tbc.py b/src/add_python/lilliput/tbc.py new file mode 100644 index 0000000..5291994 --- /dev/null +++ b/src/add_python/lilliput/tbc.py @@ -0,0 +1,178 @@ +""" + Lilliput TBC +""" +from .constants import BLOCK_BYTES, Sbox +from .multiplications import ALPHAS + + +permutation = [14, 11, 12, 10, 8, 9, 13, 15, 3, 1, 4, 5, 6, 0, 2, 7] +permutationInv = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7] + +################################################################################ + +def BuildTweakey(tweak, key): + return tweak+key + +############################# + +def _lane(TK, j): + return TK[j*8:(j+1)*8] + +def RoundTweakeySchedule(tweakey): + p = len(tweakey)//8 + + multiplied_lanes = ( + ALPHAS[j](_lane(tweakey, j)) for j in range(p) + ) + + return [byte for lane in multiplied_lanes for byte in lane] + + +def SubTweakeyExtract(tweakey, Ci): + RTKi = [0]*8 + + for j, byte in enumerate(tweakey): + RTKi[j%8] ^= byte + + RTKi[0] ^= Ci + + return RTKi + + +def TweakeyScheduleWhole(tweakey, r): + # store main tweakey in TKs[0] + # and corresponding round tweakey in RTKs[0] + TKs = [tweakey] + RTKs = [SubTweakeyExtract(TKs[0], 0)] + + for i in range(1, r): + TKs.append(RoundTweakeySchedule(TKs[i-1])) + RTKs.append(SubTweakeyExtract(TKs[i], i)) + + return RTKs + + +################################################################################ + +def NonLinearLayer(state, subtweakey): + + variables_xored = [0 for byte in range(0, 8)] + for byte in range(0,8): + variables_xored[byte] = state[byte] ^ subtweakey[byte] + + variables_sboxed = [0 for byte in range(0, 8)] + for byte in range(0, 8): + variables_sboxed[byte] = Sbox[variables_xored[byte]] + + state_output = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0,BLOCK_BYTES): + state_output[byte] = state[byte] + for byte in range(0, 8): + state_output[15 - byte] ^= variables_sboxed[byte] + + return state_output + + +def LinearLayer(state): + state_output = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0, BLOCK_BYTES): + state_output[byte] = state[byte] + + for byte in range(1, 8): + state_output[15] ^= state[byte] + + for byte in range(9, 15): + state_output[byte] ^= state[7] + + return state_output + + +def PermutationLayerEnc(state): + state_output = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0, BLOCK_BYTES): + state_output[byte] = state[permutation[byte]] + + return state_output + +def PermutationLayerDec(state): + state_output = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0, BLOCK_BYTES): + state_output[byte] = state[permutationInv[byte]] + + return state_output + + +def OneRoundEGFNEnc(state, subtweakey): + state_non_linear = NonLinearLayer(state, subtweakey) + state_linear = LinearLayer(state_non_linear) + state_permutation = PermutationLayerEnc(state_linear) + + return state_permutation + +def LastRoundEGFN(state, subtweakey): + state_non_linear = NonLinearLayer(state, subtweakey) + state_linear = LinearLayer(state_non_linear) + + return state_linear + + +def OneRoundEGFNDec(state, subtweakey): + state_non_linear = NonLinearLayer(state, subtweakey) + state_linear = LinearLayer(state_non_linear) + state_permutation = PermutationLayerDec(state_linear) + + return state_permutation + + +def _rounds(key_bytes): + rounds = { + 128: 32, + 192: 36, + 256: 42 + } + return rounds[key_bytes*8] + + +################################################################################ +# Lilliput TBC + +def encrypt(tweak, key, message): + r = _rounds(len(key)) + + tweakey = BuildTweakey(tweak, key) + RTKs = TweakeyScheduleWhole(tweakey, r) + + state = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0, BLOCK_BYTES): + state[byte] = message[byte] + + for i in range(0, r-1): + state_output = OneRoundEGFNEnc(state, RTKs[i]) + + for byte in range(0, BLOCK_BYTES): + state[byte] = state_output[byte] + + state_output = LastRoundEGFN(state, RTKs[r-1]) + + return state_output + + +def decrypt(tweak, key, cipher): + r = _rounds(len(key)) + + tweakey = BuildTweakey(tweak, key) + RTKs = TweakeyScheduleWhole(tweakey, r) + + state = [0 for byte in range(0, BLOCK_BYTES)] + for byte in range(0, BLOCK_BYTES): + state[byte] = cipher[byte] + + for i in range(0, r-1): + state_output = OneRoundEGFNDec(state, RTKs[r-i-1]) + + for byte in range(0, BLOCK_BYTES): + state[byte] = state_output[byte] + + state_output = LastRoundEGFN(state, RTKs[0]) + + return state_output diff --git a/test/python.sh b/test/python.sh new file mode 100755 index 0000000..ea23caf --- /dev/null +++ b/test/python.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -eu + +TEST_DIR=$(dirname $0) +ROOT_DIR=${TEST_DIR}/.. + +make -C ${ROOT_DIR} nist + +./python/generate-vectors.sh +./python/compare.sh diff --git a/test/python/compare.sh b/test/python/compare.sh new file mode 100755 index 0000000..414eb1e --- /dev/null +++ b/test/python/compare.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +PYTHON_DIR=$(dirname $0) +ROOT_DIR=${PYTHON_DIR}/../../ +RESULTS_DIR=${ROOT_DIR}/results +CRYPTO_AEAD=${ROOT_DIR}/crypto_aead + +set -eu + +mkdir -p ${RESULTS_DIR}/crypto_aead_ref +for d in ${CRYPTO_AEAD}/lilliputaei* +do + mkdir -p ${RESULTS_DIR}/crypto_aead_ref/$(basename $d) + cp $d/LWC*.txt ${RESULTS_DIR}/crypto_aead_ref/$(basename $d)/ +done + +diff -ru ${RESULTS_DIR}/crypto_aead_ref ${RESULTS_DIR}/crypto_aead_py diff --git a/test/python/crypto_aead.py b/test/python/crypto_aead.py new file mode 100644 index 0000000..792369c --- /dev/null +++ b/test/python/crypto_aead.py @@ -0,0 +1,18 @@ +import lilliput +from lilliput.constants import NONCE_BYTES as NPUBBYTES, TAG_BYTES + +# Import KEYBYTES to expose it to genkat_aead. +# Import MODE to provide it to lilliput. +from parameters import KEYBYTES, MODE + + +def encrypt(m, ad, npub, k): + c, tag = lilliput.encrypt(m, ad, k, npub, MODE) + return c+tag + + +def decrypt(c, ad, npub, k): + clen = len(c)-TAG_BYTES + ctext = c[:clen] + tag = c[clen:] + return lilliput.decrypt(ctext, tag, ad, k, npub, MODE) diff --git a/test/python/generate-vectors.sh b/test/python/generate-vectors.sh new file mode 100755 index 0000000..e328c67 --- /dev/null +++ b/test/python/generate-vectors.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -eu + +PYTHON_DIR=$(dirname $0) +ROOT_DIR=${PYTHON_DIR}/../../ +SRC_DIR=${ROOT_DIR}/src/add_python +RESULTS_DIR=${ROOT_DIR}/results +CRYPTO_AEAD=${RESULTS_DIR}/crypto_aead_py + +mkdir -p ${CRYPTO_AEAD}/lilliputae{i,ii}{128,192,256}v1 + +declare -A names=([1]=lilliputaei [2]=lilliputaeii) + +for mode in 1 2 +do + for keylen in 128 192 256 + do + echo generating for ${mode} ${keylen} + + cat < ${RESULTS_DIR}/parameters.py +MODE = ${mode} +KEYBYTES = $((keylen/8)) +EOF + + PYTHONPATH=${RESULTS_DIR}:${SRC_DIR} ${PYTHON_DIR}/genkat_aead.py + + dest=${CRYPTO_AEAD}/${names[${mode}]}${keylen}v1 + mv LWC_AEAD_KAT_${keylen}_120.txt ${dest} + done +done diff --git a/test/python/genkat_aead.py b/test/python/genkat_aead.py new file mode 100755 index 0000000..01bed6f --- /dev/null +++ b/test/python/genkat_aead.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import crypto_aead + + +MAX_MESSAGE_LENGTH = 32 +MAX_ADATA_LENGTH = 32 + + +def print_bstr(output, label, buf): + print('{l} = {b}'.format(l=label, b=buf.hex().upper()), file=output) + + +def generate_test_vectors(): + output_path = 'LWC_AEAD_KAT_{key}_{npub}.txt'.format( + key=crypto_aead.KEYBYTES*8, npub=crypto_aead.NPUBBYTES*8 + ) + + npub = bytes(range(crypto_aead.NPUBBYTES)) + key = bytes(range(crypto_aead.KEYBYTES)) + + with open(output_path, 'w') as output: + + count = 1 + for mlen in range(MAX_MESSAGE_LENGTH+1): + for adlen in range(MAX_ADATA_LENGTH+1): + print('Count = {c}'.format(c=count), file=output) + + msg = bytes(range(mlen)) + ad = bytes(range(adlen)) + + print_bstr(output, 'Key', key) + print_bstr(output, 'Nonce', npub) + print_bstr(output, 'PT', msg) + print_bstr(output, 'AD', ad) + + ct = crypto_aead.encrypt(msg, ad, npub, key) + + print_bstr(output, 'CT', ct) + + crypto_aead.decrypt(ct, ad, npub, key) + + count += 1 + + print(file=output) + + +if __name__ == '__main__': + generate_test_vectors() -- cgit v1.2.3