Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-forkae-paef.h
1 /*
2  * Copyright (C) 2020 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 /* We expect a number of macros to be defined before this file
24  * is included to configure the underlying ForkAE PAEF variant.
25  *
26  * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256
27  * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes).
28  * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes.
29  * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes.
30  * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher.
31  * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256
32  */
33 #if defined(FORKAE_ALG_NAME)
34 
35 #define FORKAE_CONCAT_INNER(name,suffix) name##suffix
36 #define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix)
37 
38 /* Limit on the amount of data we can process based on the counter size */
39 #define FORKAE_PAEF_DATA_LIMIT \
40  ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \
41  (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE)
42 
43 /* Processes the associated data in PAEF mode */
44 STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)
45  (unsigned char tweakey[FORKAE_TWEAKEY_SIZE],
46  unsigned long long counter, unsigned char domain)
47 {
48  unsigned posn;
49  counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3));
50  for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) {
51  tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] =
52  (unsigned char)counter;
53  counter >>= 8;
54  }
55 }
56 
57 /* Check that the last block is padded correctly; -1 if ok, 0 if not */
58 STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding)
59  (const unsigned char *block, unsigned len)
60 {
61  int check = block[0] ^ 0x80;
62  while (len > 1) {
63  --len;
64  check |= block[len];
65  }
66  return (check - 1) >> 8;
67 }
68 
69 int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt)
70  (unsigned char *c, unsigned long long *clen,
71  const unsigned char *m, unsigned long long mlen,
72  const unsigned char *ad, unsigned long long adlen,
73  const unsigned char *nsec,
74  const unsigned char *npub,
75  const unsigned char *k)
76 {
77  unsigned char tweakey[FORKAE_TWEAKEY_SIZE];
78  unsigned char tag[FORKAE_BLOCK_SIZE];
79  unsigned char block[FORKAE_BLOCK_SIZE];
80  unsigned long long counter;
81  (void)nsec;
82 
83  /* Set the length of the returned ciphertext */
84  *clen = mlen + FORKAE_BLOCK_SIZE;
85 
86  /* Validate the size of the associated data and plaintext as there
87  * is a limit on the size of the PAEF counter field */
88  if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT)
89  return -2;
90 
91  /* Format the initial tweakey with the key and nonce */
92  memcpy(tweakey, k, 16);
93  memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE);
94  memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0,
95  FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE);
96 
97  /* Tag value starts at zero. We will XOR this with all of the
98  * intermediate tag values that are calculated for each block */
99  memset(tag, 0, sizeof(tag));
100 
101  /* Process the associated data */
102  counter = 1;
103  while (adlen > FORKAE_BLOCK_SIZE) {
104  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0);
105  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad);
106  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
107  ad += FORKAE_BLOCK_SIZE;
108  adlen -= FORKAE_BLOCK_SIZE;
109  ++counter;
110  }
111  if (adlen == FORKAE_BLOCK_SIZE) {
112  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1);
113  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad);
114  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
115  } else if (adlen != 0 || mlen == 0) {
116  unsigned temp = (unsigned)adlen;
117  memcpy(block, ad, temp);
118  block[temp] = 0x80;
119  memset(block + temp + 1, 0, sizeof(block) - temp - 1);
120  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3);
121  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block);
122  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
123  }
124 
125  /* If there is no message payload, then generate the tag and we are done */
126  if (!mlen) {
127  memcpy(c, tag, sizeof(tag));
128  return 0;
129  }
130 
131  /* Encrypt all plaintext blocks except the last */
132  counter = 1;
133  while (mlen > FORKAE_BLOCK_SIZE) {
134  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4);
135  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m);
136  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
137  c += FORKAE_BLOCK_SIZE;
138  m += FORKAE_BLOCK_SIZE;
139  mlen -= FORKAE_BLOCK_SIZE;
140  ++counter;
141  }
142 
143  /* Encrypt the last block and generate the final authentication tag */
144  if (mlen == FORKAE_BLOCK_SIZE) {
145  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5);
146  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m);
147  lw_xor_block(c, tag, FORKAE_BLOCK_SIZE);
148  memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE);
149  } else {
150  unsigned temp = (unsigned)mlen;
151  memcpy(block, m, temp);
152  block[temp] = 0x80;
153  memset(block + temp + 1, 0, sizeof(block) - temp - 1);
154  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7);
155  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block);
156  lw_xor_block(c, tag, FORKAE_BLOCK_SIZE);
157  memcpy(c + FORKAE_BLOCK_SIZE, block, temp);
158  }
159  return 0;
160 }
161 
162 int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt)
163  (unsigned char *m, unsigned long long *mlen,
164  unsigned char *nsec,
165  const unsigned char *c, unsigned long long clen,
166  const unsigned char *ad, unsigned long long adlen,
167  const unsigned char *npub,
168  const unsigned char *k)
169 {
170  unsigned char tweakey[FORKAE_TWEAKEY_SIZE];
171  unsigned char tag[FORKAE_BLOCK_SIZE];
172  unsigned char block[FORKAE_BLOCK_SIZE];
173  unsigned char *mtemp = m;
174  unsigned long long counter;
175  (void)nsec;
176 
177  /* Validate the ciphertext length and set the return "mlen" value */
178  if (clen < FORKAE_BLOCK_SIZE)
179  return -1;
180  clen -= FORKAE_BLOCK_SIZE;
181  *mlen = clen;
182 
183  /* Validate the size of the associated data and plaintext as there
184  * is a limit on the size of the PAEF counter field */
185  if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT)
186  return -2;
187 
188  /* Format the initial tweakey with the key and nonce */
189  memcpy(tweakey, k, 16);
190  memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE);
191  memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0,
192  FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE);
193 
194  /* Tag value starts at zero. We will XOR this with all of the
195  * intermediate tag values that are calculated for each block */
196  memset(tag, 0, sizeof(tag));
197 
198  /* Process the associated data */
199  counter = 1;
200  while (adlen > FORKAE_BLOCK_SIZE) {
201  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0);
202  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad);
203  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
204  ad += FORKAE_BLOCK_SIZE;
205  adlen -= FORKAE_BLOCK_SIZE;
206  ++counter;
207  }
208  if (adlen == FORKAE_BLOCK_SIZE) {
209  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1);
210  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad);
211  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
212  } else if (adlen != 0 || clen == 0) {
213  unsigned temp = (unsigned)adlen;
214  memcpy(block, ad, temp);
215  block[temp] = 0x80;
216  memset(block + temp + 1, 0, sizeof(block) - temp - 1);
217  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3);
218  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block);
219  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
220  }
221 
222  /* If there is no message payload, then check the tag and we are done */
223  if (!clen)
224  return aead_check_tag(m, clen, tag, c, sizeof(tag));
225 
226  /* Decrypt all ciphertext blocks except the last */
227  counter = 1;
228  while (clen > FORKAE_BLOCK_SIZE) {
229  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4);
230  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c);
231  lw_xor_block(tag, block, FORKAE_BLOCK_SIZE);
232  c += FORKAE_BLOCK_SIZE;
233  m += FORKAE_BLOCK_SIZE;
234  clen -= FORKAE_BLOCK_SIZE;
235  ++counter;
236  }
237 
238  /* Decrypt the last block and check the final authentication tag */
239  if (clen == FORKAE_BLOCK_SIZE) {
240  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5);
241  lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE);
242  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m);
243  return aead_check_tag
244  (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag));
245  } else {
246  unsigned temp = (unsigned)clen;
247  unsigned char block2[FORKAE_BLOCK_SIZE];
248  int check;
249  FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7);
250  lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE);
251  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)
252  (tweakey, block2, block, block2);
253  check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding)
254  (block2 + temp, FORKAE_BLOCK_SIZE - temp);
255  memcpy(m, block2, temp);
257  (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check);
258  }
259 }
260 
261 #endif /* FORKAE_ALG_NAME */
262 
263 /* Now undefine everything so that we can include this file again for
264  * another variant on the ForkAE PAEF algorithm */
265 #undef FORKAE_ALG_NAME
266 #undef FORKAE_BLOCK_SIZE
267 #undef FORKAE_NONCE_SIZE
268 #undef FORKAE_COUNTER_SIZE
269 #undef FORKAE_TWEAKEY_SIZE
270 #undef FORKAE_BLOCK_FUNC
271 #undef FORKAE_CONCAT_INNER
272 #undef FORKAE_CONCAT
273 #undef FORKAE_PAEF_DATA_LIMIT
int aead_check_tag(unsigned char *plaintext, unsigned long long plaintext_len, const unsigned char *tag1, const unsigned char *tag2, unsigned tag_len)
Check an authentication tag in constant time.
Definition: aead-common.c:26
int aead_check_tag_precheck(unsigned char *plaintext, unsigned long long plaintext_len, const unsigned char *tag1, const unsigned char *tag2, unsigned tag_len, int precheck)
Check an authentication tag in constant time with a previous check.
Definition: aead-common.c:49