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

lilliput-i.c (6346B)


      1 /*
      2 Implementation of the Lilliput-AE tweakable block cipher.
      3 
      4 Authors, hereby denoted as "the implementer":
      5     Kévin Le Gouguec,
      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 ---
     16 
     17 This file implements Lilliput-AE's nonce-respecting mode based on ΘCB3.
     18 */
     19 
     20 #include <stdbool.h>
     21 #include <stdint.h>
     22 #include <string.h>
     23 
     24 #include "cipher.h"
     25 #include "lilliput-ae.h"
     26 #include "lilliput-ae-utils.h"
     27 
     28 
     29 static const uint8_t _0n[BLOCK_BYTES] = {
     30     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     31     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     32 };
     33 
     34 
     35 static uint8_t _upper_nibble(uint8_t i)
     36 {
     37     return i >> 4;
     38 }
     39 
     40 static uint8_t _lower_nibble(uint8_t i)
     41 {
     42     return i & 0x0f;
     43 }
     44 
     45 static void _init_msg_tweak(const uint8_t N[NONCE_BYTES], uint8_t tweak[TWEAK_BYTES])
     46 {
     47     /* The t-bit tweak is filled as follows:
     48      *
     49      *   1    4    5     |N|+4    |N|+5     t
     50      * [ prefix ||  nonce      || block index ]
     51      *
     52      * The s-bit block index is encoded as follows:
     53      *
     54      *   |N|+5    t-s    t-s+1                t
     55      * [ zero padding || block index, MSB first ]
     56      *
     57      * This function sets bits 5 to t-s once and for all.
     58      */
     59 
     60     tweak[0] = _upper_nibble(N[0]);
     61 
     62     for (size_t i=1; i<NONCE_BYTES; i++)
     63     {
     64         tweak[i] = _lower_nibble(N[i-1]) << 4 ^ _upper_nibble(N[i]);
     65     }
     66 
     67     tweak[NONCE_BYTES] = _lower_nibble(N[NONCE_BYTES-1]) << 4;
     68 
     69     /* The number of bits we need to zero out is:
     70      *     t - |N| - s - 4        - 4
     71      *                   (prefix)   (zeroed out by previous assignment)
     72      */
     73     memset(&tweak[NONCE_BYTES+1], 0, TWEAK_BYTES-NONCE_BYTES-sizeof(size_t)-1);
     74 }
     75 
     76 static void _fill_msg_tweak(
     77     uint8_t prefix,
     78     size_t  block_index,
     79     uint8_t tweak[TWEAK_BYTES]
     80 )
     81 {
     82     /* The t-bit tweak is filled as follows:
     83      *
     84      *   1    4    5     |N|+4    |N|+5     t
     85      * [ prefix ||  nonce      || block index ]
     86      *
     87      * The s-bit block index is encoded as follows:
     88      *
     89      *   |N|+5    t-s    t-s+1                t
     90      * [ zero padding || block index, MSB first ]
     91      *
     92      * This function assumes bits 5 to t-s have already been set, and
     93      * only sets bits 1 to 4 and t-s+1 to t.
     94      */
     95 
     96     uint8_t *msb = &tweak[0];
     97     *msb = prefix<<4 ^ _lower_nibble(*msb);
     98 
     99     copy_block_index(block_index, tweak);
    100 }
    101 
    102 static void _encrypt_message(
    103     const uint8_t key[KEY_BYTES],
    104     size_t        M_len,
    105     const uint8_t M[M_len],
    106     const uint8_t N[NONCE_BYTES],
    107     uint8_t       C[M_len+BLOCK_BYTES],
    108     uint8_t       Final[BLOCK_BYTES]
    109 )
    110 {
    111     size_t l = M_len / BLOCK_BYTES;
    112     size_t rest = M_len % BLOCK_BYTES;
    113 
    114     uint8_t tweak[TWEAK_BYTES];
    115     _init_msg_tweak(N, tweak);
    116 
    117     uint8_t checksum[BLOCK_BYTES];
    118     memset(checksum, 0, BLOCK_BYTES);
    119 
    120     for (size_t j=0; j<l; j++)
    121     {
    122         xor_into(checksum, &M[j*BLOCK_BYTES]);
    123         _fill_msg_tweak(0x0, j, tweak);
    124         encrypt(key, tweak, &M[j*BLOCK_BYTES], &C[j*BLOCK_BYTES]);
    125     }
    126 
    127     if (rest == 0)
    128     {
    129         _fill_msg_tweak(0x1, l, tweak);
    130         encrypt(key, tweak, checksum, Final);
    131     }
    132     else
    133     {
    134         uint8_t M_rest[BLOCK_BYTES];
    135         uint8_t Pad[BLOCK_BYTES];
    136 
    137         pad10(rest, &M[l*BLOCK_BYTES], M_rest);
    138         xor_into(checksum, M_rest);
    139 
    140         _fill_msg_tweak(0x4, l, tweak);
    141         encrypt(key, tweak, _0n, Pad);
    142         xor_arrays(rest, &C[l*BLOCK_BYTES], &M[l*BLOCK_BYTES], Pad);
    143 
    144         _fill_msg_tweak(0x5, l+1, tweak);
    145         encrypt(key, tweak, checksum, Final);
    146     }
    147 }
    148 
    149 static void _decrypt_message(
    150     const uint8_t key[KEY_BYTES],
    151     size_t        C_len,
    152     const uint8_t C[C_len],
    153     const uint8_t N[NONCE_BYTES],
    154     uint8_t       M[C_len],
    155     uint8_t       Final[BLOCK_BYTES]
    156 )
    157 {
    158     size_t l = C_len / BLOCK_BYTES;
    159     size_t rest = C_len % BLOCK_BYTES;
    160 
    161     uint8_t tweak[TWEAK_BYTES];
    162     _init_msg_tweak(N, tweak);
    163 
    164     uint8_t checksum[BLOCK_BYTES];
    165     memset(checksum, 0, BLOCK_BYTES);
    166 
    167     for (size_t j=0; j<l; j++)
    168     {
    169         _fill_msg_tweak(0x0, j, tweak);
    170         decrypt(key, tweak, &C[j*BLOCK_BYTES], &M[j*BLOCK_BYTES]);
    171         xor_into(checksum, &M[j*BLOCK_BYTES]);
    172     }
    173 
    174     if (rest == 0)
    175     {
    176         _fill_msg_tweak(0x1, l, tweak);
    177         encrypt(key, tweak, checksum, Final);
    178     }
    179     else
    180     {
    181         uint8_t M_rest[BLOCK_BYTES];
    182         uint8_t Pad[BLOCK_BYTES];
    183 
    184         _fill_msg_tweak(0x4, l, tweak);
    185         encrypt(key, tweak, _0n, Pad);
    186         xor_arrays(rest, &M[l*BLOCK_BYTES], &C[l*BLOCK_BYTES], Pad);
    187 
    188         pad10(rest, &M[l*BLOCK_BYTES], M_rest);
    189         xor_into(checksum, M_rest);
    190 
    191         _fill_msg_tweak(0x5, l+1, tweak);
    192         encrypt(key, tweak, checksum, Final);
    193     }
    194 }
    195 
    196 static void _generate_tag(
    197     const uint8_t Final[BLOCK_BYTES],
    198     const uint8_t Auth[BLOCK_BYTES],
    199     uint8_t       tag[TAG_BYTES]
    200 )
    201 {
    202     xor_arrays(TAG_BYTES, tag, Final, Auth);
    203 }
    204 
    205 
    206 void lilliput_ae_encrypt(
    207     size_t        message_len,
    208     const uint8_t message[message_len],
    209     size_t        auth_data_len,
    210     const uint8_t auth_data[auth_data_len],
    211     const uint8_t key[KEY_BYTES],
    212     const uint8_t nonce[NONCE_BYTES],
    213     uint8_t       ciphertext[message_len],
    214     uint8_t       tag[TAG_BYTES]
    215 )
    216 {
    217     uint8_t auth[BLOCK_BYTES];
    218     process_associated_data(key, auth_data_len, auth_data, auth);
    219 
    220     uint8_t final[BLOCK_BYTES];
    221     _encrypt_message(key, message_len, message, nonce, ciphertext, final);
    222 
    223     _generate_tag(final, auth, tag);
    224 }
    225 
    226 bool lilliput_ae_decrypt(
    227     size_t        ciphertext_len,
    228     const uint8_t ciphertext[ciphertext_len],
    229     size_t        auth_data_len,
    230     const uint8_t auth_data[auth_data_len],
    231     const uint8_t key[KEY_BYTES],
    232     const uint8_t nonce[NONCE_BYTES],
    233     const uint8_t tag[TAG_BYTES],
    234     uint8_t       message[ciphertext_len]
    235 )
    236 {
    237     uint8_t auth[BLOCK_BYTES];
    238     process_associated_data(key, auth_data_len, auth_data, auth);
    239 
    240     uint8_t final[BLOCK_BYTES];
    241     _decrypt_message(key, ciphertext_len, ciphertext, nonce, message, final);
    242 
    243     uint8_t effective_tag[TAG_BYTES];
    244     _generate_tag(final, auth, effective_tag);
    245 
    246     return memcmp(tag, effective_tag, TAG_BYTES) == 0;
    247 }