Solaris Software
Loading...
Searching...
No Matches
encryption.c
Go to the documentation of this file.
1/*
2 ==============================================================================
3 Name : encryption.c
4 Author : polfosol
5 Version : 12
6 Copyright : copyright © 2022 - polfosol
7 Description : ANSI-C compatible implementation of µAES ™ library.
8 ==============================================================================
9 */
10
11#include "encryption.h"
12
13/*----------------------------------------------------------------------------*\
14 Constants and MACROs
15\*----------------------------------------------------------------------------*/
17{
18 BLOCKSIZE = 128 / 8, /* Block length in AES is 'always' 128-bits. */
20 Nb = BLOCKSIZE / 4, /* number of columns comprising a AES state. */
21 Nk = KEYSIZE / 4, /* number of 32 bit words in a key. */
22 ROUNDS = Nk + 6, /* number of rounds in AES Cipher. */
23 HB = BLOCKSIZE / 2, /* length of a half-block unit. */
24 LAST = BLOCKSIZE - 1, /* index of last element (LSB) in a block. */
25 MIDST = LAST / 2, /* index of half-block LSB. */
26 PL = BLOCKSIZE + 1 /* length of arithmetic blocks in poly-1305. */
27};
28
29#define IMPLEMENT(x) (x) > 0
30
31#define INCREASE_SECURITY 0 /* see the comments at the bottom of header. */
32#define AVOID_FUNCTION_CALL 0
33#define SMALL_CIPHER 0
34
35/** Lookup-tables are "static constant", so that they can be placed in read-only
36 * storage instead of RAM. They can be computed dynamically trading ROM for RAM.
37 * This may be useful in (embedded) bootloader applications, where ROM is often
38 * limited. Note that sbox[y] = x, if and only if rsbox[x] = y. For more details
39 * on dynamic sbox computation, see https://en.wikipedia.org/wiki/Rijndael_S-box
40 */
41static const char sbox[256] =
42 "c|w{\362ko\3050\01g+\376\327\253v\312\202\311}\372YG\360\255\324\242\257"""
43 "\234\244r\300\267\375\223&6\?\367\3144\245\345\361q\3301\25\04\307#\303\30"
44 "\226\05\232\a\22\200\342\353\'\262u\t\203,\32\33nZ\240R;\326\263)\343/\204"
45 "S\321\0\355 \374\261[j\313\2769JLX\317\320\357\252\373CM3\205E\371\02\177P"
46 "<\237\250Q\243@\217\222\2358\365\274\266\332!\20\377\363\322\315\f\23\354_"
47 "\227D\27\304\247~=d]\31s`\201O\334\"*\220\210F\356\270\24\336^\v\333\3402:"
48 "\nI\06$\\\302\323\254b\221\225\344y\347\3107m\215\325N\251lV\364\352ez\256"
49 "\b\272x%.\34\246\264\306\350\335t\37K\275\213\212p>\265fH\03\366\16a5W\271"
50 "\206\301\035\236\341\370\230\021i\331\216\224\233\36\207\351\316U(\337\214"
51 "\241\211\r\277\346BhA\231-\17\260T\273\26";
52
53#if DECRYPTION
54static const char rsbox[256] =
55 "R\tj\32506\2458\277@\243\236\201\363\327\373|\3439\202\233/\377\2074\216CD"
56 "\304\336\351\313T{\2242\246\302#=\356L\225\vB\372\303N\b.\241f(\331$\262v["
57 "\242Im\213\321%r\370\366d\206h\230\026\324\244\\\314]e\266\222lpHP\375\355"
58 "\271\332^\25FW\247\215\235\204\220\330\253\0\214\274\323\n\367\344X\05\270"
59 "\263E\06\320,\036\217\312?\17\02\301\257\275\03\01\23\212k:\221\021AOg\334"
60 "\352\227\362\317\316\360\264\346s\226\254t\"\347\2555\205\342\3717\350\34u"
61 "\337nG\361\32q\35)\305\211o\267b\16\252\30\276\33\374V>K\306\322y \232\333"
62 "\300\376x\315Z\364\037\335\2503\210\a\3071\261\22\20Y\'\200\354_`Q\177\251"
63 "\31\265J\r-\345z\237\223\311\234\357\240\340;M\256*\365\260\310\353\273<"""
64 "\203S\231a\27+\4~\272w\326&\341i\24cU!\f}";
65#endif
66
67/*----------------------------------------------------------------------------*\
68 Data types and private variables
69\*----------------------------------------------------------------------------*/
70
71/** The array that stores all round keys during the AES key-expansion process */
72static uint8_t RoundKey[BLOCKSIZE * ROUNDS + KEYSIZE];
73
74/** block_t indicates fixed-size memory blocks, and state_t represents the state
75 * matrix. note that state[i][j] means the i-th COLUMN and j-th ROW of matrix */
76typedef uint8_t block_t[BLOCKSIZE];
77typedef uint8_t state_t[Nb][4];
78
79/*----------------------------------------------------------------------------*\
80 Auxiliary functions for the Rijndael algorithm
81\*----------------------------------------------------------------------------*/
82
83#define SBoxValue(x) *(sbox + x)
84#define InvSBoxValue(x) (rsbox[x]) /* omitted dynamic s-box calculation */
85
86#define COPYDWORD(x, y) *(int32_t*) &y = *(int32_t*) &x
87#define XOR32BITS(x, y) *(int32_t*) &y ^= *(int32_t*) &x
88
89#ifdef INT64_MAX
90#define XOR64BITS(x, y) *(int64_t*) &y ^= *(int64_t*) &x
91#else
92#define XOR64BITS(x, y) XOR32BITS(x, y); XOR32BITS(*(&x + 4), *(&y + 4))
93#endif
94
95#if AVOID_FUNCTION_CALL
96#define xorBlock(x, y) XOR64BITS(*(x), *(y)); XOR64BITS((x)[8], (y)[8])
97
98#define xtime(x) ((x) & 0x80 ? (x) * 2 ^ 0x11b : (x) << 1)
99
100#define mixG8(a, b, c, d) b ^ c ^ d ^ \
101 xtime(a ^ b ^ xtime(a ^ c ^ xtime(a ^ b ^ c ^ d )))
102#else
103
104/** doubling the value of x in Galois bit field GF(2^8) with polynomial 0x11b */
105static uint8_t xtime( uint8_t x )
106{
107 return (x > 0x7f) * 0x1b ^ (x << 1);
108}
109
110/** XOR two 128bit blocks, i.e. add two numbers in Galois bit field GF(2^128) */
111static void xorBlock( const block_t src, block_t dest )
112{
113 uint8_t n = BLOCKSIZE; /* many CPUs do 128-bit xor in a */
114 while (n) /* single instruction such as XORPS */
115 { /* see the file: x86-improvements */
116 n -= sizeof (size_t);
117 *(size_t*) &dest[n] ^= *(size_t const*) &src[n];
118 }
119}
120
121#if DECRYPTION
122
123/** inverse multiply in 8bit GF: mul(a,14) ^ mul(b,11) ^ mul(c,13) ^ mul(d,9) */
124static uint8_t mixG8( uint8_t a, uint8_t b, uint8_t c, uint8_t d )
125{
126 b ^= a;
127 d ^= b ^ c;
128 c ^= a;
129 a ^= d;
130 c ^= xtime( d );
131 b ^= xtime( c );
132 a ^= xtime( b );
133 return a; /* or use (9 11 13 14) lookup tables */
134}
135#endif
136#endif
137
138/*----------------------------------------------------------------------------*\
139 Main functions for the Rijndael encryption algorithm
140\*----------------------------------------------------------------------------*/
141
142/** This function produces (ROUNDS+1) round keys, which are used in each round
143 * to encrypt/decrypt the intermediate states. First round key is the main key
144 * itself, and other rounds are constructed from the previous ones as follows */
145static void KeyExpansion( const uint8_t* key )
146{
147 uint8_t rcon = 1, i;
148 memcpy( RoundKey, key, KEYSIZE );
149
150 for (i = KEYSIZE; i < BLOCKSIZE * (ROUNDS + 1); i += 4)
151 {
152 switch (i % KEYSIZE)
153 {
154 case 0:
155 memcpy( &RoundKey[i], &RoundKey[i - KEYSIZE], KEYSIZE );
156 if (4 / Nk && !rcon)
157 {
158 rcon = 0x1b; /* this only happens in AES-128, with Nk = 4 */
159 }
160 RoundKey[i ] ^= SBoxValue( RoundKey[i - 3] ) ^ rcon;
161 RoundKey[i + 1] ^= SBoxValue( RoundKey[i - 2] );
162 RoundKey[i + 2] ^= SBoxValue( RoundKey[i - 1] );
163 RoundKey[i + 3] ^= SBoxValue( RoundKey[i - 4] );
164 rcon <<= 1;
165 break;
166#if AES___== 256 /* an extra round is applied only in AES-256 */
167 case 48 - KEYSIZE:
168 RoundKey[i ] ^= SBoxValue( RoundKey[i - 4] );
169 RoundKey[i + 1] ^= SBoxValue( RoundKey[i - 3] );
170 RoundKey[i + 2] ^= SBoxValue( RoundKey[i - 2] );
171 RoundKey[i + 3] ^= SBoxValue( RoundKey[i - 1] );
172 break;
173#endif
174 default:
175 XOR32BITS( RoundKey[(i - 4)], RoundKey[i ] );
176 break;
177 }
178 }
179}
180
181/** XOR the round keys with the rijndael state matrix; namely, add them in GF */
182static void AddRoundKey( const uint8_t round, block_t state )
183{
184 xorBlock( RoundKey + BLOCKSIZE * round, state );
185}
186
187/** Substitute values in the state matrix with associated values in the S-box */
188static void SubBytes( block_t state )
189{
190 uint8_t i;
191 for (i = 0; i < BLOCKSIZE; ++i)
192 {
193 state[i] = SBoxValue( state[i] );
194 }
195}
196
197/** Shift/rotate the rows of the state matrix to the left. Each row is shifted
198 * with a different offset (= Row number). So the "zeroth" row is not shifted */
199static void ShiftRows( state_t state )
200{
201 uint8_t tmp = state[0][1];
202 state[0][1] = state[1][1];
203 state[1][1] = state[2][1];
204 state[2][1] = state[3][1];
205 state[3][1] = tmp; /* the first row rotates 1 column(s) to left */
206
207 tmp = state[0][2];
208 state[0][2] = state[2][2];
209 state[2][2] = tmp;
210 tmp = state[1][2];
211 state[1][2] = state[3][2];
212 state[3][2] = tmp; /* the second row rotates 2 columns to left, */
213
214 tmp = state[3][3];
215 state[3][3] = state[2][3];
216 state[2][3] = state[1][3];
217 state[1][3] = state[0][3];
218 state[0][3] = tmp; /* and the 3rd row rotates 3 columns to left */
219}
220
221/** Use matrix multiplication in Galois field to mix the columns of the state */
222static void MixColumns( state_t state )
223{
224 uint8_t C[4], i;
225 for (i = 0; i < Nb; ++i) /*-> https://crypto.stackexchange.com/q/2402 */
226 {
227 COPYDWORD( state[i], C[0] );
228 C[3] ^= C[1];
229 C[1] ^= C[0];
230 C[0] ^= C[2];
231 C[2] = xtime( C[0] );
232 C[0] ^= xtime( C[1] );
233 C[1] = xtime( C[3] );
234
235 state[i][0] ^= C[0] ^= C[3];
236 state[i][1] ^= C[0] ^= C[2];
237 state[i][2] ^= C[0] ^= C[1];
238 state[i][3] ^= C[0] ^= C[2];
239 }
240}
241
242/** Encrypt a plaintext input block and save the result/ciphertext as output. */
243static void rijndaelEncrypt( const block_t input, block_t output )
244{
245 uint8_t r;
246 state_t* mat = (void*) output;
247
248 /* copy plaintext into the state matrix, and beware of undefined behavior */
249 if (input != output) memcpy( mat, input, BLOCKSIZE );
250
251 /* The encryption is carried out in #ROUNDS iterations, of which the first
252 * #ROUNDS-1 are identical. The last round doesn't involve mixing columns */
253 for (r = 0; r != ROUNDS; )
254 {
255 AddRoundKey( r, output );
256 SubBytes( output );
257 ShiftRows( *mat );
258 ++r != ROUNDS ? MixColumns( *mat ) : AddRoundKey( ROUNDS, output );
259 }
260}
261
262/*----------------------------------------------------------------------------*\
263 Block-decryption part of the Rijndael algorithm
264\*----------------------------------------------------------------------------*/
265
266#if IMPLEMENT(DECRYPTION)
267
268/** Substitutes the values in state matrix with values of the inverted S-box. */
269static void InvSubBytes( block_t state )
270{
271 uint8_t i;
272 for (i = 0; i < BLOCKSIZE; ++i)
273 {
274 state[i] = InvSBoxValue( state[i] );
275 }
276}
277
278/** This function shifts (i.e rotates) the rows of the state matrix to right. */
279static void InvShiftRows( state_t state )
280{
281 uint8_t tmp = state[3][1];
282 state[3][1] = state[2][1];
283 state[2][1] = state[1][1];
284 state[1][1] = state[0][1];
285 state[0][1] = tmp; /* the first row rotates 1 columns to right, */
286
287 tmp = state[0][2];
288 state[0][2] = state[2][2];
289 state[2][2] = tmp;
290 tmp = state[1][2];
291 state[1][2] = state[3][2];
292 state[3][2] = tmp; /* the second row rotates 2 columns to right */
293
294 tmp = state[0][3];
295 state[0][3] = state[1][3];
296 state[1][3] = state[2][3];
297 state[2][3] = state[3][3];
298 state[3][3] = tmp; /* the third row rotates 3 columns to right. */
299}
300
301/** Reverse the process of mixing columns by matrix multiplication in GF(2^8) */
302static void InvMixColumns( state_t state )
303{
304 uint8_t C[4], i;
305 for (i = 0; i < Nb; ++i) /*-> https://crypto.stackexchange.com/q/2569 */
306 {
307 COPYDWORD( state[i], C[0] );
308 state[i][0] = mixG8( C[0], C[1], C[2], C[3] );
309 state[i][1] = mixG8( C[1], C[2], C[3], C[0] );
310 state[i][2] = mixG8( C[2], C[3], C[0], C[1] );
311 state[i][3] = mixG8( C[3], C[0], C[1], C[2] );
312 }
313}
314
315/** Decrypt a ciphertext input block and save the result/plaintext to output. */
316static void rijndaelDecrypt( const block_t input, block_t output )
317{
318 uint8_t r;
319 state_t* mat = (void*) output;
320
321 /* copy input to the state matrix, i.e initialize the state by ciphertext */
322 if (input != output) memcpy( mat, input, BLOCKSIZE );
323
324 /* Decryption is carried out in #ROUNDS iterations. The rounds are similar
325 * except for the first one which doesn't involve [reverse]mixing columns */
326 for (r = ROUNDS; r != 0; )
327 {
328 r-- != ROUNDS ? InvMixColumns( *mat ) : AddRoundKey( ROUNDS, output );
329 InvShiftRows( *mat );
330 InvSubBytes( output );
331 AddRoundKey( r, output );
332 }
333}
334#endif /* DECRYPTION */
335
336#if MICRO_RJNDL
337/**
338 * @brief encrypt or decrypt a single block with a given key
339 * @param key a byte array with a fixed size of KEYSIZE
340 * @param mode mode of operation: 'E' (1) to encrypt, 'D' (0) to decrypt
341 * @param x input byte array with BLOCKSIZE bytes
342 * @param y output byte array with BLOCKSIZE bytes
343 */
344void SPP_EXTERNAL_ENCRYPTION_cipher( const uint8_t* key, const char mode, const block_t x, block_t y )
345{
346 KeyExpansion( key );
347 mode & 1 ? rijndaelEncrypt( x, y ) : rijndaelDecrypt( x, y );
348}
349#endif
350
351
352/*----------------------------------------------------------------------------*\
353 * Implementation of different block ciphers modes *
354 * Definitions & Auxiliary Functions *
355\*----------------------------------------------------------------------------*/
356
357/** function-pointer types, indicating functions that take fixed-size blocks: */
358typedef void (*fmix_t)( const block_t, block_t ) SDCC_REENT;
359typedef void (*fdouble_t)( block_t );
360
361#define AES_setkey(key) KeyExpansion( key )
362
363#if !INCREASE_SECURITY
364#define BURN(key) (void) key
365#define SABOTAGE(buf, len) (void) buf /* the line will be ignored */
366#define memcmp_s memcmp
367
368#else
369#define BURN(key) memset( key, 0, sizeof key )
370#define SABOTAGE(buf, len) memset( buf, 0, len )
371#if AEAD_MODES | KWA
372
373/** for constant-time comparison of memory blocks, to avoid "timing attacks". */
374static uint8_t memcmp_s( const void* src, const void* dest, const char len )
375{
376 const volatile char *p1 = src, *p2 = (const volatile char*) dest;
377 volatile uint8_t result = 0;
378 char i;
379 for (i = 0; i != len; i++)
380 {
381 result |= p1[i] ^ p2[i];
382 }
383 return result;
384}
385#endif
386#endif /* SECURITY */
387
388#if SMALL_CIPHER
389typedef uint8_t count_t;
390
391#define incBlock(block, index) ++block[index]
392#define xorBEint(buf, num, pos) buf[pos - 1] ^= (num) >> 8; buf[pos] ^= num
393#define copyLint(buf, num, pos) buf[pos + 1] = (num) >> 8; buf[pos] = num
394
395#else
396typedef size_t count_t;
397
398#if XTS | GCM_SIV
399
400/** copy a little endian integer to the block, with LSB at specified position */
401static void copyLint( block_t block, size_t num, uint8_t pos )
402{
403 do
404 block[pos++] = (uint8_t) num;
405 while (num >>= 8);
406}
407#endif
408
409#if CTR | KWA | FPE
410
411/** xor a byte array with a big-endian integer, whose LSB is at specified pos */
412static void xorBEint( uint8_t* buff, size_t num, uint8_t pos )
413{
414 do
415 buff[pos--] ^= (uint8_t) num;
416 while (num >>= 8);
417}
418#endif
419
420#if CTR
421
422/** increment the value of a 128-bit counter block, regarding its endian-ness */
423static void incBlock( block_t block, uint8_t index )
424{
425 do /* increment the LSBs, */
426 if (++block[index]) /* ..until no overflow */
427 break;
428 while (index > HB ? --index : ++index < 4);
429}
430#endif
431#endif /* SMALL CIPHER */
432
433#if EAX * !EAXP | SIV | OCB | CMAC
434
435/** Multiply a block by two in Galois bit field GF(2^128): big-endian version */
436static void doubleBblock( block_t array )
437{
438 int c = 0, i;
439 for (i = BLOCKSIZE; i > 0; c >>= 8) /* from last byte (LSB) to */
440 { /* first: left-shift, then */
441 c |= array[--i] << 1; /* append the previous MSBit */
442 array[i] = (uint8_t) c;
443 } /* if first MSBit is carried */
444 array[LAST] ^= c * 0x87; /* .. A ^= 10000111b (B.E.) */
445}
446#endif
447
448#if XTS | EAXP
449
450/** Multiply a block by two in Galois field GF(2^128): little-endian version. */
451static void doubleLblock( block_t array )
452{
453 int i, c = 0;
454 for (i = 0; i < BLOCKSIZE; c >>= 8) /* the same as doubleBblock */
455 { /* ..but with reversed bytes */
456 c |= array[i] << 1;
457 array[i++] = (uint8_t) c;
458 }
459 array[0] ^= c * 0x87; /* A ^= 10000111b (L.E.) */
460}
461#endif
462
463#if GCM
464
465/** Divide a 128-bit big-endian integer by two in Galois bit field GF(2^128). */
466static void divideBblock( block_t array )
467{
468 unsigned i, c = 0;
469 for (i = 0; i < BLOCKSIZE; ++i) /* from first to last byte, */
470 { /* prepend the previous LSB */
471 c = c << 8 | array[i]; /* then shift it to right. */
472 array[i] = c >> 1;
473 } /* if block is odd (LSB = 1) */
474 if (c & 1) array[0] ^= 0xe1; /* .. A ^= 11100001b << 120 */
475}
476
477/** Multiply two 128-bit numbers (big-endian blocks) in the Galois bit field. */
478static void mulGF128( const block_t x, block_t y )
479{
480 uint8_t b, i;
481 block_t result = { 0 }; /* working memory */
482
483 for (i = 0; i < BLOCKSIZE; ++i)
484 {
485 for (b = 0x80; b; b >>= 1) /* check all the bits of X, */
486 {
487 if (x[i] & b) /* ..and if any bit is set, */
488 {
489 xorBlock( y, result ); /* ..add Y to the result */
490 }
491 divideBblock( y ); /* Y_next = (Y / 2) in GF */
492 }
493 }
494 memcpy( y, result, sizeof result ); /* result is saved into y */
495}
496#endif /* GCM */
497
498#if GCM_SIV
499
500/** Divide a block by two in 128-bit Galois field: the little-endian version. */
501static void divideLblock( block_t array )
502{
503 unsigned c = 0, i;
504 for (i = BLOCKSIZE; i--; ) /* similar to divideBblock ↑ */
505 { /* ..but with reversed bytes */
506 c = c << 8 | array[i];
507 array[i] = c >> 1;
508 }
509 if (c & 1) array[LAST] ^= 0xe1; /* (L.E) A ^= 11100001b<<120 */
510}
511
512/** The so-called "dot multiplying" in GF(2^128), used in POLYVAL calculation */
513static void dotGF128( const block_t x, block_t y )
514{
515 uint8_t b, i;
516 block_t result = { 0 };
517
518 for (i = BLOCKSIZE; i--; )
519 {
520 for (b = 0x80; b; b >>= 1) /* pretty much the same as */
521 { /* ..(reversed) mulGF128 */
522 divideLblock( y );
523 if (x[i] & b)
524 {
525 xorBlock( y, result );
526 }
527 }
528 }
529 memcpy( y, result, sizeof result ); /* result is saved into y */
530}
531#endif /* GCM-SIV */
532
533#if CTR | CFB | OFB | CTS | OCB
534
535/** mix/cipher the block B and then xor the result with n bytes of X to get Y */
536static void mixThenXor( fmix_t mix, const block_t B, block_t f,
537 const uint8_t* X, uint8_t n, uint8_t* Y )
538{
539 if (n != 0)
540 {
541 mix( B, f ); /* Y = f(B) ^ X */
542 while (n--)
543 {
544 Y[n] = f[n] ^ X[n];
545 }
546 }
547}
548#endif
549
550#if AEAD_MODES | FPE
551
552/** xor the result with input data and then apply the digest/mixing function.
553 * repeat this process for each block of data, until all blocks are digested. */
554static void xMac( const void* data, const size_t dataSize,
555 const block_t seed, fmix_t mix, block_t result )
556{
557 uint8_t const* x;
558 count_t n = dataSize / BLOCKSIZE; /* number of full blocks */
559
560 for (x = data; n--; x += BLOCKSIZE)
561 {
562 xorBlock( x, result ); /* M_next = mix(seed, M ^ X) */
563 mix( seed, result );
564 }
565 for (n = dataSize % BLOCKSIZE; n--; ) /* if any partial block left */
566 {
567 result[n] ^= x[n];
568 if (n == 0)
569 {
570 mix( seed, result );
571 }
572 }
573}
574#endif
575
576#if CMAC | SIV | EAX | OCB
577
578/** calculate CMAC of input data using pre-calculated keys: K1 (D) and K2 (Q) */
579static void cMac( const block_t K1, const block_t K2,
580 const void* data, const size_t dataSize, block_t mac )
581{
582 const uint8_t s = dataSize ? (dataSize - 1) % BLOCKSIZE + 1 : 0;
583 const uint8_t *lastcut = s ? (uint8_t*) data + dataSize - s : &s, *k = K1;
584
585 xMac( data, dataSize - s, mac, &rijndaelEncrypt, mac );
586 if (s < BLOCKSIZE)
587 {
588 mac[s] ^= 0x80; /* pad( M_last; K1, K2 ) */
589 k = K2;
590 }
591 xorBlock( k, mac );
592 xMac( lastcut, s + !s, mac, &rijndaelEncrypt, mac );
593}
594
595/** calculate key-dependent constants D and Q using a given doubling function */
596static void getSubkeys( fdouble_t gfdouble, const char quad,
597 const uint8_t* key, block_t D, block_t Q )
598{
599 AES_setkey( key );
600 rijndaelEncrypt( D, D ); /* H or L_* = Enc(zeros) */
601 if (quad)
602 {
603 gfdouble( D ); /* D or L_$ = double(L_*) */
604 }
605 memcpy( Q, D, BLOCKSIZE );
606 gfdouble( Q ); /* Q or L_0 = double(L_$) */
607}
608#endif
609
610#ifdef AES_PADDING
611
612/** in ECB mode & CBC without CTS, the last (partial) block has to be padded. */
613static char padBlock( const uint8_t len, block_t block )
614{
615 uint8_t n = BLOCKSIZE - len, *p = &block[len];
616
617#if AES_PADDING
618 memset( p, n * (AES_PADDING != 2), n );
619 *p ^= (0x80) * (AES_PADDING == 2); /* either PKCS#7 / IEC7816-4 */
620#else
621 memset( p, 0, n % BLOCKSIZE ); /* default (zero) padding */
622#endif
623 return len || AES_PADDING;
624}
625#endif
626
627
628/*----------------------------------------------------------------------------*\
629 ECB-AES (electronic codebook mode) functions
630\*----------------------------------------------------------------------------*/
631#if IMPLEMENT(ECB)
632/**
633 * @brief encrypt the input plaintext using ECB-AES block-cipher method
634 * @param key encryption key with a fixed size specified by KEYSIZE
635 * @param pntxt input plaintext buffer
636 * @param ptextLen size of plaintext in bytes
637 * @param crtxt resulting cipher-text buffer
638 */
639void SPP_EXTERNAL_ENCRYPTION_ecbEncrypt( const uint8_t* key,
640 const void* pntxt, const size_t ptextLen, void* crtxt )
641{
642 uint8_t* y;
643 count_t n = ptextLen / BLOCKSIZE; /* number of full blocks */
644 memcpy( crtxt, pntxt, ptextLen ); /* copy plaintext to output */
645
646 AES_setkey( key );
647 for (y = crtxt; n--; y += BLOCKSIZE)
648 {
649 rijndaelEncrypt( y, y ); /* C = Enc(P) */
650 }
651 if (padBlock( ptextLen % BLOCKSIZE, y ))
652 {
653 rijndaelEncrypt( y, y );
654 }
655 BURN( RoundKey );
656}
657
658/**
659 * @brief decrypt the input ciphertext using ECB-AES block-cipher method
660 * @param key decryption key with a fixed size specified by KEYSIZE
661 * @param crtxt input ciphertext buffer
662 * @param crtxtLen size of ciphertext in bytes
663 * @param pntxt resulting plaintext buffer
664 * @return error if the ciphertext has a partial block
665 */
666char SPP_EXTERNAL_ENCRYPTION_ecbDecrypt( const uint8_t* key,
667 const void* crtxt, const size_t crtxtLen, void* pntxt )
668{
669 uint8_t* y;
670 count_t n = crtxtLen / BLOCKSIZE;
671 memcpy( pntxt, crtxt, crtxtLen ); /* do in-place decryption */
672
673 AES_setkey( key );
674 for (y = pntxt; n--; y += BLOCKSIZE)
675 {
676 rijndaelDecrypt( y, y ); /* P = Dec(C) */
677 }
678 BURN( RoundKey );
679
680 /* if padding is enabled, check whether the result is properly padded. error
681 * must be thrown if it's not. here we skip that and just check the size. */
682 return crtxtLen % BLOCKSIZE ? M_DECRYPTION_ERROR : M_SUCCESS;
683}
684#endif /* ECB */
685
686
687/*----------------------------------------------------------------------------*\
688 CBC-AES (cipher block chaining) functions
689\*----------------------------------------------------------------------------*/
690#if IMPLEMENT(CBC)
691/**
692 * @brief encrypt the input plaintext using CBC-AES block-cipher method
693 * @param key encryption key with a fixed size specified by KEYSIZE
694 * @param iVec initialization vector
695 * @param pntxt input plaintext buffer
696 * @param ptextLen size of plaintext in bytes
697 * @param crtxt resulting cipher-text buffer
698 * @return error in CTS mode, if plaintext is a single partial block
699 */
700char SPP_EXTERNAL_ENCRYPTION_cbcEncrypt( const uint8_t* key, const block_t iVec,
701 const void* pntxt, const size_t ptextLen, void* crtxt )
702{
703 uint8_t const* iv = iVec;
704 uint8_t r = ptextLen % BLOCKSIZE, *y;
705 count_t n = ptextLen / BLOCKSIZE;
706
707#if CTS
708 if (n > 1 && !r && --n) r = BLOCKSIZE; /* CS3 ciphertext stealing */
709
710 if (n == 0) return M_DATALENGTH_ERROR; /* data size >= BLOCKSIZE */
711#endif
712 memcpy( crtxt, pntxt, ptextLen ); /* do in-place encryption */
713
714 AES_setkey( key );
715 for (y = crtxt; n--; y += BLOCKSIZE)
716 {
717 xorBlock( iv, y ); /* C = Enc(IV ^ P) */
718 rijndaelEncrypt( y, y ); /* IV_next = C */
719 iv = y;
720 }
721#if CTS
722 if (r)
723 {
724 block_t L = { 0 };
725 memcpy( L, y, r ); /* backup the last chunk */
726 memcpy( y, y - BLOCKSIZE, r ); /* 'steal' the cipher-text */
727 y -= BLOCKSIZE; /* ..to fill the last chunk */
728 iv = L;
729#else
730 if (padBlock( r, y ))
731 {
732#endif
733 xorBlock( iv, y );
734 rijndaelEncrypt( y, y );
735 }
736 BURN( RoundKey );
737 return M_SUCCESS;
738}
739
740/**
741 * @brief decrypt the input ciphertext using CBC-AES block-cipher method
742 * @param key decryption key with a fixed size specified by KEYSIZE
743 * @param iVec initialization vector
744 * @param crtxt input ciphertext buffer
745 * @param crtxtLen size of ciphertext in bytes
746 * @param pntxt resulting plaintext buffer
747 * @return error if the size of ciphertext is not a valid value
748 */
749char SPP_EXTERNAL_ENCRYPTION_cbcDecrypt( const uint8_t* key, const block_t iVec,
750 const void* crtxt, const size_t crtxtLen, void* pntxt )
751{
752 uint8_t const *x = crtxt, *iv = iVec;
753 uint8_t r = crtxtLen % BLOCKSIZE, *y;
754 count_t n = crtxtLen / BLOCKSIZE;
755
756#if CTS
757 if (n > 1 && !r && --n) r = BLOCKSIZE;
758
759 if (n == 0) return M_DATALENGTH_ERROR;
760#else
761 if (r != 0) return M_DATALENGTH_ERROR;
762#endif
763 n -= r > 0; /* hold last 2 blocks in CTS */
764
765 AES_setkey( key );
766 for (y = pntxt; n--; y += BLOCKSIZE)
767 {
768 rijndaelDecrypt( x, y ); /* P = Dec(C) ^ IV */
769 xorBlock( iv, y ); /* IV_next = C */
770 iv = x;
771 x += BLOCKSIZE;
772#if CTS
773 }
774 if (r)
775 { /* last two blocks: {X, Z} */
776 const uint8_t* z = x + BLOCKSIZE;
777 mixThenXor( &rijndaelDecrypt, x, y, z, r, y + BLOCKSIZE );
778 memcpy( y, z, r );
779 rijndaelDecrypt( y, y ); /* P2 = Z ^ Dec(X) = Z ^ Y */
780 xorBlock( iv, y ); /* P1 = IV ^ Dec(Z | *Y) */
781#endif
782 }
783 BURN( RoundKey );
784 return M_SUCCESS;
785}
786#endif /* CBC */
787
788
789/*----------------------------------------------------------------------------*\
790 CFB-AES (cipher feedback) functions
791\*----------------------------------------------------------------------------*/
792#if IMPLEMENT(CFB)
793/**
794 * @brief the general scheme of CFB-AES block-ciphering algorithm
795 * @param key encryption key with a fixed size specified by KEYSIZE
796 * @param iVec initialization vector
797 * @param mode mode of operation: (1) to encrypt, (0) to decrypt
798 * @param input buffer of the input plain/cipher-text
799 * @param dataSize size of input in bytes
800 * @param output buffer of the resulting cipher/plain-text
801 */
802static void CFB_cipher( const uint8_t* key, const block_t iVec, const char mode,
803 const void* input, const size_t dataSize, void* output )
804{
805 uint8_t const *iv = iVec, *x = input;
806 uint8_t* y;
807 block_t tmp;
808 count_t n = dataSize / BLOCKSIZE; /* number of full blocks */
809
810 AES_setkey( key );
811 for (y = output; n--; y += BLOCKSIZE)
812 {
813 rijndaelEncrypt( iv, y ); /* both in en[de]cryption: */
814 xorBlock( x, y ); /* Y = Enc(IV) ^ X */
815 iv = mode ? y : x; /* IV_next = Ciphertext */
816 x += BLOCKSIZE;
817 }
818 mixThenXor( &rijndaelEncrypt, iv, tmp, x, dataSize % BLOCKSIZE, y );
819 BURN( RoundKey );
820}
821
822/**
823 * @brief encrypt the input plaintext using CFB-AES block-cipher method
824 * @param key encryption key with a fixed size specified by KEYSIZE
825 * @param iVec initialization vector
826 * @param pntxt input plaintext buffer
827 * @param ptextLen size of plaintext in bytes
828 * @param crtxt resulting cipher-text buffer
829 */
830void SPP_EXTERNAL_ENCRYPTION_cfbEncrypt( const uint8_t* key, const block_t iVec,
831 const void* pntxt, const size_t ptextLen, void* crtxt )
832{
833 CFB_cipher( key, iVec, 1, pntxt, ptextLen, crtxt );
834}
835
836/**
837 * @brief decrypt the input ciphertext using CFB-AES block-cipher method
838 * @param key decryption key with a fixed size specified by KEYSIZE
839 * @param iVec initialization vector
840 * @param crtxt input ciphertext buffer
841 * @param crtxtLen size of ciphertext in bytes
842 * @param pntxt resulting plaintext buffer
843 */
844void SPP_EXTERNAL_ENCRYPTION_cfbDecrypt( const uint8_t* key, const block_t iVec,
845 const void* crtxt, const size_t crtxtLen, void* pntxt )
846{
847 CFB_cipher( key, iVec, 0, crtxt, crtxtLen, pntxt );
848}
849#endif /* CFB */
850
851
852/*----------------------------------------------------------------------------*\
853 OFB-AES (output feedback) functions
854\*----------------------------------------------------------------------------*/
855#if IMPLEMENT(OFB)
856/**
857 * @brief encrypt the input plaintext using OFB-AES block-cipher method
858 * @param key encryption key with a fixed size specified by KEYSIZE
859 * @param iVec initialization vector
860 * @param pntxt input plaintext buffer
861 * @param ptextLen size of plaintext in bytes
862 * @param crtxt resulting cipher-text buffer
863 */
864void SPP_EXTERNAL_ENCRYPTION_ofbEncrypt( const uint8_t* key, const block_t iVec,
865 const void* pntxt, const size_t ptextLen, void* crtxt )
866{
867 count_t n = ptextLen / BLOCKSIZE;
868 uint8_t* y;
869 block_t iv;
870
871 memcpy( iv, iVec, sizeof iv );
872 memcpy( crtxt, pntxt, ptextLen ); /* i.e. in-place encryption */
873
874 AES_setkey( key );
875 for (y = crtxt; n--; y += BLOCKSIZE)
876 {
877 rijndaelEncrypt( iv, iv ); /* IV_next = Enc(IV) */
878 xorBlock( iv, y ); /* C = IV_next ^ P */
879 }
880 mixThenXor( &rijndaelEncrypt, iv, iv, y, ptextLen % BLOCKSIZE, y );
881 BURN( RoundKey );
882}
883
884/**
885 * @brief decrypt the input ciphertext using OFB-AES block-cipher method
886 * @param key decryption key with a fixed size specified by KEYSIZE
887 * @param iVec initialization vector
888 * @param crtxt input ciphertext buffer
889 * @param crtxtLen size of ciphertext in bytes
890 * @param pntxt resulting plaintext buffer
891 */
892void SPP_EXTERNAL_ENCRYPTION_ofbDecrypt( const uint8_t* key, const block_t iVec,
893 const void* crtxt, const size_t crtxtLen, void* pntxt )
894{
895 SPP_EXTERNAL_ENCRYPTION_ofbEncrypt( key, iVec, crtxt, crtxtLen, pntxt );
896}
897#endif /* OFB */
898
899
900/*----------------------------------------------------------------------------*\
901 Parallelizable, counter-based modes of AES: demonstrating the main idea
902 + How to use it in a simple, non-authenticated API
903\*----------------------------------------------------------------------------*/
904#if CTR
905
907{
909 SIV_CTR = 'S', /* RFC-5297 */
910 SIVGCM_CTR = 'S' & 'G', /* RFC-8452 */
911 CCM_GCM = 'C' | 'G' /* either CCM or GCM */
912};
913
914/**
915 * @brief the general scheme of operation in block-counter mode
916 * @param iCtr initialized counter block
917 * @param mode specifies the "counter based" block-cipher or AEAD mode
918 * @param input buffer of the input plain/cipher-text
919 * @param dataSize size of input in bytes
920 * @param output buffer of the resulting cipher/plain-text
921 */
922static void CTR_cipher( const block_t iCtr, const char mode,
923 const void* input, const size_t dataSize, void* output )
924{
925 block_t cnt, enc;
926 count_t n = dataSize / BLOCKSIZE;
927 uint8_t index = LAST, *y;
928
929 memcpy( output, input, dataSize ); /* do in-place en/decryption */
930 memcpy( cnt, iCtr, sizeof cnt );
931
932 switch (mode)
933 {
934 case SIV_CTR:
935 cnt[+8] &= 0x7F; /* clear 2 bits in SIV mode */
936 cnt[12] &= 0x7F;
937 break;
938 case SIVGCM_CTR:
939 cnt[LAST] |= 0x80; /* set 1 bit of L.E counter */
940 index = 0;
941 break;
942 case CCM_GCM:
943 incBlock( cnt, index ); /* pre-increment in CCM/GCM */
944 break;
945 }
946 for (y = output; n--; y += BLOCKSIZE)
947 {
948 rijndaelEncrypt( cnt, enc ); /* both in en[de]cryption: */
949 xorBlock( enc, y ); /* Y = Enc(Ctr) ^ X */
950 incBlock( cnt, index ); /* Ctr_next = Ctr + 1 */
951 }
952 mixThenXor( &rijndaelEncrypt, cnt, cnt, y, dataSize % BLOCKSIZE, y );
953}
954#endif
955
956#if IMPLEMENT(CTR_NA)
957/**
958 * @brief encrypt the input plaintext using CTR-AES block-cipher method
959 * @param key encryption key with a fixed size specified by KEYSIZE
960 * @param iv initialization vector a.k.a. nonce
961 * @param pntxt input plaintext buffer
962 * @param ptextLen size of plaintext in bytes
963 * @param crtxt resulting cipher-text buffer
964 */
965void SPP_EXTERNAL_ENCRYPTION_ctrEncrypt( const uint8_t* key, const uint8_t* iv,
966 const void* pntxt, const size_t ptextLen, void* crtxt )
967{
968#if PRESET_COUNTER
969 uint8_t const* ctr = iv; /* block is pre-initialized */
970#else
971 block_t ctr = { 0 };
972 memcpy( ctr, iv, CTR_IV_LENGTH );
973
974 xorBEint( ctr, CTR_START_VALUE, LAST ); /* initialize the counter */
975#endif
976 AES_setkey( key );
977 CTR_cipher( ctr, CTR_DEFAULT, pntxt, ptextLen, crtxt );
978 BURN( RoundKey );
979}
980
981/**
982 * @brief decrypt the input ciphertext using CTR-AES block-cipher method
983 * @param key decryption key with a fixed size specified by KEYSIZE
984 * @param iv initialization vector a.k.a. nonce
985 * @param crtxt input ciphertext buffer
986 * @param crtxtLen size of ciphertext in bytes
987 * @param pntxt resulting plaintext buffer
988 */
989void SPP_EXTERNAL_ENCRYPTION_ctrDecrypt( const uint8_t* key, const uint8_t* iv,
990 const void* crtxt, const size_t crtxtLen, void* pntxt )
991{
992 SPP_EXTERNAL_ENCRYPTION_ctrEncrypt( key, iv, crtxt, crtxtLen, pntxt );
993}
994#endif /* CTR */
995
996
997/*----------------------------------------------------------------------------*\
998 XEX-AES based modes (xor-encrypt-xor): the basic idea
999 + main functions of XTS-AES (XEX Tweaked-codebook with ciphertext Stealing)
1000\*----------------------------------------------------------------------------*/
1001#if IMPLEMENT(XTS)
1002/**
1003 * @brief encrypt or decrypt a data unit with XTS method
1004 * @param keypair pair of encryption keys, each one has KEYSIZE bytes
1005 * @param mode mode of operation: encrypting (1) or decrypting (0)
1006 * @param tweak data unit identifier block, similar to nonce in CTR mode
1007 * @param sectid sector id: in case of a null tweak, use this instead
1008 * @param dataSize size of input data, to be encrypted/decrypted
1009 * @param storage result of encryption/decryption process
1010 * @return error if the data is too small (less than one block)
1011 */
1012static char XTS_cipher( const uint8_t* keypair, const char mode,
1013 const block_t tweak, const size_t sectid,
1014 const size_t dataSize, void* storage )
1015{
1016 fmix_t cipher = mode ? &rijndaelEncrypt : &rijndaelDecrypt;
1017 uint8_t r = dataSize % BLOCKSIZE, *y;
1018 count_t n = dataSize / BLOCKSIZE + !r;
1019 block_t T;
1020
1021 if (dataSize < BLOCKSIZE) return M_DATALENGTH_ERROR;
1022
1023 if (~sectid != 0)
1024 { /* the `i` block is either */
1025 memset( T, 0, sizeof T ); /* ..a little-endian number */
1026 copyLint( T, sectid, 0 ); /* ..or a byte array (tweak) */
1027 }
1028 else
1029 {
1030 memcpy( T, tweak, sizeof T );
1031 }
1032 AES_setkey( keypair + KEYSIZE ); /* T = encrypt `i` with key2 */
1033 rijndaelEncrypt( T, T );
1034
1035 AES_setkey( keypair ); /* now key1 is cipher key */
1036 for (y = storage; --n; y += BLOCKSIZE)
1037 { /* XEX: xor-encrypt-xor */
1038 xorBlock( T, y );
1039 cipher( y, y );
1040 xorBlock( T, y ); /* Y = T ^ Cipher( T ^ X ) */
1041 doubleLblock( T ); /* T_next = alpha · T */
1042 }
1043 if (r)
1044 { /* XTS: ciphertext stealing */
1045 block_t L;
1046 memcpy( L, T, sizeof L );
1047 doubleLblock( mode ? T : L ); /* T = α·L or L = α·T */
1048
1049 xorBlock( L, y );
1050 cipher( y, y );
1051 xorBlock( L, y );
1052 memcpy( L, y, sizeof L );
1053 memcpy( y, y + BLOCKSIZE, r ); /* 'steal' the cipher-text */
1054 memcpy( y + BLOCKSIZE, L, r ); /* ..to fill the last chunk */
1055
1056 xorBlock( T, y );
1057 cipher( y, y ); /* encrypt or decrypt the */
1058 xorBlock( T, y ); /* ..block we stole from */
1059 }
1060 BURN( RoundKey );
1061 return M_SUCCESS;
1062}
1063
1064/**
1065 * @brief encrypt the input plaintext using XTS-AES block-cipher method
1066 * @param keys two-part encryption key with a fixed size of 2*KEYSIZE
1067 * @param tweak tweak bytes of data unit, a.k.a sector ID (little-endian)
1068 * @param pntxt input plaintext buffer
1069 * @param ptextLen size of plaintext in bytes
1070 * @param crtxt resulting cipher-text buffer
1071 * @return error if plaintext is a single partial block
1072 */
1073char SPP_EXTERNAL_ENCRYPTION_xtsEncrypt( const uint8_t* keys, const uint8_t* tweak,
1074 const void* pntxt, const size_t ptextLen, void* crtxt )
1075{
1076 memcpy( crtxt, pntxt, ptextLen ); /* do in-place encryption */
1077 return XTS_cipher( keys, 1, tweak, ~0, ptextLen, crtxt );
1078}
1079
1080/**
1081 * @brief encrypt the input ciphertext using XTS-AES block-cipher method
1082 * @param keys two-part encryption key with a fixed size of 2*KEYSIZE
1083 * @param tweak tweak bytes of data unit, a.k.a sector ID (little-endian)
1084 * @param crtxt input ciphertext buffer
1085 * @param crtxtLen size of ciphertext in bytes
1086 * @param pntxt resulting plaintext buffer
1087 * @return error if ciphertext is a single partial block
1088 */
1089char SPP_EXTERNAL_ENCRYPTION_xtsDecrypt( const uint8_t* keys, const uint8_t* tweak,
1090 const void* crtxt, const size_t crtxtLen, void* pntxt )
1091{
1092 memcpy( pntxt, crtxt, crtxtLen ); /* in-place decryption */
1093 return XTS_cipher( keys, 0, tweak, ~0, crtxtLen, pntxt );
1094}
1095#endif /* XTS */
1096
1097
1098/*----------------------------------------------------------------------------*\
1099 CMAC-AES (cipher-based message authentication code): main function
1100\*----------------------------------------------------------------------------*/
1101#if IMPLEMENT(CMAC)
1102/**
1103 * @brief derive the AES-CMAC of input data using an encryption key
1104 * @param key AES encryption key
1105 * @param data buffer of input data
1106 * @param dataSize size of data in bytes
1107 * @param mac calculated CMAC hash
1108 */
1109void SPP_EXTERNAL_ENCRYPTION_cmac( const uint8_t* key,
1110 const void* data, const size_t dataSize, block_t mac )
1111{
1112 block_t K1 = { 0 }, K2;
1113 memcpy( mac, K1, sizeof K1 ); /* initialize mac */
1114
1115 getSubkeys( &doubleBblock, 1, key, K1, K2 );
1116 cMac( K1, K2, data, dataSize, mac );
1117 BURN( RoundKey );
1118}
1119#endif /* CMAC */
1120
1121
1122/*----------------------------------------------------------------------------*\
1123 GCM-AES (Galois counter mode): authentication with GMAC & main functions
1124\*----------------------------------------------------------------------------*/
1125#if IMPLEMENT(GCM)
1126
1127/** calculate G-Hash of ciphertext and AAD using an authentication subkey `H` */
1128static void gHash( const block_t H, const void* aData, const void* crtxt,
1129 const size_t aDataLen, const size_t crtxtLen, block_t gh )
1130{
1131 block_t len = { 0 };
1132 xorBEint( len, aDataLen * 8, MIDST );
1133 xorBEint( len, crtxtLen * 8, LAST ); /* save bit-sizes into len */
1134
1135 xMac( aData, aDataLen, H, &mulGF128, gh ); /* first digest AAD, then */
1136 xMac( crtxt, crtxtLen, H, &mulGF128, gh ); /* ..ciphertext, and then */
1137 xMac( len, sizeof len, H, &mulGF128, gh ); /* ..bit sizes into GHash */
1138}
1139
1140/** encrypt zeros to get the authentication subkey (H), and construct the IV. */
1141static void GCMsetup( const uint8_t* key,
1142 const uint8_t* nonce, block_t auKey, block_t iv )
1143{
1144 AES_setkey( key );
1145 rijndaelEncrypt( auKey, auKey ); /* auKey = Enc( zero block ) */
1146 if (GCM_NONCE_LEN != 12)
1147 {
1148 gHash( auKey, NULL, nonce, 0, GCM_NONCE_LEN, iv );
1149 return;
1150 }
1151 memcpy( iv, nonce, 12 );
1152 iv[LAST] = 1;
1153}
1154
1155/**
1156 * @brief encrypt the input plaintext using GCM-AES block-cipher method
1157 * @param key encryption key with a fixed size specified by KEYSIZE
1158 * @param nonce a.k.a initialization vector with fixed size: GCM_NONCE_LEN
1159 * @param aData additional authentication data
1160 * @param aDataLen size of additional authentication data
1161 * @param pntxt input plain-text buffer
1162 * @param ptextLen size of plaintext in bytes
1163 * @param crtxt resulting cipher-text buffer + message authentication tag
1164 */
1165void SPP_EXTERNAL_ENCRYPTION_gcmEncrypt( const uint8_t* key, const uint8_t* nonce,
1166 const void* aData, const size_t aDataLen,
1167 const void* pntxt, const size_t ptextLen, void* crtxt )
1168{
1169 char* tag = (char*) crtxt + ptextLen;
1170 block_t H = { 0 }, iv = { 0 }, G = { 0 };
1171
1172 GCMsetup( key, nonce, H, iv ); /* get IV & auth. subkey H */
1173 CTR_cipher( iv, CCM_GCM, pntxt, ptextLen, crtxt );
1174 rijndaelEncrypt( iv, iv );
1175 BURN( RoundKey );
1176
1177 gHash( H, aData, crtxt, aDataLen, ptextLen, G );
1178 xorBlock( iv, G );
1179 memcpy( tag, G, GCM_TAG_LEN ); /* GMAC = Enc(iv) ^ G-HASH */
1180}
1181
1182/**
1183 * @brief decrypt the input ciphertext using GCM-AES block-cipher method
1184 * @param key decryption key with a fixed size specified by KEYSIZE
1185 * @param nonce a.k.a initialization vector with fixed size: GCM_NONCE_LEN
1186 * @param aData additional authentication data
1187 * @param aDataLen size of additional authentication data
1188 * @param crtxt input cipher-text buffer + appended authentication tag
1189 * @param crtxtLen size of ciphertext, excluding tag
1190 * @param pntxt resulting plaintext buffer
1191 * @return whether message authentication/decryption was successful
1192 */
1193char SPP_EXTERNAL_ENCRYPTION_gcmDecrypt( const uint8_t* key, const uint8_t* nonce,
1194 const void* aData, const size_t aDataLen,
1195 const void* crtxt, const size_t crtxtLen, void* pntxt )
1196{
1197 const char* tag = (char*) crtxt + crtxtLen;
1198 block_t H = { 0 }, iv = { 0 }, G = { 0 };
1199
1200 GCMsetup( key, nonce, H, iv );
1201 gHash( H, aData, crtxt, aDataLen, crtxtLen, G );
1202 rijndaelEncrypt( iv, H );
1203 xorBlock( H, G ); /* tag = Enc(iv) ^ G-HASH */
1204
1205 if (memcmp_s( tag, G, GCM_TAG_LEN ))
1206 { /* compare tags and */
1207 BURN( RoundKey ); /* ..proceed if they match */
1209 }
1210 CTR_cipher( iv, CCM_GCM, crtxt, crtxtLen, pntxt );
1211 BURN( RoundKey );
1212 return M_SUCCESS;
1213}
1214#endif /* GCM */
1215
1216
1217/*----------------------------------------------------------------------------*\
1218 CCM-AES (counter with CBC-MAC): CBC-MAC authentication & main functions
1219\*----------------------------------------------------------------------------*/
1220#if IMPLEMENT(CCM)
1221
1222/** this function calculates the CBC-MAC of plaintext and authentication data */
1223static void CCMtag( const block_t iv, const void* aData, const void* pntxt,
1224 const size_t aDataLen, const size_t ptextLen, block_t M )
1225{
1226 block_t A = { 0 };
1227 uint8_t p = 1, s = 0;
1228
1229 memcpy( M, iv, BLOCKSIZE ); /* initialize CBC-MAC */
1230 M[0] |= (CCM_TAG_LEN - 2) << 2; /* set some flags on M_* */
1231 xorBEint( M, ptextLen, LAST ); /* copy data size into M_* */
1232
1233 if (aDataLen) /* construct the 'A' block */
1234 {
1235 M[0] |= 0x40;
1236 rijndaelEncrypt( M, M ); /* flag M_* and encrypt it */
1237 if (aDataLen > 0xFEFFL)
1238 { /* assuming aDataLen < 2^32 */
1239 p += 4;
1240 A[0] = 0xFF, A[1] = 0xFE; /* prepend FFFE to aDataLen */
1241 }
1242 xorBEint( A, aDataLen, p ); /* copy aDataLen into A */
1243 s = sizeof A - (++p);
1244 memcpy( A + p, aData, aDataLen < s ? aDataLen : s );
1245 }
1246
1247 /* digest the first s bytes of aData, the rest of it, and then plaintext: */
1248 xMac( A, sizeof A, M, &rijndaelEncrypt, M );
1249 if (aDataLen > s)
1250 {
1251 xMac( (char*) aData + s, aDataLen - s, M, &rijndaelEncrypt, M );
1252 }
1253 xMac( pntxt, ptextLen, M, &rijndaelEncrypt, M );
1254
1255 rijndaelEncrypt( iv, A ); /* tag = Enc(iv) ^ CBCMac */
1256 xorBlock( A, M );
1257}
1258
1259/**
1260 * @brief encrypt the input plaintext using CCM-AES block-cipher method
1261 * @param key encryption key with a fixed size specified by KEYSIZE
1262 * @param nonce a.k.a initialization vector with fixed size: CCM_NONCE_LEN
1263 * @param aData additional authentication data
1264 * @param aDataLen size of additional authentication data
1265 * @param pntxt input plain-text buffer
1266 * @param ptextLen size of plaintext in bytes
1267 * @param crtxt resulting cipher-text buffer + message authentication tag
1268 */
1269void SPP_EXTERNAL_ENCRYPTION_ccmEncrypt( const uint8_t* key, const uint8_t* nonce,
1270 const void* aData, const size_t aDataLen,
1271 const void* pntxt, const size_t ptextLen, void* crtxt )
1272{
1273 char* tag = (char*) crtxt + ptextLen;
1274 block_t iv = { 14 - CCM_NONCE_LEN, 0 }, C;
1275
1276 memcpy( iv + 1, nonce, CCM_NONCE_LEN );
1277 AES_setkey( key );
1278 CCMtag( iv, aData, pntxt, aDataLen, ptextLen, C );
1279 CTR_cipher( iv, CCM_GCM, pntxt, ptextLen, crtxt );
1280 BURN( RoundKey );
1281
1282 memcpy( tag, C, CCM_TAG_LEN );
1283}
1284
1285/**
1286 * @brief decrypt the input ciphertext using CCM-AES block-cipher method
1287 * @param key decryption key with a fixed size specified by KEYSIZE
1288 * @param nonce a.k.a initialization vector with fixed size: CCM_NONCE_LEN
1289 * @param aData additional authentication data
1290 * @param aDataLen size of additional authentication data
1291 * @param crtxt input cipher-text buffer + appended authentication tag
1292 * @param crtxtLen size of ciphertext, excluding tag
1293 * @param pntxt resulting plaintext buffer
1294 * @return whether message decryption/authentication was successful
1295 */
1296char SPP_EXTERNAL_ENCRYPTION_ccmDecrypt( const uint8_t* key, const uint8_t* nonce,
1297 const void* aData, const size_t aDataLen,
1298 const void* crtxt, const size_t crtxtLen, void* pntxt )
1299{
1300 const char* tag = (char*) crtxt + crtxtLen;
1301 block_t iv = { 14 - CCM_NONCE_LEN, 0 }, C;
1302
1303 memcpy( iv + 1, nonce, CCM_NONCE_LEN );
1304 AES_setkey( key );
1305 CTR_cipher( iv, CCM_GCM, crtxt, crtxtLen, pntxt );
1306 CCMtag( iv, aData, pntxt, aDataLen, crtxtLen, C );
1307 BURN( RoundKey );
1308
1309 if (memcmp_s( tag, C, CCM_TAG_LEN ))
1310 {
1311 SABOTAGE( pntxt, crtxtLen ); /* invalid tag: clear pntxt */
1313 }
1314 return M_SUCCESS;
1315}
1316#endif /* CCM */
1317
1318
1319/*----------------------------------------------------------------------------*\
1320 SIV-AES (synthetic init-vector): nonce synthesis & main functions
1321\*----------------------------------------------------------------------------*/
1322#if IMPLEMENT(SIV)
1323
1324/** calculate the CMAC* of AAD unit(s), then plaintext, and synthesize the IV */
1325static void S2V( const uint8_t* key, const void* aData, const void* pntxt,
1326 const size_t aDataLen, const size_t ptextLen, block_t IV )
1327{
1328 block_t K[2] = { { 0 } }, Y;
1329 uint8_t r, *Q = K[1];
1330
1331 memcpy( IV, *K, BLOCKSIZE ); /* initialize/clear IV */
1332 getSubkeys( &doubleBblock, 1, key, *K, Q );
1333 rijndaelEncrypt( *K, Y ); /* Y_0 = CMAC(zero block) */
1334
1335 /* in case of multiple AAD units, each one must be handled in a similar way.
1336 * for example, let aData be a 2-D array and aDataLen a null-terminated one.
1337 * then instead of `if (aDataLen) { cMac(*K, Q, aData, aDataLen, IV)` write:
1338 * for (r = 0; *aDataLen; ) { cMac( *K, Q, aData[r++], *aDataLen++, IV ); */
1339 if (aDataLen)
1340 {
1341 cMac( *K, Q, aData, aDataLen, IV );
1342 doubleBblock( Y ); /* Y_$ = double( Y_{i-1} ) */
1343 xorBlock( IV, Y ); /* Y_i = Y_$ ^ CMAC(AAD_i) */
1344 memset( IV, 0, BLOCKSIZE );
1345 }
1346 if (ptextLen < sizeof Y)
1347 { /* for short messages: */
1348 doubleBblock( Y ); /* Y = double( Y_n ) */
1349 r = 0;
1350 }
1351 else if ((r = ptextLen % sizeof Y) > 0)
1352 {
1353 memset( *K, 0, BLOCKSIZE );
1354 }
1355 xorBlock( Y, *K + r );
1356 cMac( *K, *K, pntxt, ptextLen - r, IV ); /* CMAC*( Y xor_end MSG ) */
1357
1358 if (r == 0) return;
1359
1360 cMac( NULL, Q, (char*) pntxt + ptextLen - r, r, IV );
1361}
1362
1363/**
1364 * @brief encrypt the input plaintext using SIV-AES block-cipher method
1365 * @param keys two-part encryption key with a fixed size of 2*KEYSIZE
1366 * @param aData additional authentication data
1367 * @param aDataLen size of additional authentication data
1368 * @param pntxt input plain-text buffer
1369 * @param ptextLen size of plaintext in bytes
1370 * @param iv synthesized I.V block, typically prepended to ciphertext
1371 * @param crtxt resulting cipher-text buffer
1372 */
1373void SPP_EXTERNAL_ENCRYPTION_sivEncrypt( const uint8_t* keys,
1374 const void* aData, const size_t aDataLen,
1375 const void* pntxt, const size_t ptextLen,
1376 block_t iv, void* crtxt )
1377{
1378 S2V( keys, aData, pntxt, aDataLen, ptextLen, iv );
1379 AES_setkey( keys + KEYSIZE );
1380 CTR_cipher( iv, SIV_CTR, pntxt, ptextLen, crtxt );
1381 BURN( RoundKey );
1382}
1383
1384/**
1385 * @brief decrypt the input ciphertext using SIV-AES block-cipher method
1386 * @param keys two-part encryption key with a fixed size of 2*KEYSIZE
1387 * @param iv provided I.V block to validate
1388 * @param aData additional authentication data
1389 * @param aDataLen size of additional authentication data
1390 * @param crtxt input cipher-text buffer
1391 * @param crtxtLen size of ciphertext in bytes
1392 * @param pntxt resulting plaintext buffer
1393 * @return whether message decryption/authentication was successful
1394 */
1395char SPP_EXTERNAL_ENCRYPTION_sivDecrypt( const uint8_t* keys, const block_t iv,
1396 const void* aData, const size_t aDataLen,
1397 const void* crtxt, const size_t crtxtLen, void* pntxt )
1398{
1399 block_t IV;
1400 AES_setkey( keys + KEYSIZE );
1401 CTR_cipher( iv, SIV_CTR, crtxt, crtxtLen, pntxt );
1402 S2V( keys, aData, pntxt, aDataLen, crtxtLen, IV );
1403 BURN( RoundKey );
1404
1405 if (memcmp_s( IV, iv, sizeof IV )) /* verify the synthesized IV */
1406 {
1407 SABOTAGE( pntxt, crtxtLen );
1409 }
1410 return M_SUCCESS;
1411}
1412#endif /* SIV */
1413
1414
1415/*----------------------------------------------------------------------------*\
1416 SIV-GCM-AES (Galois counter mode with synthetic i.v)
1417 authentication & i.v synthesis with polyval + main functions
1418\*----------------------------------------------------------------------------*/
1419#if IMPLEMENT(GCM_SIV)
1420
1421/** calculate the POLYVAL of plaintext and AAD using authentication subkey H. */
1422static void polyval( const block_t H, const void* aData, const void* pntxt,
1423 const size_t aDataLen, const size_t ptextLen, block_t pv )
1424{
1425 block_t len = { 0 }; /* save bit-sizes into len */
1426 copyLint( len, aDataLen * 8, 0 );
1427 copyLint( len, ptextLen * 8, HB );
1428
1429 xMac( aData, aDataLen, H, &dotGF128, pv ); /* first digest AAD, then */
1430 xMac( pntxt, ptextLen, H, &dotGF128, pv ); /* ..plaintext, and then */
1431 xMac( len, sizeof len, H, &dotGF128, pv ); /* ..bit sizes into POLYVAL */
1432}
1433
1434/** derive the pair of authentication-encryption-keys from main key and nonce */
1435static void GCM_SIVsetup( const uint8_t* key, const uint8_t* nonce, block_t AK )
1436{
1437 uint8_t iv[5 * HB + KEYSIZE], *h, *k;
1438 k = h = iv + BLOCKSIZE;
1439 memcpy( iv + 4, nonce, SIVGCM_NONCE_LEN );
1440
1441 AES_setkey( key );
1442 for (*(int32_t*) iv = 0; *iv < 2 + Nk / 2; ++*iv)
1443 {
1444 rijndaelEncrypt( iv, k ); /* encrypt & take half, then */
1445 k += HB; /* ..increment iv's LSB */
1446 }
1447 AES_setkey( k - KEYSIZE ); /* set the main cipher-key */
1448 memcpy( AK, h, BLOCKSIZE ); /* take authentication key */
1449}
1450
1451/** get the tag in GCM-SIV mode, given the nonce and calculated POLYVAL block */
1452static void GCM_SIVtag( const uint8_t* nonce, block_t pv, block_t tag )
1453{
1454 XOR64BITS( nonce[0], pv[0] ); /* xor POLYVAL with nonce */
1455 XOR32BITS( nonce[8], pv[8] );
1456 pv[LAST] &= 0x7F; /* clear one bit & encrypt, */
1457 rijndaelEncrypt( pv, tag );
1458}
1459
1460/**
1461 * @brief encrypt the input plaintext using SIV-GCM-AES block-cipher method
1462 * @param key encryption key with a fixed size specified by KEYSIZE
1463 * @param nonce provided 96-bit nonce
1464 * @param aData additional authentication data
1465 * @param aDataLen size of additional authentication data
1466 * @param pntxt input plain-text buffer
1467 * @param ptextLen size of plaintext in bytes
1468 * @param crtxt resulting cipher-text buffer + message authentication tag
1469 */
1470void SPP_EXTERNAL_ENCRYPTION_gcmSivEncrypt( const uint8_t* key, const uint8_t* nonce,
1471 const void* aData, const size_t aDataLen,
1472 const void* pntxt, const size_t ptextLen, void* crtxt )
1473{
1474 block_t P = { 0 };
1475 uint8_t *H, *tag = (uint8_t*) crtxt + ptextLen;
1476
1477 H = tag; /* use a pre-allocated space */
1478 GCM_SIVsetup( key, nonce, H );
1479 polyval( H, aData, pntxt, aDataLen, ptextLen, P );
1480 GCM_SIVtag( nonce, P, tag );
1481 CTR_cipher( tag, SIVGCM_CTR, pntxt, ptextLen, crtxt );
1482 BURN( RoundKey );
1483}
1484
1485/**
1486 * @brief decrypt the input ciphertext using SIV-GCM-AES block-cipher method
1487 * @param key decryption key with a fixed size specified by KEYSIZE
1488 * @param nonce provided 96-bit nonce
1489 * @param aData additional authentication data
1490 * @param aDataLen size of additional authentication data
1491 * @param crtxt input cipher-text buffer + appended authentication tag
1492 * @param crtxtLen size of ciphertext, excluding tag
1493 * @param pntxt resulting plaintext buffer
1494 * @return whether message decryption/authentication was successful
1495 */
1496char SPP_EXTERNAL_ENCRYPTION_gcmSivDecrypt( const uint8_t* key, const uint8_t* nonce,
1497 const void* aData, const size_t aDataLen,
1498 const void* crtxt, const size_t crtxtLen, void* pntxt )
1499{
1500 block_t H, P = { 0 };
1501 uint8_t const* tag = (uint8_t*) crtxt + crtxtLen;
1502
1503 GCM_SIVsetup( key, nonce, H ); /* get authentication subkey */
1504 CTR_cipher( tag, SIVGCM_CTR, crtxt, crtxtLen, pntxt );
1505 polyval( H, aData, pntxt, aDataLen, crtxtLen, P );
1506 GCM_SIVtag( nonce, P, P );
1507 BURN( RoundKey );
1508
1509 if (memcmp_s( tag, P, SIVGCM_TAG_LEN ))
1510 { /* tag verification failed */
1511 SABOTAGE( pntxt, crtxtLen );
1513 }
1514 return M_SUCCESS;
1515}
1516#endif /* GCM-SIV */
1517
1518
1519/*----------------------------------------------------------------------------*\
1520 EAX-AES (encrypt-then-authenticate-then-translate): OMAC & main functions
1521\*----------------------------------------------------------------------------*/
1522#if IMPLEMENT(EAX)
1523
1524/** this function calculates the OMAC of a data array using D (K1) and Q (K2) */
1525static void oMac( const uint8_t indx, const block_t D, const block_t Q,
1526 const void* data, const size_t dataSize, block_t mac )
1527{
1528#if EAXP
1529 if (!dataSize && indx)
1530 {
1531 memset( mac, 0, BLOCKSIZE );
1532 return; /* ignoring null ciphertext */
1533 }
1534 memcpy( mac, indx ? Q : D, BLOCKSIZE );
1535#else
1536 dataSize ? memset( mac, 0, BLOCKSIZE ) : memcpy( mac, D, BLOCKSIZE );
1537
1538 mac[LAST] ^= indx;
1539 rijndaelEncrypt( mac, mac );
1540
1541 if (!dataSize) return; /* then OMAC = CMAC( [t]_n ) */
1542#endif
1543 cMac( D, Q, data, dataSize, mac );
1544}
1545
1546/**
1547 * @brief encrypt the input plaintext using EAX-AES block-cipher method
1548 * @param key encryption key with a fixed size specified by KEYSIZE
1549 * @param nonce nonce with variable size in EAX' and fixed size in EAX
1550 * @param nonceLen size of the nonce byte array; should be non-zero in EAX'
1551 * @param aData additional authentication data; used in EAX only
1552 * @param aDataLen size of additional authentication data
1553 * @param pntxt input plain-text buffer
1554 * @param ptextLen size of plaintext in bytes
1555 * @param crtxt ciphertext result + auth. tag (4 bytes mac in EAX')
1556 */
1557void SPP_EXTERNAL_ENCRYPTION_eaxEncrypt( const uint8_t* key, const uint8_t* nonce,
1558#if EAXP
1559 const size_t nonceLen,
1560#else
1561 const void* aData, const size_t aDataLen,
1562#endif
1563 const void* pntxt, const size_t ptextLen, void* crtxt )
1564{
1565 char* tag = (char*) crtxt + ptextLen;
1566#if EAXP
1567 block_t D = { 0 }, Q, siv;
1568 getSubkeys( &doubleLblock, 1, key, D, Q );
1569
1570 oMac( 0, D, Q, nonce, nonceLen, siv ); /* N = CMAC'( nonce ) */
1571 COPYDWORD( siv[12], tag[0] );
1572 siv[12] &= 0x7F; /* clear 2 bits to get N' */
1573 siv[14] &= 0x7F;
1574 CTR_cipher( siv, CTR_DEFAULT, pntxt, ptextLen, crtxt );
1575
1576 oMac( 2, D, Q, crtxt, ptextLen, siv ); /* C' = CMAC'( ciphertext ) */
1577 XOR32BITS( siv[12], tag[0] ); /* mac = N ^ C' */
1578 BURN( RoundKey );
1579#else
1580 block_t D = { 0 }, Q, siv, mac;
1581 getSubkeys( &doubleBblock, 1, key, D, Q );
1582
1583 oMac( 0, D, Q, nonce, EAX_NONCE_LEN, siv ); /* N = OMAC(0; nonce) */
1584 oMac( 1, D, Q, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
1585 xorBlock( siv, mac );
1586 CTR_cipher( siv, CTR_DEFAULT, pntxt, ptextLen, crtxt );
1587
1588 oMac( 2, D, Q, crtxt, ptextLen, siv ); /* C = OMAC(2; ciphertext) */
1589 BURN( RoundKey );
1590 xorBlock( mac, siv ); /* tag = N ^ H ^ C */
1591 memcpy( tag, siv, EAX_TAG_LEN );
1592#endif
1593}
1594
1595/**
1596 * @brief decrypt the input ciphertext using EAX-AES block-cipher method
1597 * @param key decryption key with a fixed size specified by KEYSIZE
1598 * @param nonce nonce with variable size in EAX' and fixed size in EAX
1599 * @param nonceLen size of the nonce byte array; only used in EAX'
1600 * @param aData additional authentication data; for EAX only, not EAX'
1601 * @param aDataLen size of additional authentication data
1602 * @param crtxt input cipher-text buffer + appended authentication tag
1603 * @param crtxtLen size of cipher-text; excluding tag / 4-bytes mac in EAX'
1604 * @param pntxt resulting plaintext buffer
1605 * @return whether message authentication/decryption was successful
1606 */
1607char SPP_EXTERNAL_ENCRYPTION_eaxDecrypt( const uint8_t* key, const uint8_t* nonce,
1608#if EAXP
1609 const size_t nonceLen,
1610#else
1611 const void* aData, const size_t aDataLen,
1612#endif
1613 const void* crtxt, const size_t crtxtLen, void* pntxt )
1614{
1615 const char* tag = (char*) crtxt + crtxtLen;
1616 block_t D = { 0 }, Q, siv, mac;
1617#if EAXP
1618 getSubkeys( &doubleLblock, 1, key, D, Q );
1619
1620 oMac( 2, D, Q, crtxt, crtxtLen, mac ); /* C' = CMAC'( ciphertext ) */
1621 oMac( 0, D, Q, nonce, nonceLen, siv ); /* N = CMAC'( nonce ) */
1622 XOR32BITS( tag[+0], mac[12] );
1623 XOR32BITS( siv[12], mac[12] );
1624 siv[12] &= 0x7F;
1625 siv[14] &= 0x7F; /* clear 2 bits to get N' */
1626
1627 if (*(int32_t*) &mac[12] != 0) /* result of mac validation */
1628#else
1629 getSubkeys( &doubleBblock, 1, key, D, Q );
1630
1631 oMac( 2, D, Q, crtxt, crtxtLen, mac ); /* C = OMAC(2; ciphertext) */
1632 oMac( 1, D, Q, aData, aDataLen, siv ); /* H = OMAC(1; adata) */
1633 xorBlock( siv, mac );
1634 oMac( 0, D, Q, nonce, EAX_NONCE_LEN, siv ); /* N = OMAC(0; nonce) */
1635 xorBlock( siv, mac ); /* tag = N ^ H ^ C */
1636
1637 if (memcmp_s( tag, mac, EAX_TAG_LEN ))
1638#endif
1639 { /* authenticate then decrypt */
1640 BURN( RoundKey );
1642 }
1643 CTR_cipher( siv, CTR_DEFAULT, crtxt, crtxtLen, pntxt );
1644 BURN( RoundKey );
1645 return M_SUCCESS;
1646}
1647#endif /* EAX */
1648
1649
1650/*----------------------------------------------------------------------------*\
1651 OCB-AES (offset codebook mode): auxiliary and main functions
1652 + how to parallelize it by independent calculation of the offset blocks
1653\*----------------------------------------------------------------------------*/
1654#if IMPLEMENT(OCB)
1655
1656static void nop( const block_t x, block_t y ) {}
1657
1658/** Calculate the offset block (Δ_i) at a specified index, given the initial Δ_0
1659 * and L$ blocks. This method has minimum memory usage, but it might be slow. To
1660 * make it faster, pre-calculate all L_{i}s (avoid doubling inside the loop). */
1661static void getDelta( const count_t index,
1662 const block_t Ld, const block_t delta0, block_t delta )
1663{
1664 count_t mask, bit = 1;
1665 block_t L; /* Δ_i = Δ_{i-1} ^ L_ntz(i) */
1666
1667 memcpy( L, Ld, sizeof L ); /* initialize L_$ and Δ */
1668 memcpy( delta, delta0, BLOCKSIZE );
1669
1670 while ((mask = index - bit) < index)
1671 { /* L_0 = double( L_$ ), */
1672 doubleBblock( L ); /* L_k = double( L_{k-1} ) */
1673 mask &= bit <<= 1;
1674 if (!mask)
1675 {
1676 xorBlock( L, delta );
1677 }
1678 }
1679}
1680
1681/**
1682 * @brief encrypt or decrypt the data using OCB method
1683 * @param key encryption or decryption key
1684 * @param nonce byte array with a fixed size of OCB_NONCE_LEN
1685 * @param ptextLen size of input 'plain'text; which is zero in decryption
1686 * @param aDataLen size of additional authentication data
1687 * @param dataSize size of input data, to be encrypted/decrypted
1688 * @param aData additional authentication data
1689 * @param data result of encryption/decryption process
1690 * @param tag calculated tag from plaintext checksum, and PMAC of aData
1691 */
1692static void OCB_cipher( const uint8_t* key, const uint8_t* nonce,
1693 const size_t ptextLen, const size_t aDataLen,
1694 const size_t dataSize, const void* aData,
1695 void* data, block_t tag )
1696{
1697 fmix_t cipher = ptextLen ? &rijndaelEncrypt : &rijndaelDecrypt;
1698
1699 block_t offset[4] = { { 0 } }; /* [L_$] [L_*] [Ktop] [Δ_n] */
1700 uint8_t *y;
1701 uint8_t *Ld = offset[0], *Ls = offset[1], *kt = offset[2], *del = offset[3];
1702 count_t n = nonce[OCB_NONCE_LEN - 1] % 64, i;
1703 uint8_t const s = 8 - n % 8, *x = kt + n / 8;
1704
1705 memcpy( kt + BLOCKSIZE - OCB_NONCE_LEN, nonce, OCB_NONCE_LEN );
1706 kt[0] |= OCB_TAG_LEN << 4;
1707 kt[LAST - OCB_NONCE_LEN] |= 1; /* set 1 bit and clear last */
1708 kt[LAST] &= 0xC0; /* ..six bits of nonce (kt) */
1709
1710 getSubkeys( &doubleBblock, 0, key, Ls, Ld );
1711 rijndaelEncrypt( kt, kt ); /* construct K_top */
1712 memcpy( del, kt + 1, HB ); /* stretch K_top */
1713 for (i = 0; i < BLOCKSIZE; ++i)
1714 {
1715 del[i] ^= kt[i];
1716 kt[i] = (x[i] << 8 | x[i + 1]) >> s; /* shift the stretched K_top */
1717 }
1718
1719 xMac( data, ptextLen, NULL, &nop, tag ); /* get plaintext? checksum */
1720 i = 0, n = dataSize / BLOCKSIZE;
1721
1722 for (y = data; i < n; y += BLOCKSIZE)
1723 { /* calculate Δ_i using */
1724 getDelta( ++i, Ld, kt, del ); /* ..my 'magic' algorithm */
1725 xorBlock( del, y );
1726 cipher( y, y );
1727 xorBlock( del, y ); /* Y = Δ_i ^ Cipher(Δ_i ^ X) */
1728 }
1729 if (n == 0)
1730 {
1731 del = kt; /* Δ_N = Δ_0 = K_top */
1732 kt = offset[3];
1733 }
1734 if ((i = dataSize % BLOCKSIZE) != 0)
1735 { /* Y_* = Enc(L_* ^ Δ_N) ^ X */
1736 tag[i] ^= 0x80; /* and pad X_* or checksum */
1737 xorBlock( Ls, del );
1738 mixThenXor( &rijndaelEncrypt, del, kt, y, i, y );
1739 }
1740
1741 xMac( data, dataSize - ptextLen, NULL, &nop, tag );
1742 cMac( Ld, NULL, del, BLOCKSIZE, tag );
1743
1744 /*- tag = Enc( checksum ^ Δ_* ^ L_$ ) so far. next, add "PMAC" of aData: **/
1745 i = 0, n = aDataLen / BLOCKSIZE;
1746
1747 for (x = aData; i < n; x += BLOCKSIZE)
1748 {
1749 getDelta( ++i, Ld, x, del );
1750 rijndaelEncrypt( del, del ); /* Δ = Enc( A_i ^ Δ_i ) */
1751 xorBlock( del, tag ); /* add Δ to the tag */
1752 }
1753 if ((i = aDataLen % BLOCKSIZE) != 0)
1754 {
1755 memset( kt, 0, BLOCKSIZE );
1756 getDelta( n, Ld, kt, del );
1757 cMac( NULL, Ls, x, i, del ); /* Δ = Enc(L_* ^ A_* ^ Δ_N) */
1758 xorBlock( del, tag ); /* add Δ to the tag */
1759 }
1760 BURN( RoundKey );
1761}
1762
1763/**
1764 * @brief encrypt the input stream using OCB-AES block-cipher method
1765 * @param key encryption key with a fixed size specified by KEYSIZE
1766 * @param nonce a.k.a initialization vector with fixed size: OCB_NONCE_LEN
1767 * @param aData additional authentication data
1768 * @param aDataLen size of additional authentication data
1769 * @param pntxt input plain-text buffer
1770 * @param ptextLen size of plaintext in bytes
1771 * @param crtxt resulting cipher-text buffer + message authentication tag
1772 */
1773void SPP_EXTERNAL_ENCRYPTION_ocbEncrypt( const uint8_t* key, const uint8_t* nonce,
1774 const void* aData, const size_t aDataLen,
1775 const void* pntxt, const size_t ptextLen, void* crtxt )
1776{
1777 block_t mac = { 0 };
1778 char* tag = (char*) crtxt + ptextLen;
1779
1780 memcpy( crtxt, pntxt, ptextLen ); /* doing in-place encryption */
1781 OCB_cipher( key, nonce, ptextLen, aDataLen, ptextLen, aData, crtxt, mac );
1782 memcpy( tag, mac, OCB_TAG_LEN );
1783}
1784
1785/**
1786 * @brief decrypt the input stream using OCB-AES block-cipher method
1787 * @param key decryption key with a fixed size specified by KEYSIZE
1788 * @param nonce a.k.a initialization vector with fixed size: OCB_NONCE_LEN
1789 * @param aData additional authentication data
1790 * @param aDataLen size of additional authentication data
1791 * @param crtxt input cipher-text buffer + appended authentication tag
1792 * @param crtxtLen size of ciphertext, excluding tag
1793 * @param pntxt resulting plaintext buffer
1794 * @return whether message decryption/authentication was successful
1795 */
1796char SPP_EXTERNAL_ENCRYPTION_ocbDecrypt( const uint8_t* key, const uint8_t* nonce,
1797 const void* aData, const size_t aDataLen,
1798 const void* crtxt, const size_t crtxtLen, void* pntxt )
1799{
1800 block_t mac = { 0 };
1801 const char* tag = (char*) crtxt + crtxtLen;
1802
1803 memcpy( pntxt, crtxt, crtxtLen ); /* doing in-place decryption */
1804 OCB_cipher( key, nonce, 0, aDataLen, crtxtLen, aData, pntxt, mac );
1805
1806 if (memcmp_s( tag, mac, OCB_TAG_LEN ))
1807 {
1808 SABOTAGE( pntxt, crtxtLen );
1810 }
1811 return M_SUCCESS;
1812}
1813#endif /* OCB */
1814
1815
1816/*----------------------------------------------------------------------------*\
1817 KW-AES: Main functions for AES key-wrapping (RFC-3394)
1818\*----------------------------------------------------------------------------*/
1819#if IMPLEMENT(KWA)
1820#define IV_KWA "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6"
1821/**
1822 * @brief encrypt the input secret with key-wrapping method
1823 * @param kek key-encryption-key a.k.a master key
1824 * @param secret input plaintext secret
1825 * @param secretLen size of secret in bytes
1826 * @param wrapped wrapped secret, prepended with an additional half-block
1827 * @return error if size is not a multiple of HB, or size < BLOCKSIZE
1828 */
1829char SPP_EXTERNAL_ENCRYPTION_keyWrap( const uint8_t* kek,
1830 const void* secret, const size_t secretLen, void* wrapped )
1831{
1832 char *output = wrapped;
1833 char *r = output + HB, *end = output + secretLen;
1834 block_t A;
1835 count_t i, n = secretLen / HB; /* number of semi-blocks */
1836
1837 if (n < 2 || secretLen % HB) return M_DATALENGTH_ERROR;
1838
1839 memcpy( A, IV_KWA, HB ); /* initialization vector */
1840 memcpy( r, secret, secretLen ); /* in-place encryption */
1841 AES_setkey( kek );
1842
1843 for (i = 0, n *= 6; i++ < n; )
1844 {
1845 memcpy( A + HB, r, HB ); /* R = LSB(64, A) */
1846 rijndaelEncrypt( A, A ); /* A* = Enc( L | R ) */
1847 memcpy( r, A + HB, HB ); /* L* = MSB(64, A*) ^ i */
1848 xorBEint( A, i, MIDST );
1849 r = (r == end ? output : r) + HB;
1850 }
1851 BURN( RoundKey );
1852
1853 memcpy( output, A, HB ); /* authentication vector */
1854 return M_SUCCESS;
1855}
1856
1857/**
1858 * @brief unwrap/decrypt a wrapped secret according to RFC-3394
1859 * @param kek key-encryption-key a.k.a master key
1860 * @param wrapped ciphertext input, the wrapped secret
1861 * @param wrapLen size of ciphertext/wrapped input in bytes
1862 * @param secret unwrapped secret, which is a half block shorter than input
1863 * @return whether decrypting/unwrapping secret was successful
1864 */
1865char SPP_EXTERNAL_ENCRYPTION_keyUnwrap( const uint8_t* kek,
1866 const void* wrapped, const size_t wrapLen, void* secret )
1867{
1868 char const* input = wrapped;
1869 char *r = secret, *end = (char*) secret + wrapLen - HB;
1870 block_t A;
1871 count_t i, n = wrapLen / HB; /* number of semi-blocks */
1872
1873 if (n-- < 3 || wrapLen % HB) return M_DATALENGTH_ERROR;
1874
1875 memcpy( A, input, HB );
1876 memcpy( r, input + HB, wrapLen - HB ); /* in-place decryption */
1877 AES_setkey( kek );
1878
1879 for (i = n * 6; i > 0; --i)
1880 {
1881 r = (r == secret ? end : r) - HB;
1882 xorBEint( A, i, MIDST );
1883 memcpy( A + HB, r, HB ); /* L = MSB(64, A) ^ i */
1884 rijndaelDecrypt( A, A ); /* A* = Dec( L | R ) */
1885 memcpy( r, A + HB, HB ); /* R* = LSB(64, A*) */
1886 }
1887 BURN( RoundKey );
1888
1889 if (memcmp_s( A, IV_KWA, HB )) /* authenticate/error-check */
1890 {
1891 SABOTAGE( secret, n * HB );
1893 }
1894 return M_SUCCESS;
1895}
1896#endif /* KWA */
1897
1898
1899/*----------------------------------------------------------------------------*\
1900 Poly1305-AES message authentication: auxiliary functions and main API
1901\*----------------------------------------------------------------------------*/
1902#if IMPLEMENT(POLY1305)
1903
1904/** add two little-endian blocks x and y up to length len, so that: y = y + x */
1905static void addLblocks( const uint8_t* x, const uint8_t len, uint8_t* y )
1906{
1907 int a, i;
1908 for (i = a = 0; i < len; a >>= 8)
1909 {
1910 a += x[i] + y[i];
1911 y[i++] = (uint8_t) a;
1912 }
1913}
1914
1915/** derive modulo(2^130-5) for a large integer saved in a little-endian block */
1916static void modP1305( uint8_t* block, int32_t q )
1917{
1918 if (q < 4) return; /* q is block's MSBs: B>>128 */
1919
1920 block[PL - 1] &= 3; /* subtract (q >> 2) << 130 */
1921
1922 for (q = (q >> 2) * 5; q; q >>= 8) /* suppose Q = B / (2 ^ 130) */
1923 { /* ..then "almost" always: */
1924 q += *block; /* mod = B - Q * (2^130-5) */
1925 *block++ = (uint8_t) q; /* so subtract Q * 2^130 and */
1926 } /* ..then add (Q * 5) := q */
1927}
1928
1929/** modular multiplication of two little-endian poly1305 blocks: y *= x mod P */
1930static void mulLblocks( const uint8_t* x, uint8_t* y )
1931{
1932 uint8_t n = PL, result[PL] = { 0 };
1933 while (n--)
1934 {
1935 uint8_t s = 8 * (n != 0), i;
1936 int32_t m = 0, y_n = y[n]; /* Y = [Y_0][Y_1]...[Y_16], */
1937
1938 for (i = 0; i < sizeof result; ++i) /* multiply X by MSB of Y */
1939 { /* ..and add to the result */
1940 m >>= 8; /* if Y has another byte in */
1941 m += (y_n * x[i] + result[i]) << s; /* ..queue, shift the result */
1942 result[i] = (uint8_t) m; /* ..but don't shift for Y_0 */
1943 }
1944 modP1305( result, m ); /* modular multiplication */
1945 }
1946 memcpy( y, result, sizeof result );
1947}
1948
1949/**
1950 * @brief derive the Poly1305-AES mac of message using a nonce and key pair.
1951 * @param keys pair of encryption/mixing keys (k, r); size = KEYSIZE + 16
1952 * @param nonce a 128 bit string which is encrypted by AES_k
1953 * @param data buffer of input data
1954 * @param dataSize size of data in bytes
1955 * @param mac calculated Poly1305-AES mac
1956 */
1957void SPP_EXTERNAL_ENCRYPTION_poly1305( const uint8_t* keys, const block_t nonce,
1958 const void* data, const size_t dataSize, block_t mac )
1959{
1960 uint8_t r[PL], rk[PL] = { 1 }, c[PL] = { 0 }, poly[PL] = { 0 }, s = PL - 1;
1961 count_t q = (dataSize - 1) / BLOCKSIZE;
1962 const char* pos = (const char*) data + dataSize;
1963
1964 AES_setkey( keys );
1965 rijndaelEncrypt( nonce, mac ); /* derive AES_k(nonce) */
1966 BURN( RoundKey );
1967
1968 if (!dataSize) return;
1969
1970 memcpy( r, keys + KEYSIZE, s ); /* extract r from (K,r) pair */
1971 for (r[s] = 0; s > 3; s -= 3)
1972 {
1973 r[s--] &= 0xFC; /* clear bottom 2 bits */
1974 r[s ] &= 0x0F; /* clear top 4 bits */
1975 }
1976 s = dataSize - BLOCKSIZE * q; /* size of last chunk */
1977 do
1978 {
1979 memcpy( c, pos -= s, s ); /* copy message to chunk */
1980 c[s] = 1; /* append 1 to each chunk */
1981 s = BLOCKSIZE;
1982 mulLblocks( r, rk ); /* r^k = r^{k-1} * r */
1983 mulLblocks( rk, c ); /* calculate c_{q-k} * r^k */
1984 addLblocks( c, PL, poly ); /* ..and add it to poly, */
1985 modP1305( poly, poly[s] ); /* ..then take mod(2^130-5) */
1986
1987 } while (q--);
1988
1989 q = poly[s] * 4; /* still, in some rare cases */
1990 if (poly[0] > 0xFA && q == 12) /* ..poly may be >= 2^130-5 */
1991 { /* ..if it is so, set q=16 */
1992 for (q = 1; poly[q] == 0xFF; ++q);
1993 }
1994 modP1305( poly, q / 4 );
1995
1996 addLblocks( poly, BLOCKSIZE, mac ); /* add AES_k(nonce) to poly */
1997}
1998#endif /* POLY1305 */
1999
2000
2001/*----------------------------------------------------------------------------*\
2002 FPE-AES (format-preserving encryption): definitions & auxiliary functions
2003\*----------------------------------------------------------------------------*/
2004#if IMPLEMENT(FPE)
2005
2006#if CUSTOM_ALPHABET
2007#include "micro_fpe.h"
2008#else
2009#define ALPHABET "0123456789"
2010#define RADIX 10 /* strlen (ALPHABET) */
2011#define LOGRDX 3.32192809488736 /* log2 (RADIX) */
2012#define MINLEN 6 /* ceil (6 / log10 (RADIX)) */
2013#define MAXLEN 56 /* only if FF_X == 3 */
2014#endif
2015
2016#if ALPHABET_IS_NON_ASCII
2017typedef wchar_t alpha_t;
2018#else
2019typedef char alpha_t; /* type of plain/ciphertext */
2020#endif
2021
2022#if RADIX - 1 <= UCHAR_MAX
2023typedef unsigned char radix_t; /* digit type in base-radix */
2024#else
2025typedef unsigned short radix_t;
2026#endif
2027
2028#if FF_X == 3 /* FF3 'tweakLen' is fixed */
2029#define TWEAK_PARAMS uint8_t* tweak
2030#define TWEAK_AGRS tweak
2031#define FPE_PERMUTE FF3_cipher
2032#else /* FF1 implementation: */
2033#define FPE_PERMUTE FF1_cipher
2034#define TWEAK_PARAMS uint8_t* tweak, const size_t tweakLen
2035#define TWEAK_AGRS tweak, tweakLen
2036
2037static size_t b1; /* the b constant in FF1 */
2038
2039/** convert the string s in base-RADIX to a big-endian number, denoted by num */
2040static void numRadix( const radix_t* s, size_t len, uint8_t* num, size_t bytes )
2041{
2042 memset( num, 0, bytes );
2043 while (len--)
2044 { /* we can reasonably assume */
2045 size_t k = bytes, y; /* .. RADIX^2 <= SIZE_MAX+1 */
2046 for (y = *s++; k--; y >>= 8)
2047 {
2048 y += num[k] * RADIX;
2049 num[k] = (uint8_t) y; /* num = num * RADIX + y */
2050 }
2051 }
2052}
2053
2054/** convert a big-endian number to string s, its representation in base-RADIX */
2055static void strRadix( const uint8_t* num, size_t bytes, radix_t* s, size_t len )
2056{
2057 memset( s, 0, sizeof (radix_t) * len );
2058 while (bytes--)
2059 {
2060 size_t k = len, x;
2061 for (x = *num++; k--; x /= RADIX)
2062 {
2063 x += s[k] << 8; /* str = (str << 8) + x */
2064 s[k] = x % RADIX;
2065 }
2066 }
2067}
2068
2069/** add two numbers x, y in base-RADIX and save the result in y, i.e. y += x; */
2070static void addRadix( const radix_t* x, const size_t len, radix_t* y )
2071{
2072 size_t k = len, a;
2073 for (a = 0; k--; a /= RADIX) /* big-endian addition */
2074 {
2075 a += y[k] + x[k]; /* a /= RADIX is equivalent */
2076 y[k] = a % RADIX; /* ..to: a = (a >= RADIX) */
2077 }
2078}
2079
2080/** subtract two numbers in base-RADIX and save the result in y, i.e. y -= x; */
2081static void subRadix( const radix_t* x, const size_t len, radix_t* y )
2082{
2083 size_t k = len, s;
2084 for (s = 1; k--; s /= RADIX) /* big-endian subtraction */
2085 {
2086 s += RADIX - 1 + y[k] - x[k];
2087 y[k] = s % RADIX;
2088 }
2089}
2090
2091/** derive C at step i of FF1 rounds, given the values: u, v and PRF_init = P */
2092static void FF1round( const uint8_t i, const block_t P,
2093 const size_t u, const size_t v, radix_t* C )
2094{
2095 block_t R = { 0 };
2096 uint8_t* num = (uint8_t*) &C[u]; /* use pre-allocated memory, */
2097 size_t k = b1 % sizeof R, ext = (i & 1) * u;
2098
2099 numRadix( C - v - ext, v, num, b1 ); /* ..to get NUM_radix(B) */
2100 num[-1] = i;
2101 memcpy( R + LAST - k, num - 1, k + 1 ); /* feed NUM_radix to the PRF */
2102
2103 xMac( P, BLOCKSIZE, R, &rijndaelEncrypt, R );
2104 xMac( num + k, b1 - k, R, &rijndaelEncrypt, R );
2105
2106 memcpy( num, R, sizeof R ); /* R = PRF(P || Q) */
2107 k = (b1 + 3L) / sizeof R; /* total additional blocks */
2108
2109 for (ext = 0; k; ext = k--)
2110 { /* S = R | Enc(R ^[k]) | ... */
2111 xorBEint( R, ext ^ k, LAST );
2112 rijndaelEncrypt( R, num + k * sizeof R );
2113 }
2114 strRadix( num, (b1 + 7) & ~3L, C, u ); /* take first 'd' bytes of S */
2115}
2116
2117/** encrypt/decrypt a base-RADIX string X with length len using FF1 algorithm */
2118static void FF1_cipher( const uint8_t* key, const char mode,
2119 const TWEAK_PARAMS, const size_t len, radix_t* X )
2120{
2121 size_t u = (len + !mode) / 2, t = tweakLen, v = b1 % BLOCKSIZE;
2122 radix_t* xC = X + len;
2123 block_t P = { 1, 2, 1, RADIX >> 16, RADIX >> 8 & 0xFF, RADIX & 0xFF, 10 };
2124 uint8_t i = t % BLOCKSIZE + v >= BLOCKSIZE ? 0 : t % BLOCKSIZE;
2125
2126 AES_setkey( key );
2127
2128 P[7] ^= len / 2; /* initializing P block */
2129 xorBEint( P, len, 11 );
2130 xorBEint( P, t, LAST );
2131 rijndaelEncrypt( P, P ); /* P -> PRF(P || tweak) */
2132 xMac( tweak, t - i, P, &rijndaelEncrypt, P );
2133
2134 while (i)
2135 {
2136 P[--i] ^= tweak[--t];
2137 }
2138 for (t = 10 * mode; i < t; ++i, u = v) /* Feistel procedure */
2139 { /* encryption rounds */
2140 FF1round( i, P, u, v = len - u, xC );
2141 addRadix( xC, u, X + (i & 1) * v ); /* add C to A then swap A,B */
2142 }
2143 for (i ^= 10 + (size_t) 0; i--; u = v) /* decryption rounds */
2144 {
2145 FF1round( i, P, u, v = len - u, xC );
2146 subRadix( xC, u, X + (i & 1) * v ); /* subtract C from A */
2147 }
2148}
2149#endif /* FF1 */
2150
2151#if FF_X == 3 /* FF3/FF3-1 method: */
2152
2153/** converts a string in base-RADIX to a little-endian number, denoted by num */
2154static void numRadix( const radix_t* s, uint8_t len, uint8_t* num, char bytes )
2155{
2156 memset( num, 0, bytes );
2157 while (len--)
2158 {
2159 size_t y = s[len], i;
2160 for (i = 0; i < bytes; y >>= 8) /* bytes = 12 "always" */
2161 {
2162 y += num[i] * RADIX;
2163 num[i++] = (uint8_t) y; /* num = num * RADIX + y */
2164 }
2165 }
2166}
2167
2168/** convert a little-endian number to its base-RADIX representation string: s */
2169static void strRadix( const uint8_t* num, char bytes, radix_t* s, uint8_t len )
2170{
2171 memset( s, 0, sizeof (radix_t) * len );
2172 while (bytes--)
2173 {
2174 size_t x = num[bytes], i;
2175 for (i = 0; i < len; x /= RADIX)
2176 {
2177 x += s[i] << 8; /* str = (str << 8) + x */
2178 s[i++] = x % RADIX;
2179 }
2180 }
2181}
2182
2183/** add two numbers x, y in base-RADIX and save the result in y, i.e. y += x; */
2184static void addRadix( const radix_t* x, const uint8_t len, radix_t* y )
2185{
2186 size_t a = 0, i;
2187 for (i = 0; i < len; a /= RADIX) /* little-endian addition */
2188 {
2189 a += y[i] + x[i];
2190 y[i++] = a % RADIX;
2191 }
2192}
2193
2194/** subtract two numbers in base-RADIX and save the result in y, i.e. y -= x; */
2195static void subRadix( const radix_t* x, const uint8_t len, radix_t* y )
2196{
2197 size_t s = 1, i;
2198 for (i = 0; i < len; s /= RADIX) /* little-endian subtraction */
2199 {
2200 s += RADIX - 1 + y[i] - x[i];
2201 y[i++] = s % RADIX;
2202 }
2203}
2204
2205/** calculate C at step i of FF3 rounds, given the values: u, v and tweak (T) */
2206static void FF3round( const uint8_t i, const uint8_t* T,
2207 const uint8_t u, const uint8_t v, radix_t* C )
2208{
2209 uint8_t w = (i & 1) * 4, ext = (i & 1) * u;
2210 block_t P;
2211 COPYDWORD( T[w], P[12] ); /* W = (i is odd) ? TR : TL */
2212 P[12] ^= i;
2213
2214 numRadix( C - v - ext, v, P, 12 ); /* get REV. NUM_radix( B ) */
2215 rijndaelEncrypt( P, P );
2216 strRadix( P, sizeof P, C, u ); /* C = REV. STR_m( c ) */
2217}
2218
2219/** encrypt/decrypt a base-RADIX string X with size len using FF3-1 algorithm */
2220static void FF3_cipher( const uint8_t* key, const char mode,
2221 const TWEAK_PARAMS, const size_t len, radix_t* X )
2222{
2223 radix_t* xC = X + len;
2224 uint8_t T[8], u = (len + mode) / 2, v, i, *tmp = (void*) xC;
2225
2226 memcpy( tmp, tweak, FF3_TWEAK_LEN );
2227 tmp[FF3_TWEAK_LEN] = tmp[3];
2228 if (FF3_TWEAK_LEN == 7) /* FF3 vs. FF3-1 */
2229 {
2230 tmp[7] <<= 4;
2231 tmp[3] &= 0xF0;
2232 }
2233
2234 for (i = 7 + 1; i--; ) T[7 - i] = tmp[i];
2235 for (i = KEYSIZE; i; ) tmp[--i] = *key++; /* key/tweak are reversed */
2236
2237 AES_setkey( tmp );
2238 SABOTAGE( tmp, KEYSIZE );
2239
2240 for (; i < 8 * mode; ++i, u = v) /* Feistel procedure */
2241 { /* encryption rounds */
2242 FF3round( i, T, u, v = len - u, xC );
2243 addRadix( xC, u, X + (i & 1) * v ); /* add C to A then swap A,B */
2244 }
2245 for (i ^= (char) 8U; i--; u = v) /* decryption rounds */
2246 {
2247 FF3round( i, T, u, v = len - u, xC );
2248 subRadix( xC, u, X + (i & 1) * v );
2249 }
2250}
2251#endif /* FF3 */
2252
2253/*----------------------------------------------------------------------------*\
2254 FPE-AES: main functions
2255\*----------------------------------------------------------------------------*/
2256#include <stdlib.h>
2257
2258/**
2259 * @brief encrypt or decrypt the input string with FPE method
2260 * @param key encryption or decryption key
2261 * @param mode mode of operation: encrypting (1) or decrypting (0)
2262 * @param tweak tweak byte array
2263 * @param tweakLen size of tweak. must be exactly 7 in FF3-1
2264 * @param input input string, consisted of characters in ALPHABET
2265 * @param dataSize length of the string, or its number of characters
2266 * @param output result of format-preserved encryption/decryption
2267 * @return an associated error code in case of failure
2268 */
2269static char FPE_cipher( const uint8_t* key, const char mode, const TWEAK_PARAMS,
2270 const void* input, const size_t dataSize, void* output )
2271{
2272 size_t v = (dataSize + 1) / 2;
2273 size_t n = (dataSize + v) * sizeof (radix_t);
2274 alpha_t const* alpha = ALPHABET;
2275 alpha_t* y = output;
2276 radix_t* index;
2277
2278 if (dataSize < MINLEN) return M_DATALENGTH_ERROR;
2279#if FF_X == 3
2280 if (dataSize > MAXLEN) return M_DATALENGTH_ERROR;
2281
2282 v *= sizeof (radix_t);
2283 n += v < KEYSIZE ? KEYSIZE - v : 0;
2284#else /* extra memory is needed.. */
2285 b1 = (size_t) (LOGRDX * v + 8 - 1e-14) / 8; /* to store NUM_radix and.. */
2286 n += (b1 + 4 + LAST) & ~LAST; /* mix it in Feistel rounds */
2287#endif
2288
2289 if ((index = malloc( n )) == NULL)
2290 {
2291 return M_MEMORY_ERROR; /* memory allocation failed */
2292 }
2293 for (n = 0; n < dataSize; ++n) /* find index of each char */
2294 {
2295 const alpha_t *ch = (alpha_t*) input + n;
2296 for (v = 0x0; *ch != alpha[v]; )
2297 {
2298 if (++v == RADIX)
2299 {
2300 free( index ); /* invalid character found */
2301 return M_DATAFORMAT_ERROR;
2302 }
2303 }
2304 *(index + n) = (radix_t) v;
2305 } /* now permute the indexes: */
2306
2307 FPE_PERMUTE( key, mode, TWEAK_AGRS, n, index );
2308 BURN( RoundKey );
2309
2310 for (y[n] = 0; n--; ) /* construct the output as */
2311 { /* null-terminated? string */
2312 y[n] = alpha[index[n]];
2313 }
2314 free( index );
2315 return M_SUCCESS;
2316}
2317
2318/**
2319 * @brief encrypt the input string using FPE-AES block-cipher method
2320 * @param key encryption key with a fixed size specified by KEYSIZE
2321 * @param tweak tweak byte array; similar to nonce in other schemes
2322 * @param tweakLen size of tweak. must be exactly 7 in FF3-1
2323 * @param pntxt input plaintext string, consisted of ALPHABET characters
2324 * @param ptextLen size of plaintext string, or number of characters
2325 * @param crtxt resulting ciphertext string
2326 * @return whether encryption was successful
2327 */
2328char SPP_EXTERNAL_ENCRYPTION_fpeEncrypt( const uint8_t* key, const TWEAK_PARAMS,
2329 const void* pntxt, const size_t ptextLen, void* crtxt )
2330{
2331 return FPE_cipher( key, 1, TWEAK_AGRS, pntxt, ptextLen, crtxt );
2332}
2333
2334/**
2335 * @brief decrypt a ciphertext string using FPE-AES block-cipher method
2336 * @param key decryption key with a fixed size specified by KEYSIZE
2337 * @param tweak tweak byte array; similar to nonce in other schemes
2338 * @param tweakLen size of tweak. must be exactly 7 in FF3-1
2339 * @param crtxt input ciphertext string, consisted of ALPHABET characters
2340 * @param crtxtLen size of ciphertext string, or number of characters
2341 * @param pntxt resulting plaintext string
2342 * @return whether decryption was successful
2343 */
2344char SPP_EXTERNAL_ENCRYPTION_fpeDecrypt( const uint8_t* key, const TWEAK_PARAMS,
2345 const void* crtxt, const size_t crtxtLen, void* pntxt )
2346{
2347 return FPE_cipher( key, 0, TWEAK_AGRS, crtxt, crtxtLen, pntxt );
2348}
2349#endif /* FPE */
#define MINLEN
#define ALPHABET
#define FPE_PERMUTE
void SPP_EXTERNAL_ENCRYPTION_ctrDecrypt(const uint8_t *key, const uint8_t *iv, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using CTR-AES block-cipher method
Definition encryption.c:989
uint8_t block_t[BLOCKSIZE]
Definition encryption.c:76
static char padBlock(const uint8_t len, block_t block)
Definition encryption.c:613
static void cMac(const block_t K1, const block_t K2, const void *data, const size_t dataSize, block_t mac)
Definition encryption.c:579
void SPP_EXTERNAL_ENCRYPTION_ecbEncrypt(const uint8_t *key, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using ECB-AES block-cipher method
Definition encryption.c:639
unsigned short radix_t
static void GCM_SIVsetup(const uint8_t *key, const uint8_t *nonce, block_t AK)
static void rijndaelDecrypt(const block_t input, block_t output)
Definition encryption.c:316
char SPP_EXTERNAL_ENCRYPTION_cbcEncrypt(const uint8_t *key, const block_t iVec, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using CBC-AES block-cipher method
Definition encryption.c:700
void SPP_EXTERNAL_ENCRYPTION_ctrEncrypt(const uint8_t *key, const uint8_t *iv, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using CTR-AES block-cipher method
Definition encryption.c:965
void SPP_EXTERNAL_ENCRYPTION_poly1305(const uint8_t *keys, const block_t nonce, const void *data, const size_t dataSize, block_t mac)
derive the Poly1305-AES mac of message using a nonce and key pair.
static void divideLblock(block_t array)
Definition encryption.c:501
static char FPE_cipher(const uint8_t *key, const char mode, const TWEAK_PARAMS, const void *input, const size_t dataSize, void *output)
encrypt or decrypt the input string with FPE method
static void doubleLblock(block_t array)
Definition encryption.c:451
static void dotGF128(const block_t x, block_t y)
Definition encryption.c:513
uint8_t state_t[Nb][4]
Definition encryption.c:77
void SPP_EXTERNAL_ENCRYPTION_ofbDecrypt(const uint8_t *key, const block_t iVec, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using OFB-AES block-cipher method
Definition encryption.c:892
ctr_based_modes
Definition encryption.c:907
@ CCM_GCM
Definition encryption.c:911
@ SIV_CTR
Definition encryption.c:909
@ CTR_DEFAULT
Definition encryption.c:908
@ SIVGCM_CTR
Definition encryption.c:910
#define BURN(key)
#define XOR32BITS(x, y)
Definition encryption.c:87
char SPP_EXTERNAL_ENCRYPTION_gcmSivDecrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using SIV-GCM-AES block-cipher method
static void addRadix(const radix_t *x, const size_t len, radix_t *y)
#define AES_setkey(key)
void SPP_EXTERNAL_ENCRYPTION_cfbEncrypt(const uint8_t *key, const block_t iVec, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using CFB-AES block-cipher method
Definition encryption.c:830
static uint8_t mixG8(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
Definition encryption.c:124
static void InvSubBytes(block_t state)
Definition encryption.c:269
char SPP_EXTERNAL_ENCRYPTION_keyWrap(const uint8_t *kek, const void *secret, const size_t secretLen, void *wrapped)
encrypt the input secret with key-wrapping method
#define RADIX
void SPP_EXTERNAL_ENCRYPTION_ofbEncrypt(const uint8_t *key, const block_t iVec, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using OFB-AES block-cipher method
Definition encryption.c:864
static void doubleBblock(block_t array)
Definition encryption.c:436
#define LOGRDX
static void GCMsetup(const uint8_t *key, const uint8_t *nonce, block_t auKey, block_t iv)
static void rijndaelEncrypt(const block_t input, block_t output)
Definition encryption.c:243
static void subRadix(const radix_t *x, const size_t len, radix_t *y)
#define SBoxValue(x)
Definition encryption.c:83
#define SABOTAGE(buf, len)
char SPP_EXTERNAL_ENCRYPTION_keyUnwrap(const uint8_t *kek, const void *wrapped, const size_t wrapLen, void *secret)
unwrap/decrypt a wrapped secret according to RFC-3394
basic_constants
Definition encryption.c:17
@ Nb
Definition encryption.c:20
@ PL
Definition encryption.c:26
@ Nk
Definition encryption.c:21
@ ROUNDS
Definition encryption.c:22
@ KEYSIZE
Definition encryption.c:19
@ HB
Definition encryption.c:23
@ LAST
Definition encryption.c:24
@ MIDST
Definition encryption.c:25
@ BLOCKSIZE
Definition encryption.c:18
void SPP_EXTERNAL_ENCRYPTION_gcmEncrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using GCM-AES block-cipher method
#define InvSBoxValue(x)
Definition encryption.c:84
void SPP_EXTERNAL_ENCRYPTION_ocbEncrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input stream using OCB-AES block-cipher method
static uint8_t xtime(uint8_t x)
Definition encryption.c:105
void SPP_EXTERNAL_ENCRYPTION_sivEncrypt(const uint8_t *keys, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, block_t iv, void *crtxt)
encrypt the input plaintext using SIV-AES block-cipher method
static uint8_t RoundKey[BLOCKSIZE *ROUNDS+KEYSIZE]
Definition encryption.c:72
char SPP_EXTERNAL_ENCRYPTION_cbcDecrypt(const uint8_t *key, const block_t iVec, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using CBC-AES block-cipher method
Definition encryption.c:749
static void MixColumns(state_t state)
Definition encryption.c:222
static void CCMtag(const block_t iv, const void *aData, const void *pntxt, const size_t aDataLen, const size_t ptextLen, block_t M)
char SPP_EXTERNAL_ENCRYPTION_eaxDecrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using EAX-AES block-cipher method
#define TWEAK_PARAMS
static void getSubkeys(fdouble_t gfdouble, const char quad, const uint8_t *key, block_t D, block_t Q)
Definition encryption.c:596
static void gHash(const block_t H, const void *aData, const void *crtxt, const size_t aDataLen, const size_t crtxtLen, block_t gh)
void SPP_EXTERNAL_ENCRYPTION_cfbDecrypt(const uint8_t *key, const block_t iVec, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using CFB-AES block-cipher method
Definition encryption.c:844
static void InvShiftRows(state_t state)
Definition encryption.c:279
#define memcmp_s
static void strRadix(const uint8_t *num, size_t bytes, radix_t *s, size_t len)
static void oMac(const uint8_t indx, const block_t D, const block_t Q, const void *data, const size_t dataSize, block_t mac)
static void getDelta(const count_t index, const block_t Ld, const block_t delta0, block_t delta)
char SPP_EXTERNAL_ENCRYPTION_sivDecrypt(const uint8_t *keys, const block_t iv, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using SIV-AES block-cipher method
#define IV_KWA
static void xMac(const void *data, const size_t dataSize, const block_t seed, fmix_t mix, block_t result)
Definition encryption.c:554
static void FF1round(const uint8_t i, const block_t P, const size_t u, const size_t v, radix_t *C)
#define XOR64BITS(x, y)
Definition encryption.c:92
static void S2V(const uint8_t *key, const void *aData, const void *pntxt, const size_t aDataLen, const size_t ptextLen, block_t IV)
static void GCM_SIVtag(const uint8_t *nonce, block_t pv, block_t tag)
char alpha_t
static void numRadix(const radix_t *s, size_t len, uint8_t *num, size_t bytes)
static void addLblocks(const uint8_t *x, const uint8_t len, uint8_t *y)
static void FF1_cipher(const uint8_t *key, const char mode, const TWEAK_PARAMS, const size_t len, radix_t *X)
static const char sbox[256]
Definition encryption.c:41
void SPP_EXTERNAL_ENCRYPTION_gcmSivEncrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using SIV-GCM-AES block-cipher method
static void polyval(const block_t H, const void *aData, const void *pntxt, const size_t aDataLen, const size_t ptextLen, block_t pv)
void SPP_EXTERNAL_ENCRYPTION_ccmEncrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using CCM-AES block-cipher method
static void xorBlock(const block_t src, block_t dest)
Definition encryption.c:111
#define TWEAK_AGRS
char SPP_EXTERNAL_ENCRYPTION_gcmDecrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using GCM-AES block-cipher method
static void mixThenXor(fmix_t mix, const block_t B, block_t f, const uint8_t *X, uint8_t n, uint8_t *Y)
Definition encryption.c:536
static void divideBblock(block_t array)
Definition encryption.c:466
char SPP_EXTERNAL_ENCRYPTION_xtsEncrypt(const uint8_t *keys, const uint8_t *tweak, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using XTS-AES block-cipher method
char SPP_EXTERNAL_ENCRYPTION_fpeDecrypt(const uint8_t *key, const TWEAK_PARAMS, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt a ciphertext string using FPE-AES block-cipher method
static void SubBytes(block_t state)
Definition encryption.c:188
static void CFB_cipher(const uint8_t *key, const block_t iVec, const char mode, const void *input, const size_t dataSize, void *output)
the general scheme of CFB-AES block-ciphering algorithm
Definition encryption.c:802
char SPP_EXTERNAL_ENCRYPTION_ocbDecrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input stream using OCB-AES block-cipher method
static void nop(const block_t x, block_t y)
static void incBlock(block_t block, uint8_t index)
Definition encryption.c:423
static void xorBEint(uint8_t *buff, size_t num, uint8_t pos)
Definition encryption.c:412
static void InvMixColumns(state_t state)
Definition encryption.c:302
static size_t b1
char SPP_EXTERNAL_ENCRYPTION_xtsDecrypt(const uint8_t *keys, const uint8_t *tweak, const void *crtxt, const size_t crtxtLen, void *pntxt)
encrypt the input ciphertext using XTS-AES block-cipher method
static void AddRoundKey(const uint8_t round, block_t state)
Definition encryption.c:182
static void mulGF128(const block_t x, block_t y)
Definition encryption.c:478
static void KeyExpansion(const uint8_t *key)
Definition encryption.c:145
static void OCB_cipher(const uint8_t *key, const uint8_t *nonce, const size_t ptextLen, const size_t aDataLen, const size_t dataSize, const void *aData, void *data, block_t tag)
encrypt or decrypt the data using OCB method
char SPP_EXTERNAL_ENCRYPTION_ecbDecrypt(const uint8_t *key, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using ECB-AES block-cipher method
Definition encryption.c:666
#define MAXLEN
void(*) fmix_t(const block_t, block_t)
Definition encryption.c:358
static void modP1305(uint8_t *block, int32_t q)
static void mulLblocks(const uint8_t *x, uint8_t *y)
static const char rsbox[256]
Definition encryption.c:54
static char XTS_cipher(const uint8_t *keypair, const char mode, const block_t tweak, const size_t sectid, const size_t dataSize, void *storage)
encrypt or decrypt a data unit with XTS method
void SPP_EXTERNAL_ENCRYPTION_eaxEncrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input plaintext using EAX-AES block-cipher method
void SPP_EXTERNAL_ENCRYPTION_cmac(const uint8_t *key, const void *data, const size_t dataSize, block_t mac)
derive the AES-CMAC of input data using an encryption key
char SPP_EXTERNAL_ENCRYPTION_ccmDecrypt(const uint8_t *key, const uint8_t *nonce, const void *aData, const size_t aDataLen, const void *crtxt, const size_t crtxtLen, void *pntxt)
decrypt the input ciphertext using CCM-AES block-cipher method
static void CTR_cipher(const block_t iCtr, const char mode, const void *input, const size_t dataSize, void *output)
the general scheme of operation in block-counter mode
Definition encryption.c:922
#define COPYDWORD(x, y)
Definition encryption.c:86
char SPP_EXTERNAL_ENCRYPTION_fpeEncrypt(const uint8_t *key, const TWEAK_PARAMS, const void *pntxt, const size_t ptextLen, void *crtxt)
encrypt the input string using FPE-AES block-cipher method
static void ShiftRows(state_t state)
Definition encryption.c:199
#define SDCC_REENT
Definition encryption.h:153
#define AES_PADDING
Definition encryption.h:80
@ SIVGCM_NONCE_LEN
Definition encryption.h:113
@ SIVGCM_TAG_LEN
Definition encryption.h:114
@ CTR_IV_LENGTH
Definition encryption.h:100
@ EAX_NONCE_LEN
Definition encryption.h:121
@ AES_KEYLENGTH
Definition encryption.h:128
@ GCM_TAG_LEN
Definition encryption.h:110
@ CCM_NONCE_LEN
Definition encryption.h:105
@ OCB_NONCE_LEN
Definition encryption.h:117
@ EAX_TAG_LEN
Definition encryption.h:122
@ OCB_TAG_LEN
Definition encryption.h:118
@ CCM_TAG_LEN
Definition encryption.h:106
@ CTR_START_VALUE
Definition encryption.h:99
@ GCM_NONCE_LEN
Definition encryption.h:109
#define EAXP
Definition encryption.h:69
@ M_DATAFORMAT_ERROR
Definition encryption.h:476
@ M_AUTHENTICATION_ERROR
Definition encryption.h:474
@ M_MEMORY_ERROR
Definition encryption.h:477
@ M_DATALENGTH_ERROR
Definition encryption.h:475
@ M_SUCCESS
Definition encryption.h:478
@ M_DECRYPTION_ERROR
Definition encryption.h:473