commit bac28f498c5fee10720c8ed71988434e05d9197f
parent dd934c63386c8fa22a5b0944e0256c435d55938c
Author: Kévin Le Gouguec <kevin.legouguec@airbus.com>
Date: Fri, 22 Mar 2019 10:38:19 +0100
[implem-python] Création d'un paquet "lilliput"
Diffstat:
12 files changed, 585 insertions(+), 585 deletions(-)
diff --git a/python/helpers.py b/python/helpers.py
@@ -1,92 +0,0 @@
-from constants import BLOCK_BITS, BLOCK_BYTES
-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.py b/python/lilliput.py
@@ -1,33 +0,0 @@
-from enum import Enum
-
-import lilliput_ae_1
-import lilliput_ae_2
-from constants import NONCE_BYTES
-
-
-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 encrypt(plaintext, adata, key, nonce, mode):
- _checkInputs(key, mode, nonce)
- return mode.value.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)
diff --git a/python/lilliput/__init__.py b/python/lilliput/__init__.py
@@ -0,0 +1,33 @@
+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
+
+
+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 encrypt(plaintext, adata, key, nonce, mode):
+ _checkInputs(key, mode, nonce)
+ return mode.value.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)
diff --git a/python/constants.py b/python/lilliput/constants.py
diff --git a/python/lilliput/helpers.py b/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/python/lilliput/lilliput_ae_1.py b/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/python/lilliput/lilliput_ae_2.py b/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/python/multiplications.py b/python/lilliput/multiplications.py
diff --git a/python/lilliput/tbc.py b/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/python/lilliput_ae_1.py b/python/lilliput_ae_1.py
@@ -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
-)
-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_ae_2.py b/python/lilliput_ae_2.py
@@ -1,127 +0,0 @@
-"""
- SCT 2 for lilliput ae 2
-"""
-
-from constants import BLOCK_BYTES
-from helpers import (
- ArrayToBlockbytesMatrix,
- BlockbytesMatrixToBytes,
- BuildAuth,
- Padding10LSB,
- TagValidationError,
- XorState
-)
-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/tbc.py b/python/tbc.py
@@ -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