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 }