lilliput-ae-reference-implementation

Implementations of Lilliput-AE submitted to the NIST LWC standardization process
git clone https://git.kevinlegouguec.net/lilliput-ae-reference-implementation
Log | Files | Refs | README

ae_mode_2.py (2970B)


      1 # Implementation of the Lilliput-AE tweakable block cipher.
      2 #
      3 # Authors, hereby denoted as "the implementer":
      4 #     Kévin Le Gouguec,
      5 #     Léo Reynaud
      6 #     2019.
      7 #
      8 # For more information, feedback or questions, refer to our website:
      9 # https://paclido.fr/lilliput-ae
     10 #
     11 # To the extent possible under law, the implementer has waived all copyright
     12 # and related or neighboring rights to the source code in this file.
     13 # http://creativecommons.org/publicdomain/zero/1.0/
     14 
     15 """Lilliput-II Authenticated Encryption mode.
     16 
     17 This module provides the functions for authenticated encryption and decryption
     18 using Lilliput-AE's nonce-misuse-resistant mode based on SCT-2.
     19 """
     20 
     21 from enum import Enum
     22 
     23 from .constants import BLOCK_BYTES
     24 from .ae_common import (
     25     bytes_to_block_matrix,
     26     block_matrix_to_bytes,
     27     integer_to_byte_array,
     28     build_auth,
     29     pad10,
     30     TagValidationError,
     31     xor
     32 )
     33 from . import tbc
     34 
     35 
     36 TWEAK_BITS = 128
     37 TWEAK_BYTES = TWEAK_BITS//8
     38 
     39 
     40 class _TagTweak(Enum):
     41     BLOCK = 0b0000
     42     PAD = 0b0100
     43 
     44 
     45 def _tweak_tag(j, prefix):
     46     tweak = integer_to_byte_array(j, TWEAK_BYTES)
     47 
     48     # Clear upper 4 bits and set them to prefix.
     49     tweak[0] &= 0b00001111
     50     tweak[0] |= prefix.value << 4
     51 
     52     return tweak
     53 
     54 
     55 def _add_tag_j(tag, j):
     56     tweak = xor(tag, integer_to_byte_array(j, TWEAK_BYTES))
     57     tweak[0] |= 0b10000000
     58 
     59     return tweak
     60 
     61 
     62 def _message_auth_tag(M, N, Auth, key):
     63     l = len(M)//BLOCK_BYTES
     64     need_padding = len(M)%BLOCK_BYTES > 0
     65 
     66     tag = list(Auth)
     67     M = bytes_to_block_matrix(M)
     68 
     69     for j in range(0, l):
     70         tweak = _tweak_tag(j, _TagTweak.BLOCK)
     71         encryption = tbc.encrypt(tweak, key, M[j])
     72         tag = xor(tag, encryption)
     73 
     74     if need_padding:
     75         tweak = _tweak_tag(l, _TagTweak.PAD)
     76         encryption = tbc.encrypt(tweak, key, pad10(M[l]))
     77         tag = xor(tag, encryption)
     78 
     79     tag = tbc.encrypt([0b00010000]+N, key, tag)
     80 
     81     return tag
     82 
     83 
     84 def _message_encryption(M, N, tag, key):
     85     l = len(M)//BLOCK_BYTES
     86     need_padding = len(M)%BLOCK_BYTES > 0
     87 
     88     M = bytes_to_block_matrix(M)
     89     C = []
     90 
     91     for j in range(0, l):
     92         tweak = _add_tag_j(tag, j)
     93         encryption = tbc.encrypt(tweak, key, [0b00000000]+N)
     94         C.append(xor(M[j], encryption))
     95 
     96     if need_padding:
     97         tweak = _add_tag_j(tag, l)
     98         encryption = tbc.encrypt(tweak, key, [0b00000000]+N)
     99         C.append(xor(M[l], encryption))
    100 
    101     return C
    102 
    103 
    104 def encrypt(A, M, N, key):
    105     K = list(key)
    106     N = list(N)
    107 
    108     Auth = build_auth(TWEAK_BITS, A, K)
    109     tag = _message_auth_tag(M, N, Auth, K)
    110     C = _message_encryption(M, N, tag, K)
    111 
    112     return block_matrix_to_bytes(C), bytes(tag)
    113 
    114 
    115 def decrypt(A, C, N, tag, key):
    116     K = list(key)
    117     N = list(N)
    118     tag = list(tag)
    119 
    120     M = block_matrix_to_bytes(
    121         _message_encryption(C, N, tag, K)
    122     )
    123     Auth = build_auth(TWEAK_BITS, A, K)
    124     tag2 = _message_auth_tag(M, N, Auth, K)
    125 
    126     if tag != tag2:
    127         raise TagValidationError(tag, tag2)
    128 
    129     return M