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/compare.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'python/compare.sh') 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 -- 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/compare.sh') 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