Lightweight Cryptography Primitives
 All Data Structures Files Functions Variables Typedefs Macros Pages
internal-elephant.h
1 /*
2  * Copyright (C) 2021 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 /*
24  * The contents of this header file expand out to the full implementation of
25  * Elephant for a specific underlying permutation. We expect a number of
26  * macros to be defined before this file is included to configure the
27  * underlying Elephant variant:
28  *
29  * ELEPHANT_ALG_NAME Name of the Elephant algorithm; e.g. dumbo
30  * ELEPHANT_STATE_SIZE Size of the permutation state.
31  * ELEPHANT_STATE Permutation state type; e.g. keccakp_200_state_t
32  * ELEPHANT_KEY_SIZE Size of the key
33  * ELEPHANT_NONCE_SIZE Size of the nonce
34  * ELEPHANT_TAG_SIZE Size of the tag
35  * ELEPHANT_LFSR Name of the LFSR function; e.g. dumbo_lfsr
36  * ELEPHANT_PERMUTE Name of the permutation function
37  */
38 #if defined(ELEPHANT_ALG_NAME)
39 
40 #define ELEPHANT_CONCAT_INNER(name,suffix) name##suffix
41 #define ELEPHANT_CONCAT(name,suffix) ELEPHANT_CONCAT_INNER(name,suffix)
42 
43 static int ELEPHANT_CONCAT(ELEPHANT_ALG_NAME,_aead_crypt)
44  (unsigned char *c, const unsigned char *m, size_t mlen,
45  const unsigned char *ad, size_t adlen,
46  const unsigned char *npub, const unsigned char *k,
47  int encrypt)
48 {
49  unsigned char *cstart = c;
50  size_t clen = mlen;
51  ELEPHANT_STATE state;
52  unsigned char start[ELEPHANT_STATE_SIZE];
53  unsigned char mask1[ELEPHANT_STATE_SIZE];
54  unsigned char mask2[ELEPHANT_STATE_SIZE];
55  unsigned char mask3[ELEPHANT_STATE_SIZE];
56  unsigned char tag[ELEPHANT_STATE_SIZE];
57  unsigned char *m0;
58  unsigned char *m1 = mask1;
59  unsigned char *m2 = mask2;
60  unsigned char *m3 = mask3;
61  int admore, mmore;
62 
63  /* Hash the key and generate the starting mask */
64  memcpy(state.B, k, ELEPHANT_KEY_SIZE);
65  memset(state.B + ELEPHANT_KEY_SIZE, 0, sizeof(state.B) - ELEPHANT_KEY_SIZE);
66  ELEPHANT_PERMUTE(&state);
67  memcpy(start, state.B, ELEPHANT_STATE_SIZE);
68 
69  /* Compute the initial 0, 1, and 2 mask values */
70  memcpy(m1, start, ELEPHANT_STATE_SIZE);
71  ELEPHANT_LFSR(m2, m1);
72  ELEPHANT_LFSR(m3, m2);
73 
74  /* The initial tag is the nonce concatenated with the first block of ad */
75  memcpy(tag, npub, ELEPHANT_NONCE_SIZE);
76  if (adlen >= (ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE)) {
77  memcpy(tag + ELEPHANT_NONCE_SIZE, ad,
78  ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE);
79  ad += ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE;
80  adlen -= ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE;
81  admore = 1;
82  } else {
83  memcpy(tag + ELEPHANT_NONCE_SIZE, ad, adlen);
84  tag[ELEPHANT_NONCE_SIZE + adlen] = 0x01;
85  memset(tag + ELEPHANT_NONCE_SIZE + adlen + 1, 0,
86  ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE - (adlen + 1));
87  admore = 0;
88  adlen = 0;
89  }
90 
91  /* Process associated data and message blocks until we are out */
92  mmore = 1;
93  for (;;) {
94  /* Encrypt or decrypt the next message block */
95  if (mmore) {
96  if (encrypt) {
97  /* Encrypt the plaintext message block */
98  lw_xor_block_2_src(state.B, npub, m1, ELEPHANT_NONCE_SIZE);
99  memcpy(state.B + ELEPHANT_NONCE_SIZE, m1 + ELEPHANT_NONCE_SIZE,
100  ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE);
101  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
102  ELEPHANT_PERMUTE(&state);
103  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
104  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
105  if (mlen >= ELEPHANT_STATE_SIZE) {
106  lw_xor_block_2_dest(c, state.B, m, ELEPHANT_STATE_SIZE);
107  c += ELEPHANT_STATE_SIZE;
108  m += ELEPHANT_STATE_SIZE;
109  mlen -= ELEPHANT_STATE_SIZE;
110  } else {
111  lw_xor_block_2_dest(c, state.B, m, mlen);
112  state.B[mlen] = 0x01;
113  memset(state.B + mlen + 1, 0,
114  ELEPHANT_STATE_SIZE - mlen - 1);
115  c += mlen;
116  m += mlen;
117  mlen = 0;
118  mmore = 0;
119  }
120 
121  /* Authenticate the outgoing ciphertext message block */
122  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
123  lw_xor_block(state.B, m3, ELEPHANT_STATE_SIZE);
124  ELEPHANT_PERMUTE(&state);
125  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
126  lw_xor_block(state.B, m3, ELEPHANT_STATE_SIZE);
127  lw_xor_block(tag, state.B, ELEPHANT_STATE_SIZE);
128  } else {
129  /* Authenticate the incoming ciphertext message block */
130  if (mlen >= ELEPHANT_STATE_SIZE) {
131  lw_xor_block_2_src(state.B, m, m1, ELEPHANT_STATE_SIZE);
132  } else {
133  memcpy(state.B, m, mlen);
134  state.B[mlen] = 0x01;
135  memset(state.B + mlen + 1, 0,
136  ELEPHANT_STATE_SIZE - mlen - 1);
137  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
138  }
139  lw_xor_block(state.B, m3, ELEPHANT_STATE_SIZE);
140  ELEPHANT_PERMUTE(&state);
141  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
142  lw_xor_block(state.B, m3, ELEPHANT_STATE_SIZE);
143  lw_xor_block(tag, state.B, ELEPHANT_STATE_SIZE);
144 
145  /* Decrypt the ciphertext message block */
146  lw_xor_block_2_src(state.B, npub, m1, ELEPHANT_NONCE_SIZE);
147  memcpy(state.B + ELEPHANT_NONCE_SIZE, m1 + ELEPHANT_NONCE_SIZE,
148  ELEPHANT_STATE_SIZE - ELEPHANT_NONCE_SIZE);
149  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
150  ELEPHANT_PERMUTE(&state);
151  lw_xor_block(state.B, m1, ELEPHANT_STATE_SIZE);
152  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
153  if (mlen >= ELEPHANT_STATE_SIZE) {
154  lw_xor_block_2_src(c, state.B, m, ELEPHANT_STATE_SIZE);
155  c += ELEPHANT_STATE_SIZE;
156  m += ELEPHANT_STATE_SIZE;
157  mlen -= ELEPHANT_STATE_SIZE;
158  } else {
159  lw_xor_block_2_src(c, state.B, m, mlen);
160  c += mlen;
161  m += mlen;
162  mlen = 0;
163  mmore = 0;
164  }
165  }
166  }
167 
168  /* Authenticate the next associated data block */
169  if (admore) {
170  if (adlen >= ELEPHANT_STATE_SIZE) {
171  lw_xor_block_2_src(state.B, ad, m2, ELEPHANT_STATE_SIZE);
172  ad += ELEPHANT_STATE_SIZE;
173  adlen -= ELEPHANT_STATE_SIZE;
174  } else {
175  memcpy(state.B, ad, adlen);
176  state.B[adlen] = 0x01;
177  memset(state.B + adlen + 1, 0, ELEPHANT_STATE_SIZE - adlen - 1);
178  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
179  admore = 0;
180  adlen = 0;
181  }
182  ELEPHANT_PERMUTE(&state);
183  lw_xor_block(state.B, m2, ELEPHANT_STATE_SIZE);
184  lw_xor_block(tag, state.B, ELEPHANT_STATE_SIZE);
185  }
186 
187  /* Bail out if no more blocks to be processed */
188  if (!admore && !mmore)
189  break;
190 
191  /* Rotate the masks */
192  m0 = m1;
193  m1 = m2;
194  m2 = m3;
195  m3 = m0;
196  ELEPHANT_LFSR(m3, m2);
197  }
198 
199  /* Compute the authentication tag */
200  lw_xor_block_2_src(state.B, tag, start, ELEPHANT_STATE_SIZE);
201  ELEPHANT_PERMUTE(&state);
202  if (encrypt) {
203  lw_xor_block_2_src(c, state.B, start, ELEPHANT_TAG_SIZE);
204  return 0;
205  } else {
206  lw_xor_block(state.B, start, ELEPHANT_TAG_SIZE);
207  return aead_check_tag(cstart, clen, state.B, m, ELEPHANT_TAG_SIZE);
208  }
209 }
210 
211 int ELEPHANT_CONCAT(ELEPHANT_ALG_NAME,_aead_encrypt)
212  (unsigned char *c, size_t *clen,
213  const unsigned char *m, size_t mlen,
214  const unsigned char *ad, size_t adlen,
215  const unsigned char *npub,
216  const unsigned char *k)
217 {
218  /* Set the length of the returned ciphertext */
219  *clen = mlen + ELEPHANT_TAG_SIZE;
220 
221  /* Encrypt the message and authenticate it */
222  return ELEPHANT_CONCAT(ELEPHANT_ALG_NAME,_aead_crypt)
223  (c, m, mlen, ad, adlen, npub, k, 1);
224 }
225 
226 int ELEPHANT_CONCAT(ELEPHANT_ALG_NAME,_aead_decrypt)
227  (unsigned char *m, size_t *mlen,
228  const unsigned char *c, size_t clen,
229  const unsigned char *ad, size_t adlen,
230  const unsigned char *npub,
231  const unsigned char *k)
232 {
233  /* Validate the ciphertext length and set the return "mlen" value */
234  if (clen < ELEPHANT_TAG_SIZE)
235  return -1;
236  clen -= ELEPHANT_TAG_SIZE;
237  *mlen = clen;
238 
239  /* Decrypt the message and authenticate it */
240  return ELEPHANT_CONCAT(ELEPHANT_ALG_NAME,_aead_crypt)
241  (m, c, clen, ad, adlen, npub, k, 0);
242 }
243 
244 #endif /* ELEPHANT_ALG_NAME */
245 
246 /* Now undefine everything so that we can include this file again for
247  * another variant on the Elephant algorithm */
248 #undef ELEPHANT_ALG_NAME
249 #undef ELEPHANT_STATE_SIZE
250 #undef ELEPHANT_STATE
251 #undef ELEPHANT_KEY_SIZE
252 #undef ELEPHANT_NONCE_SIZE
253 #undef ELEPHANT_TAG_SIZE
254 #undef ELEPHANT_LFSR
255 #undef ELEPHANT_PERMUTE
256 #undef ELEPHANT_CONCAT
257 #undef ELEPHANT_CONCAT_INNER