Arduino Cryptography Library
Ascon128.cpp
1 /*
2  * Copyright (C) 2018 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 #include "Ascon128.h"
24 #include "Crypto.h"
25 #include "utility/EndianUtil.h"
26 #include "utility/RotateUtil.h"
27 #include "utility/ProgMemUtil.h"
28 #include <string.h>
29 
49 #if defined(CRYPTO_LITTLE_ENDIAN)
50  : posn(7)
51  , authMode(1)
52 #else
53  : posn(0)
54  , authMode(1)
55 #endif
56 {
57 }
58 
63 {
64  clean(state);
65 }
66 
72 size_t Ascon128::keySize() const
73 {
74  return 16;
75 }
76 
85 size_t Ascon128::ivSize() const
86 {
87  return 16;
88 }
89 
95 size_t Ascon128::tagSize() const
96 {
97  return 16;
98 }
99 
100 bool Ascon128::setKey(const uint8_t *key, size_t len)
101 {
102  if (len != 16)
103  return false;
104  memcpy(state.K, key, 16);
105 #if defined(CRYPTO_LITTLE_ENDIAN)
106  state.K[0] = be64toh(state.K[0]);
107  state.K[1] = be64toh(state.K[1]);
108 #endif
109  return true;
110 }
111 
112 bool Ascon128::setIV(const uint8_t *iv, size_t len)
113 {
114  // Validate the length of the IV.
115  if (len != 16)
116  return false;
117 
118  // Set up the initial state.
119  state.S[0] = 0x80400C0600000000ULL;
120  state.S[1] = state.K[0];
121  state.S[2] = state.K[1];
122  memcpy(state.S + 3, iv, 16);
123 #if defined(CRYPTO_LITTLE_ENDIAN)
124  state.S[3] = be64toh(state.S[3]);
125  state.S[4] = be64toh(state.S[4]);
126  posn = 7;
127  authMode = 1;
128 #else
129  posn = 0;
130  authMode = 1;
131 #endif
132 
133  // Permute the state with 12 rounds starting at round 0.
134  permute(0);
135 
136  // XOR the end of the state with the original key.
137  state.S[3] ^= state.K[0];
138  state.S[4] ^= state.K[1];
139  return true;
140 }
141 
142 void Ascon128::encrypt(uint8_t *output, const uint8_t *input, size_t len)
143 {
144  if (authMode)
145  endAuth();
146  const uint8_t *in = (const uint8_t *)input;
147  uint8_t *out = (uint8_t *)output;
148  while (len > 0) {
149  // Encrypt the next byte using the first 64-bit word in the state.
150  ((uint8_t *)(state.S))[posn] ^= *in++;
151  *out++ = ((const uint8_t *)(state.S))[posn];
152  --len;
153 
154  // Permute the state for b = 6 rounds at the end of each block.
155 #if defined(CRYPTO_LITTLE_ENDIAN)
156  if (posn > 0) {
157  --posn;
158  } else {
159  permute(6);
160  posn = 7;
161  }
162 #else
163  if ((++posn) == 8) {
164  permute(6);
165  posn = 0;
166  }
167 #endif
168  }
169 }
170 
171 void Ascon128::decrypt(uint8_t *output, const uint8_t *input, size_t len)
172 {
173  if (authMode)
174  endAuth();
175  const uint8_t *in = (const uint8_t *)input;
176  uint8_t *out = (uint8_t *)output;
177  while (len > 0) {
178  // Decrypt the next byte using the first 64-bit word in the state.
179  *out++ = ((const uint8_t *)(state.S))[posn] ^ *in;
180  ((uint8_t *)(state.S))[posn] = *in++;
181  --len;
182 
183  // Permute the state for b = 6 rounds at the end of each block.
184 #if defined(CRYPTO_LITTLE_ENDIAN)
185  if (posn > 0) {
186  --posn;
187  } else {
188  permute(6);
189  posn = 7;
190  }
191 #else
192  if ((++posn) == 8) {
193  permute(6);
194  posn = 0;
195  }
196 #endif
197  }
198 }
199 
200 void Ascon128::addAuthData(const void *data, size_t len)
201 {
202  if (!authMode)
203  return;
204  const uint8_t *in = (const uint8_t *)data;
205  while (len > 0) {
206  // Incorporate the next byte of auth data into the internal state.
207  ((uint8_t *)(state.S))[posn] ^= *in++;
208  --len;
209 
210  // Permute the state for b = 6 rounds at the end of each block.
211 #if defined(CRYPTO_LITTLE_ENDIAN)
212  if (posn > 0) {
213  --posn;
214  } else {
215  permute(6);
216  posn = 7;
217  }
218 #else
219  if ((++posn) == 8) {
220  permute(6);
221  posn = 0;
222  }
223 #endif
224  }
225  authMode = 2; // We have some auth data now.
226 }
227 
228 void Ascon128::computeTag(void *tag, size_t len)
229 {
230  // End authentication mode if there was no plaintext/ciphertext.
231  if (authMode)
232  endAuth();
233 
234  // Pad the last block, add the original key, and permute the state.
235  ((uint8_t *)(state.S))[posn] ^= 0x80;
236  state.S[1] ^= state.K[0];
237  state.S[2] ^= state.K[1];
238  permute(0);
239 
240  // Compute the tag and convert it into big-endian in the return buffer.
241  uint64_t T[2];
242  T[0] = htobe64(state.S[3] ^ state.K[0]);
243  T[1] = htobe64(state.S[4] ^ state.K[1]);
244  if (len > 16)
245  len = 16;
246  memcpy(tag, T, len);
247  clean(T);
248 }
249 
250 bool Ascon128::checkTag(const void *tag, size_t len)
251 {
252  // The tag can never match if it is larger than the maximum allowed size.
253  if (len > 16)
254  return false;
255 
256  // End authentication mode if there was no plaintext/ciphertext.
257  if (authMode)
258  endAuth();
259 
260  // Pad the last block, add the original key, and permute the state.
261  ((uint8_t *)(state.S))[posn] ^= 0x80;
262  state.S[1] ^= state.K[0];
263  state.S[2] ^= state.K[1];
264  permute(0);
265 
266  // Compute the tag and convert it into big-endian.
267  uint64_t T[2];
268  T[0] = htobe64(state.S[3] ^ state.K[0]);
269  T[1] = htobe64(state.S[4] ^ state.K[1]);
270  if (len > 16)
271  len = 16;
272  bool ok = secure_compare(T, tag, len);
273  clean(T);
274  return ok;
275 }
276 
281 {
282  clean(state);
283 #if defined(CRYPTO_LITTLE_ENDIAN)
284  posn = 7;
285  authMode = 1;
286 #else
287  posn = 0;
288  authMode = 1;
289 #endif
290 }
291 
292 #if !defined(__AVR__) || defined(CRYPTO_DOC)
293 
299 void Ascon128::permute(uint8_t first)
300 {
301  uint64_t t0, t1, t2, t3, t4;
302  #define x0 state.S[0]
303  #define x1 state.S[1]
304  #define x2 state.S[2]
305  #define x3 state.S[3]
306  #define x4 state.S[4]
307  while (first < 12) {
308  // Add the round constant to the state.
309  x2 ^= ((0x0F - first) << 4) | first;
310 
311  // Substitution layer - apply the s-box using bit-slicing
312  // according to the algorithm recommended in the specification.
313  x0 ^= x4; x4 ^= x3; x2 ^= x1;
314  t0 = ~x0; t1 = ~x1; t2 = ~x2; t3 = ~x3; t4 = ~x4;
315  t0 &= x1; t1 &= x2; t2 &= x3; t3 &= x4; t4 &= x0;
316  x0 ^= t1; x1 ^= t2; x2 ^= t3; x3 ^= t4; x4 ^= t0;
317  x1 ^= x0; x0 ^= x4; x3 ^= x2; x2 = ~x2;
318 
319  // Linear diffusion layer.
320  x0 ^= rightRotate19_64(x0) ^ rightRotate28_64(x0);
321  x1 ^= rightRotate61_64(x1) ^ rightRotate39_64(x1);
322  x2 ^= rightRotate1_64(x2) ^ rightRotate6_64(x2);
323  x3 ^= rightRotate10_64(x3) ^ rightRotate17_64(x3);
324  x4 ^= rightRotate7_64(x4) ^ rightRotate41_64(x4);
325 
326  // Move onto the next round.
327  ++first;
328  }
329  #undef x0
330  #undef x1
331  #undef x2
332  #undef x3
333  #undef x4
334 }
335 
336 #endif // !__AVR__
337 
341 void Ascon128::endAuth()
342 {
343  if (authMode == 2) {
344  // We had some auth data, so we need to pad and permute the last block.
345  // There is no need to do this if there were zero bytes of auth data.
346  ((uint8_t *)(state.S))[posn] ^= 0x80;
347  permute(6);
348  }
349  state.S[4] ^= 1; // Domain separation between auth data and payload data.
350  authMode = 0;
351 #if defined(CRYPTO_LITTLE_ENDIAN)
352  posn = 7;
353 #else
354  posn = 0;
355 #endif
356 }
Ascon128()
Constructs a new Ascon128 authenticated cipher.
Definition: Ascon128.cpp:48
size_t keySize() const
Gets the size of the Ascon128 key in bytes.
Definition: Ascon128.cpp:72
size_t tagSize() const
Gets the size of the Ascon128 authentication tag in bytes.
Definition: Ascon128.cpp:95
void decrypt(uint8_t *output, const uint8_t *input, size_t len)
Decrypts an input buffer and writes the plaintext to an output buffer.
Definition: Ascon128.cpp:171
void encrypt(uint8_t *output, const uint8_t *input, size_t len)
Encrypts an input buffer and writes the ciphertext to an output buffer.
Definition: Ascon128.cpp:142
bool setIV(const uint8_t *iv, size_t len)
Sets the initialization vector to use for future encryption and decryption operations.
Definition: Ascon128.cpp:112
void clear()
Clears all security-sensitive state from this cipher object.
Definition: Ascon128.cpp:280
bool checkTag(const void *tag, size_t len)
Finalizes the decryption process and checks the authentication tag.
Definition: Ascon128.cpp:250
virtual ~Ascon128()
Destroys this Ascon128 authenticated cipher.
Definition: Ascon128.cpp:62
void addAuthData(const void *data, size_t len)
Adds extra data that will be authenticated but not encrypted.
Definition: Ascon128.cpp:200
void computeTag(void *tag, size_t len)
Finalizes the encryption process and computes the authentication tag.
Definition: Ascon128.cpp:228
size_t ivSize() const
Gets the size of the Ascon128 initialization vector in bytes.
Definition: Ascon128.cpp:85
bool setKey(const uint8_t *key, size_t len)
Sets the key to use for future encryption and decryption operations.
Definition: Ascon128.cpp:100