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-ii.c (5339B)


      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-misuse-resistant mode based on SCT-2.
     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 void _init_msg_tweak(const uint8_t tag[TAG_BYTES], uint8_t tweak[TWEAK_BYTES])
     30 {
     31     /* The t-bit tweak is filled as follows:
     32      *
     33      *   1    2                      t
     34      * [ 1 || tag[2,t] XOR block index  ]
     35      *
     36      * The s-bit block index is XORed to the tag as follows:
     37      *
     38      *   2       t-s    t-s+1                                  t
     39      * [ tag[2, t-s] || tag[t-s+1, t] XOR block index, MSB first ]
     40      *
     41      * This function sets bits 1 to t-s once and for all.
     42      */
     43 
     44     memcpy(tweak, tag, TAG_BYTES-sizeof(size_t));
     45     tweak[0] |= 0x80;
     46 }
     47 
     48 static void _fill_msg_tweak(const uint8_t tag[TAG_BYTES], size_t block_index, uint8_t tweak[TWEAK_BYTES])
     49 {
     50     /* The t-bit tweak is filled as follows:
     51      *
     52      *   1    2                      t
     53      * [ 1 || tag[2,t] XOR block index  ]
     54      *
     55      * The s-bit block index is XORed to the tag as follows:
     56      *
     57      *   2       t-s    t-s+1                                  t
     58      * [ tag[2, t-s] || tag[t-s+1, t] XOR block index, MSB first ]
     59      *
     60      * This function assumes bits 1 to t-s have already been set, and
     61      * only sets bits t-s+1 to t.
     62      */
     63 
     64     copy_block_index(block_index, tweak);
     65 
     66     for (size_t i=TWEAK_BYTES-sizeof(size_t); i<TWEAK_BYTES; i++)
     67     {
     68         tweak[i] ^= tag[i];
     69     }
     70 }
     71 
     72 static void _fill_tag_tweak(const uint8_t N[NONCE_BYTES], uint8_t tweak[TWEAK_BYTES])
     73 {
     74     /* The t-bit tweak is filled as follows:
     75      *
     76      *   1  4    5   8    t-|N|+1     t
     77      * [ 0001 ||  0^4  ||        nonce  ]
     78      */
     79 
     80     tweak[0] = 0x10;
     81     memcpy(&tweak[1], N, TWEAK_BYTES-1);
     82 }
     83 
     84 static void _generate_tag(
     85     const uint8_t key[KEY_BYTES],
     86     size_t        M_len,
     87     const uint8_t M[M_len],
     88     const uint8_t N[NONCE_BYTES],
     89     const uint8_t Auth[BLOCK_BYTES],
     90     uint8_t       tag[TAG_BYTES]
     91 )
     92 {
     93     uint8_t Ek_Mj[BLOCK_BYTES];
     94     uint8_t tag_tmp[TAG_BYTES];
     95     uint8_t tweak[TWEAK_BYTES];
     96 
     97     memset(tweak, 0, TWEAK_BYTES);
     98     memcpy(tag_tmp, Auth, TAG_BYTES);
     99 
    100     size_t l = M_len / BLOCK_BYTES;
    101     size_t rest = M_len % BLOCK_BYTES;
    102 
    103     for (size_t j=0; j<l; j++)
    104     {
    105         fill_index_tweak(0x0, j, tweak);
    106         encrypt(key, tweak, &M[j*BLOCK_BYTES], Ek_Mj);
    107         xor_into(tag_tmp, Ek_Mj);
    108     }
    109 
    110     if (rest != 0)
    111     {
    112         uint8_t M_rest[BLOCK_BYTES];
    113         pad10(rest, &M[l*BLOCK_BYTES], M_rest);
    114         fill_index_tweak(0x4, l, tweak);
    115         encrypt(key, tweak, M_rest, Ek_Mj);
    116         xor_into(tag_tmp, Ek_Mj);
    117     }
    118 
    119     _fill_tag_tweak(N, tweak);
    120     encrypt(key, tweak, tag_tmp, tag);
    121 }
    122 
    123 static void _encrypt_message(
    124     const uint8_t key[KEY_BYTES],
    125     size_t        M_len,
    126     const uint8_t M[M_len],
    127     const uint8_t N[NONCE_BYTES],
    128     const uint8_t tag[TAG_BYTES],
    129     uint8_t       C[M_len]
    130 )
    131 {
    132     uint8_t Ek_N[BLOCK_BYTES];
    133 
    134     uint8_t tweak[TWEAK_BYTES];
    135     _init_msg_tweak(tag, tweak);
    136 
    137     uint8_t padded_N[BLOCK_BYTES];
    138     padded_N[0] = 0;
    139     memcpy(&padded_N[1], N, NONCE_BYTES);
    140 
    141     size_t l = M_len / BLOCK_BYTES;
    142     size_t rest = M_len % BLOCK_BYTES;
    143 
    144     for (size_t j=0; j<l; j++)
    145     {
    146         _fill_msg_tweak(tag, j, tweak);
    147         encrypt(key, tweak, padded_N, Ek_N);
    148         xor_arrays(BLOCK_BYTES, &C[j*BLOCK_BYTES], &M[j*BLOCK_BYTES], Ek_N);
    149     }
    150 
    151     if (rest != 0)
    152     {
    153         _fill_msg_tweak(tag, l, tweak);
    154         encrypt(key, tweak, padded_N, Ek_N);
    155         xor_arrays(rest, &C[l*BLOCK_BYTES], &M[l*BLOCK_BYTES], Ek_N);
    156     }
    157 }
    158 
    159 void lilliput_ae_encrypt(
    160     size_t        message_len,
    161     const uint8_t message[message_len],
    162     size_t        auth_data_len,
    163     const uint8_t auth_data[auth_data_len],
    164     const uint8_t key[KEY_BYTES],
    165     const uint8_t nonce[NONCE_BYTES],
    166     uint8_t       ciphertext[message_len],
    167     uint8_t       tag[TAG_BYTES]
    168 )
    169 {
    170     uint8_t auth[BLOCK_BYTES];
    171     process_associated_data(key, auth_data_len, auth_data, auth);
    172 
    173     _generate_tag(key, message_len, message, nonce, auth, tag);
    174 
    175     _encrypt_message(key, message_len, message, nonce, tag, ciphertext);
    176 }
    177 
    178 bool lilliput_ae_decrypt(
    179     size_t        ciphertext_len,
    180     const uint8_t ciphertext[ciphertext_len],
    181     size_t        auth_data_len,
    182     const uint8_t auth_data[auth_data_len],
    183     const uint8_t key[KEY_BYTES],
    184     const uint8_t nonce[NONCE_BYTES],
    185     const uint8_t tag[TAG_BYTES],
    186     uint8_t       message[ciphertext_len]
    187 )
    188 {
    189     _encrypt_message(key, ciphertext_len, ciphertext, nonce, tag, message);
    190 
    191     uint8_t auth[BLOCK_BYTES];
    192     process_associated_data(key, auth_data_len, auth_data, auth);
    193 
    194     uint8_t effective_tag[TAG_BYTES];
    195     _generate_tag(key, ciphertext_len, message, nonce, auth, effective_tag);
    196 
    197     return memcmp(tag, effective_tag, TAG_BYTES) == 0;
    198 }