Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-forkae-saef.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 SAEF variant.
25  *
26  * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_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_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher.
30  * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding.
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 /* Check that the last block is padded correctly; -1 if ok, 0 if not */
39 STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding)
40  (const unsigned char *block, unsigned len)
41 {
42  int check = block[0] ^ 0x80;
43  while (len > 1) {
44  --len;
45  check |= block[len];
46  }
47  return (check - 1) >> 8;
48 }
49 
50 int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt)
51  (unsigned char *c, unsigned long long *clen,
52  const unsigned char *m, unsigned long long mlen,
53  const unsigned char *ad, unsigned long long adlen,
54  const unsigned char *nsec,
55  const unsigned char *npub,
56  const unsigned char *k)
57 {
58  unsigned char tweakey[FORKAE_TWEAKEY_SIZE];
59  unsigned char tag[FORKAE_BLOCK_SIZE];
60  unsigned char block[FORKAE_BLOCK_SIZE];
61  (void)nsec;
62 
63  /* Set the length of the returned ciphertext */
64  *clen = mlen + FORKAE_BLOCK_SIZE;
65 
66  /* Format the initial tweakey with the key and nonce */
67  memcpy(tweakey, k, 16);
68  memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE);
69  memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0,
70  FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE);
71  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08;
72 
73  /* Tag value starts at zero */
74  memset(tag, 0, sizeof(tag));
75 
76  /* Process the associated data */
77  if (adlen > 0 || mlen == 0) {
78  while (adlen > FORKAE_BLOCK_SIZE) {
79  lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE);
80  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
81  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
82  ad += FORKAE_BLOCK_SIZE;
83  adlen -= FORKAE_BLOCK_SIZE;
84  }
85  if (mlen == 0)
86  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04;
87  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02;
88  if (adlen == FORKAE_BLOCK_SIZE) {
89  lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE);
90  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
91  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
92  } else if (adlen != 0 || mlen == 0) {
93  unsigned temp = (unsigned)adlen;
94  lw_xor_block(tag, ad, temp);
95  tag[temp] ^= 0x80;
96  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01;
97  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
98  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
99  }
100  }
101 
102  /* If there is no message payload, then generate the tag and we are done */
103  if (!mlen) {
104  memcpy(c, tag, sizeof(tag));
105  return 0;
106  }
107 
108  /* Encrypt all plaintext blocks except the last */
109  while (mlen > FORKAE_BLOCK_SIZE) {
110  lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE);
111  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01;
112  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block);
113  lw_xor_block(c, tag, FORKAE_BLOCK_SIZE);
114  memcpy(tag, block, FORKAE_BLOCK_SIZE);
115  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
116  c += FORKAE_BLOCK_SIZE;
117  m += FORKAE_BLOCK_SIZE;
118  mlen -= FORKAE_BLOCK_SIZE;
119  }
120 
121  /* Encrypt the last block and generate the final authentication tag */
122  if (mlen == FORKAE_BLOCK_SIZE) {
123  lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE);
124  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04;
125  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block);
126  lw_xor_block(c, tag, FORKAE_BLOCK_SIZE);
127  memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE);
128  } else {
129  unsigned temp = (unsigned)mlen;
130  memcpy(block, tag, FORKAE_BLOCK_SIZE);
131  lw_xor_block(block, m, temp);
132  block[temp] ^= 0x80;
133  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05;
134  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block);
135  lw_xor_block(c, tag, FORKAE_BLOCK_SIZE);
136  memcpy(c + FORKAE_BLOCK_SIZE, block, temp);
137  }
138  return 0;
139 }
140 
141 int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt)
142  (unsigned char *m, unsigned long long *mlen,
143  unsigned char *nsec,
144  const unsigned char *c, unsigned long long clen,
145  const unsigned char *ad, unsigned long long adlen,
146  const unsigned char *npub,
147  const unsigned char *k)
148 {
149  unsigned char tweakey[FORKAE_TWEAKEY_SIZE];
150  unsigned char tag[FORKAE_BLOCK_SIZE];
151  unsigned char block[FORKAE_BLOCK_SIZE];
152  unsigned char *mtemp = m;
153  (void)nsec;
154 
155  /* Validate the ciphertext length and set the return "mlen" value */
156  if (clen < FORKAE_BLOCK_SIZE)
157  return -1;
158  clen -= FORKAE_BLOCK_SIZE;
159  *mlen = clen;
160 
161  /* Format the initial tweakey with the key and nonce */
162  memcpy(tweakey, k, 16);
163  memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE);
164  memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0,
165  FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE);
166  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08;
167 
168  /* Tag value starts at zero */
169  memset(tag, 0, sizeof(tag));
170 
171  /* Process the associated data */
172  if (adlen > 0 || clen == 0) {
173  while (adlen > FORKAE_BLOCK_SIZE) {
174  lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE);
175  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
176  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
177  ad += FORKAE_BLOCK_SIZE;
178  adlen -= FORKAE_BLOCK_SIZE;
179  }
180  if (clen == 0)
181  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04;
182  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02;
183  if (adlen == FORKAE_BLOCK_SIZE) {
184  lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE);
185  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
186  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
187  } else if (adlen != 0 || clen == 0) {
188  unsigned temp = (unsigned)adlen;
189  lw_xor_block(tag, ad, temp);
190  tag[temp] ^= 0x80;
191  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01;
192  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag);
193  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
194  }
195  }
196 
197  /* If there is no message payload, then check the tag and we are done */
198  if (!clen)
199  return aead_check_tag(m, clen, tag, c, sizeof(tag));
200 
201  /* Decrypt all ciphertext blocks except the last */
202  while (clen > FORKAE_BLOCK_SIZE) {
203  lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE);
204  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01;
205  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block);
206  lw_xor_block(m, tag, FORKAE_BLOCK_SIZE);
207  memcpy(tag, block, FORKAE_BLOCK_SIZE);
208  memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16);
209  c += FORKAE_BLOCK_SIZE;
210  m += FORKAE_BLOCK_SIZE;
211  clen -= FORKAE_BLOCK_SIZE;
212  }
213 
214  /* Decrypt the last block and check the final authentication tag */
215  if (clen == FORKAE_BLOCK_SIZE) {
216  lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE);
217  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04;
218  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block);
219  lw_xor_block(m, tag, FORKAE_BLOCK_SIZE);
220  return aead_check_tag
221  (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE);
222  } else {
223  unsigned temp = (unsigned)clen;
224  unsigned char mblock[FORKAE_BLOCK_SIZE];
225  int check;
226  lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE);
227  tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05;
228  FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)
229  (tweakey, mblock, block, block);
230  lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE);
231  memcpy(m, mblock, temp);
232  check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding)
233  (mblock + temp, FORKAE_BLOCK_SIZE - temp);
235  (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check);
236  }
237 }
238 
239 #endif /* FORKAE_ALG_NAME */
240 
241 /* Now undefine everything so that we can include this file again for
242  * another variant on the ForkAE SAEF algorithm */
243 #undef FORKAE_ALG_NAME
244 #undef FORKAE_BLOCK_SIZE
245 #undef FORKAE_NONCE_SIZE
246 #undef FORKAE_COUNTER_SIZE
247 #undef FORKAE_TWEAKEY_SIZE
248 #undef FORKAE_TWEAKEY_REDUCED_SIZE
249 #undef FORKAE_BLOCK_FUNC
250 #undef FORKAE_CONCAT_INNER
251 #undef FORKAE_CONCAT
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