Arduino Cryptography Library
Speck.cpp
1 /*
2  * Copyright (C) 2015 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 "Speck.h"
24 #include "Crypto.h"
25 #include "utility/RotateUtil.h"
26 #include "utility/EndianUtil.h"
27 #include <string.h>
28 
56 // The "avr-gcc" compiler doesn't do a very good job of compiling
57 // code involving 64-bit values. So we have to use inline assembly.
58 // It also helps to break the state up into 32-bit quantities
59 // because "asm" supports register names like %A0, %B0, %C0, %D0
60 // for the bytes in a 32-bit quantity, but it does not support
61 // %E0, %F0, %G0, %H0 for the high bytes of a 64-bit quantity.
62 #if defined(__AVR__)
63 #define USE_AVR_INLINE_ASM 1
64 #endif
65 
73  : rounds(32)
74 {
75 }
76 
77 Speck::~Speck()
78 {
79  clean(k);
80 }
81 
82 size_t Speck::blockSize() const
83 {
84  return 16;
85 }
86 
87 size_t Speck::keySize() const
88 {
89  // Also supports 128-bit and 192-bit, but we only report 256-bit.
90  return 32;
91 }
92 
93 // Pack/unpack byte-aligned big-endian 64-bit quantities.
94 #define pack64(data, value) \
95  do { \
96  uint64_t v = htobe64((value)); \
97  memcpy((data), &v, sizeof(uint64_t)); \
98  } while (0)
99 #define unpack64(value, data) \
100  do { \
101  memcpy(&(value), (data), sizeof(uint64_t)); \
102  (value) = be64toh((value)); \
103  } while (0)
104 
105 bool Speck::setKey(const uint8_t *key, size_t len)
106 {
107 #if USE_AVR_INLINE_ASM
108  // Automatically generated by the genspeck tool.
109  uint64_t l[4];
110  uint8_t m, mb;
111  if (len == 32) {
112  m = 4;
113  mb = 3 * 8;
114  } else if (len == 24) {
115  m = 3;
116  mb = 2 * 8;
117  } else if (len == 16) {
118  m = 2;
119  mb = 8;
120  } else {
121  return false;
122  }
123  rounds = 30 + m;
124  uint8_t r = rounds - 1;
125  __asm__ __volatile__ (
126  "ld __tmp_reg__,-X\n"
127  "st Z+,__tmp_reg__\n"
128  "ld __tmp_reg__,-X\n"
129  "st Z+,__tmp_reg__\n"
130  "ld __tmp_reg__,-X\n"
131  "st Z+,__tmp_reg__\n"
132  "ld __tmp_reg__,-X\n"
133  "st Z+,__tmp_reg__\n"
134  "ld __tmp_reg__,-X\n"
135  "st Z+,__tmp_reg__\n"
136  "ld __tmp_reg__,-X\n"
137  "st Z+,__tmp_reg__\n"
138  "ld __tmp_reg__,-X\n"
139  "st Z+,__tmp_reg__\n"
140  "ld __tmp_reg__,-X\n"
141  "st Z+,__tmp_reg__\n"
142  "sbiw r30,8\n"
143  "movw r10,r30\n"
144  "movw r30,%A2\n"
145  "ldd r8,%3\n"
146  "1:\n"
147  "ld __tmp_reg__,-X\n"
148  "st Z+,__tmp_reg__\n"
149  "dec r8\n"
150  "brne 1b\n"
151  "movw r26,%A2\n"
152  "movw r30,r10\n"
153  "clr %A2\n"
154  "ldd %B2,%3\n"
155  "clr r25\n"
156  "ld r16,Z+\n"
157  "ld r17,Z+\n"
158  "ld r18,Z+\n"
159  "ld r19,Z+\n"
160  "ld r20,Z+\n"
161  "ld r21,Z+\n"
162  "ld r22,Z+\n"
163  "ld r23,Z+\n"
164  "2:\n"
165  "add r26,%A2\n"
166  "adc r27,__zero_reg__\n"
167  "ld r15,X+\n"
168  "ld r8,X+\n"
169  "ld r9,X+\n"
170  "ld r10,X+\n"
171  "ld r11,X+\n"
172  "ld r12,X+\n"
173  "ld r13,X+\n"
174  "ld r14,X+\n"
175  "sub r26,%A2\n"
176  "sbc r27,__zero_reg__\n"
177  "sbiw r26,8\n"
178  "add r8,r16\n"
179  "adc r9,r17\n"
180  "adc r10,r18\n"
181  "adc r11,r19\n"
182  "adc r12,r20\n"
183  "adc r13,r21\n"
184  "adc r14,r22\n"
185  "adc r15,r23\n"
186  "eor r8,r25\n"
187  "add r26,%B2\n"
188  "adc r27,__zero_reg__\n"
189  "st X+,r8\n"
190  "st X+,r9\n"
191  "st X+,r10\n"
192  "st X+,r11\n"
193  "st X+,r12\n"
194  "st X+,r13\n"
195  "st X+,r14\n"
196  "st X+,r15\n"
197  "sub r26,%B2\n"
198  "sbc r27,__zero_reg__\n"
199  "sbiw r26,8\n"
200  "lsl r16\n"
201  "rol r17\n"
202  "rol r18\n"
203  "rol r19\n"
204  "rol r20\n"
205  "rol r21\n"
206  "rol r22\n"
207  "rol r23\n"
208  "adc r16, __zero_reg__\n"
209  "lsl r16\n"
210  "rol r17\n"
211  "rol r18\n"
212  "rol r19\n"
213  "rol r20\n"
214  "rol r21\n"
215  "rol r22\n"
216  "rol r23\n"
217  "adc r16, __zero_reg__\n"
218  "lsl r16\n"
219  "rol r17\n"
220  "rol r18\n"
221  "rol r19\n"
222  "rol r20\n"
223  "rol r21\n"
224  "rol r22\n"
225  "rol r23\n"
226  "adc r16, __zero_reg__\n"
227  "eor r16,r8\n"
228  "eor r17,r9\n"
229  "eor r18,r10\n"
230  "eor r19,r11\n"
231  "eor r20,r12\n"
232  "eor r21,r13\n"
233  "eor r22,r14\n"
234  "eor r23,r15\n"
235  "st Z+,r16\n"
236  "st Z+,r17\n"
237  "st Z+,r18\n"
238  "st Z+,r19\n"
239  "st Z+,r20\n"
240  "st Z+,r21\n"
241  "st Z+,r22\n"
242  "st Z+,r23\n"
243  "ldi r24,8\n"
244  "add %A2,r24\n"
245  "add %B2,r24\n"
246  "ldi r24,0x1F\n"
247  "and %A2,r24\n"
248  "and %B2,r24\n"
249  "ldd r8,%4\n"
250  "inc r25\n"
251  "cp r25,r8\n"
252  "breq 3f\n"
253  "rjmp 2b\n"
254  "3:\n"
255  "ldi r24,32\n"
256  "4:\n"
257  "st X+,__zero_reg__\n"
258  "dec r24\n"
259  "brne 4b\n"
260  : : "z"(k), "x"(key + len), "r"(l), "Q"(mb), "Q"(r)
261  : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
262  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "memory"
263  , "r24", "r25"
264  );
265  return true;
266 #else
267  uint64_t l[4];
268  uint8_t m;
269  if (len == 32) {
270  m = 4;
271  unpack64(l[2], key);
272  unpack64(l[1], key + 8);
273  unpack64(l[0], key + 16);
274  unpack64(k[0], key + 24);
275  } else if (len == 24) {
276  m = 3;
277  unpack64(l[1], key);
278  unpack64(l[0], key + 8);
279  unpack64(k[0], key + 16);
280  } else if (len == 16) {
281  m = 2;
282  unpack64(l[0], key);
283  unpack64(k[0], key + 8);
284  } else {
285  return false;
286  }
287  rounds = 30 + m;
288  uint8_t li_in = 0;
289  uint8_t li_out = m - 1;
290  for (uint8_t i = 0; i < (rounds - 1); ++i) {
291  l[li_out] = (k[i] + rightRotate8_64(l[li_in])) ^ i;
292  k[i + 1] = leftRotate3_64(k[i]) ^ l[li_out];
293  if ((++li_in) >= m)
294  li_in = 0;
295  if ((++li_out) >= m)
296  li_out = 0;
297  }
298  clean(l);
299  return true;
300 #endif
301 }
302 
303 void Speck::encryptBlock(uint8_t *output, const uint8_t *input)
304 {
305 #if USE_AVR_INLINE_ASM
306  // Automatically generated by the genspeck tool.
307  __asm__ __volatile__ (
308  "ld r15,X+\n"
309  "ld r14,X+\n"
310  "ld r13,X+\n"
311  "ld r12,X+\n"
312  "ld r11,X+\n"
313  "ld r10,X+\n"
314  "ld r9,X+\n"
315  "ld r8,X+\n"
316  "ld r23,X+\n"
317  "ld r22,X+\n"
318  "ld r21,X+\n"
319  "ld r20,X+\n"
320  "ld r19,X+\n"
321  "ld r18,X+\n"
322  "ld r17,X+\n"
323  "ld r16,X\n"
324  "1:\n"
325  "add r9,r16\n"
326  "adc r10,r17\n"
327  "adc r11,r18\n"
328  "adc r12,r19\n"
329  "adc r13,r20\n"
330  "adc r14,r21\n"
331  "adc r15,r22\n"
332  "adc r8,r23\n"
333  "ld __tmp_reg__,Z+\n"
334  "eor __tmp_reg__,r9\n"
335  "ld r9,Z+\n"
336  "eor r9,r10\n"
337  "ld r10,Z+\n"
338  "eor r10,r11\n"
339  "ld r11,Z+\n"
340  "eor r11,r12\n"
341  "ld r12,Z+\n"
342  "eor r12,r13\n"
343  "ld r13,Z+\n"
344  "eor r13,r14\n"
345  "ld r14,Z+\n"
346  "eor r14,r15\n"
347  "ld r15,Z+\n"
348  "eor r15,r8\n"
349  "mov r8,__tmp_reg__\n"
350  "lsl r16\n"
351  "rol r17\n"
352  "rol r18\n"
353  "rol r19\n"
354  "rol r20\n"
355  "rol r21\n"
356  "rol r22\n"
357  "rol r23\n"
358  "adc r16, __zero_reg__\n"
359  "lsl r16\n"
360  "rol r17\n"
361  "rol r18\n"
362  "rol r19\n"
363  "rol r20\n"
364  "rol r21\n"
365  "rol r22\n"
366  "rol r23\n"
367  "adc r16, __zero_reg__\n"
368  "lsl r16\n"
369  "rol r17\n"
370  "rol r18\n"
371  "rol r19\n"
372  "rol r20\n"
373  "rol r21\n"
374  "rol r22\n"
375  "rol r23\n"
376  "adc r16, __zero_reg__\n"
377  "eor r16,r8\n"
378  "eor r17,r9\n"
379  "eor r18,r10\n"
380  "eor r19,r11\n"
381  "eor r20,r12\n"
382  "eor r21,r13\n"
383  "eor r22,r14\n"
384  "eor r23,r15\n"
385  "dec %2\n"
386  "breq 2f\n"
387  "rjmp 1b\n"
388  "2:\n"
389  "ldd r26,%A3\n"
390  "ldd r27,%B3\n"
391  "st X+,r15\n"
392  "st X+,r14\n"
393  "st X+,r13\n"
394  "st X+,r12\n"
395  "st X+,r11\n"
396  "st X+,r10\n"
397  "st X+,r9\n"
398  "st X+,r8\n"
399  "st X+,r23\n"
400  "st X+,r22\n"
401  "st X+,r21\n"
402  "st X+,r20\n"
403  "st X+,r19\n"
404  "st X+,r18\n"
405  "st X+,r17\n"
406  "st X,r16\n"
407  : : "x"(input), "z"(k), "r"(rounds), "Q"(output)
408  : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
409  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "memory"
410  );
411 #else
412  uint64_t x, y;
413  const uint64_t *s = k;
414  unpack64(x, input);
415  unpack64(y, input + 8);
416  for (uint8_t round = rounds; round > 0; --round, ++s) {
417  x = (rightRotate8_64(x) + y) ^ s[0];
418  y = leftRotate3_64(y) ^ x;
419  }
420  pack64(output, x);
421  pack64(output + 8, y);
422 #endif
423 }
424 
425 void Speck::decryptBlock(uint8_t *output, const uint8_t *input)
426 {
427 #if USE_AVR_INLINE_ASM
428  // Automatically generated by the genspeck tool.
429  __asm__ __volatile__ (
430  "ld r15,X+\n"
431  "ld r14,X+\n"
432  "ld r13,X+\n"
433  "ld r12,X+\n"
434  "ld r11,X+\n"
435  "ld r10,X+\n"
436  "ld r9,X+\n"
437  "ld r8,X+\n"
438  "ld r23,X+\n"
439  "ld r22,X+\n"
440  "ld r21,X+\n"
441  "ld r20,X+\n"
442  "ld r19,X+\n"
443  "ld r18,X+\n"
444  "ld r17,X+\n"
445  "ld r16,X\n"
446  "1:\n"
447  "eor r16,r8\n"
448  "eor r17,r9\n"
449  "eor r18,r10\n"
450  "eor r19,r11\n"
451  "eor r20,r12\n"
452  "eor r21,r13\n"
453  "eor r22,r14\n"
454  "eor r23,r15\n"
455  "bst r16,0\n"
456  "ror r23\n"
457  "ror r22\n"
458  "ror r21\n"
459  "ror r20\n"
460  "ror r19\n"
461  "ror r18\n"
462  "ror r17\n"
463  "ror r16\n"
464  "bld r23,7\n"
465  "bst r16,0\n"
466  "ror r23\n"
467  "ror r22\n"
468  "ror r21\n"
469  "ror r20\n"
470  "ror r19\n"
471  "ror r18\n"
472  "ror r17\n"
473  "ror r16\n"
474  "bld r23,7\n"
475  "bst r16,0\n"
476  "ror r23\n"
477  "ror r22\n"
478  "ror r21\n"
479  "ror r20\n"
480  "ror r19\n"
481  "ror r18\n"
482  "ror r17\n"
483  "ror r16\n"
484  "bld r23,7\n"
485  "ld __tmp_reg__,-Z\n"
486  "eor __tmp_reg__,r15\n"
487  "ld r15,-Z\n"
488  "eor r15,r14\n"
489  "ld r14,-Z\n"
490  "eor r14,r13\n"
491  "ld r13,-Z\n"
492  "eor r13,r12\n"
493  "ld r12,-Z\n"
494  "eor r12,r11\n"
495  "ld r11,-Z\n"
496  "eor r11,r10\n"
497  "ld r10,-Z\n"
498  "eor r10,r9\n"
499  "ld r9,-Z\n"
500  "eor r9,r8\n"
501  "mov r8,__tmp_reg__\n"
502  "sub r9,r16\n"
503  "sbc r10,r17\n"
504  "sbc r11,r18\n"
505  "sbc r12,r19\n"
506  "sbc r13,r20\n"
507  "sbc r14,r21\n"
508  "sbc r15,r22\n"
509  "sbc r8,r23\n"
510  "dec %2\n"
511  "breq 2f\n"
512  "rjmp 1b\n"
513  "2:\n"
514  "ldd r26,%A3\n"
515  "ldd r27,%B3\n"
516  "st X+,r15\n"
517  "st X+,r14\n"
518  "st X+,r13\n"
519  "st X+,r12\n"
520  "st X+,r11\n"
521  "st X+,r10\n"
522  "st X+,r9\n"
523  "st X+,r8\n"
524  "st X+,r23\n"
525  "st X+,r22\n"
526  "st X+,r21\n"
527  "st X+,r20\n"
528  "st X+,r19\n"
529  "st X+,r18\n"
530  "st X+,r17\n"
531  "st X,r16\n"
532  : : "x"(input), "z"(k + rounds), "r"(rounds), "Q"(output)
533  : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
534  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "memory"
535  );
536 #else
537  uint64_t x, y;
538  const uint64_t *s = k + rounds - 1;
539  unpack64(x, input);
540  unpack64(y, input + 8);
541  for (uint8_t round = rounds; round > 0; --round, --s) {
542  y = rightRotate3_64(x ^ y);
543  x = leftRotate8_64((x ^ s[0]) - y);
544  }
545  pack64(output, x);
546  pack64(output + 8, y);
547 #endif
548 }
549 
551 {
552  clean(k);
553 }
Speck()
Constructs a Speck block cipher with no initial key.
Definition: Speck.cpp:72
bool setKey(const uint8_t *key, size_t len)
Sets the key to use for future encryption and decryption operations.
Definition: Speck.cpp:105
void clear()
Clears all security-sensitive state from this block cipher.
Definition: Speck.cpp:550
size_t blockSize() const
Size of a single block processed by this cipher, in bytes.
Definition: Speck.cpp:82
size_t keySize() const
Default size of the key for this block cipher, in bytes.
Definition: Speck.cpp:87
void decryptBlock(uint8_t *output, const uint8_t *input)
Decrypts a single block using this cipher.
Definition: Speck.cpp:425
void encryptBlock(uint8_t *output, const uint8_t *input)
Encrypts a single block using this cipher.
Definition: Speck.cpp:303