Arduino Cryptography Library
SpeckTiny.cpp
1 /*
2  * Copyright (C) 2016 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 "SpeckTiny.h"
24 #include "Crypto.h"
25 #include "utility/RotateUtil.h"
26 #include "utility/EndianUtil.h"
27 #include <string.h>
28 
60 // The "avr-gcc" compiler doesn't do a very good job of compiling
61 // code involving 64-bit values. So we have to use inline assembly.
62 // It also helps to break the state up into 32-bit quantities
63 // because "asm" supports register names like %A0, %B0, %C0, %D0
64 // for the bytes in a 32-bit quantity, but it does not support
65 // %E0, %F0, %G0, %H0 for the high bytes of a 64-bit quantity.
66 #if defined(__AVR__)
67 #define USE_AVR_INLINE_ASM 1
68 #endif
69 
77  : rounds(32)
78 {
79 }
80 
81 SpeckTiny::~SpeckTiny()
82 {
83  clean(k);
84 }
85 
86 size_t SpeckTiny::blockSize() const
87 {
88  return 16;
89 }
90 
91 size_t SpeckTiny::keySize() const
92 {
93  // Also supports 128-bit and 192-bit, but we only report 256-bit.
94  return 32;
95 }
96 
97 // Pack/unpack byte-aligned big-endian 64-bit quantities.
98 #define pack64(data, value) \
99  do { \
100  uint64_t v = htobe64((value)); \
101  memcpy((data), &v, sizeof(uint64_t)); \
102  } while (0)
103 #define unpack64(value, data) \
104  do { \
105  memcpy(&(value), (data), sizeof(uint64_t)); \
106  (value) = be64toh((value)); \
107  } while (0)
108 
109 bool SpeckTiny::setKey(const uint8_t *key, size_t len)
110 {
111 #if USE_AVR_INLINE_ASM
112  // Determine the number of rounds to use and validate the key length.
113  if (len == 32) {
114  rounds = 34;
115  } else if (len == 24) {
116  rounds = 33;
117  } else if (len == 16) {
118  rounds = 32;
119  } else {
120  return false;
121  }
122 
123  // Copy the bytes of the key into the "k" array in reverse order to
124  // convert big endian into little-endian.
125  __asm__ __volatile__ (
126  "1:\n"
127  "ld __tmp_reg__,-Z\n"
128  "st X+,__tmp_reg__\n"
129  "dec %2\n"
130  "brne 1b\n"
131  : : "x"(k), "z"(key + len), "r"(len)
132  );
133 #else
134  if (len == 32) {
135  rounds = 34;
136  unpack64(k[3], key);
137  unpack64(k[2], key + 8);
138  unpack64(k[1], key + 16);
139  unpack64(k[0], key + 24);
140  } else if (len == 24) {
141  rounds = 33;
142  unpack64(k[2], key);
143  unpack64(k[1], key + 8);
144  unpack64(k[0], key + 16);
145  } else if (len == 16) {
146  rounds = 32;
147  unpack64(k[1], key);
148  unpack64(k[0], key + 8);
149  } else {
150  return false;
151  }
152 #endif
153  return true;
154 }
155 
156 void SpeckTiny::encryptBlock(uint8_t *output, const uint8_t *input)
157 {
158 #if USE_AVR_INLINE_ASM
159  // Automatically generated by the genspeck tool.
160  uint64_t l[5];
161  uint8_t r = rounds;
162  uint8_t mb = (r - 31) * 8;
163  __asm__ __volatile__ (
164  "movw r8,r30\n"
165  "ldd r16,%4\n"
166  "ldi r24,8\n"
167  "add r16,r24\n"
168  "1:\n"
169  "ld __tmp_reg__,X+\n"
170  "st Z+,__tmp_reg__\n"
171  "dec r16\n"
172  "brne 1b\n"
173  "movw r30,r8\n"
174  "movw r26,%A2\n"
175  "ld r15,X+\n"
176  "ld r14,X+\n"
177  "ld r13,X+\n"
178  "ld r12,X+\n"
179  "ld r11,X+\n"
180  "ld r10,X+\n"
181  "ld r9,X+\n"
182  "ld r8,X+\n"
183  "ld r23,X+\n"
184  "ld r22,X+\n"
185  "ld r21,X+\n"
186  "ld r20,X+\n"
187  "ld r19,X+\n"
188  "ld r18,X+\n"
189  "ld r17,X+\n"
190  "ld r16,X\n"
191  "clr %A2\n"
192  "ldd %B2,%4\n"
193  "clr r25\n"
194  "2:\n"
195  "add r9,r16\n"
196  "adc r10,r17\n"
197  "adc r11,r18\n"
198  "adc r12,r19\n"
199  "adc r13,r20\n"
200  "adc r14,r21\n"
201  "adc r15,r22\n"
202  "adc r8,r23\n"
203  "ld __tmp_reg__,Z+\n"
204  "eor __tmp_reg__,r9\n"
205  "ld r9,Z+\n"
206  "eor r9,r10\n"
207  "ld r10,Z+\n"
208  "eor r10,r11\n"
209  "ld r11,Z+\n"
210  "eor r11,r12\n"
211  "ld r12,Z+\n"
212  "eor r12,r13\n"
213  "ld r13,Z+\n"
214  "eor r13,r14\n"
215  "ld r14,Z+\n"
216  "eor r14,r15\n"
217  "ld r15,Z+\n"
218  "eor r15,r8\n"
219  "mov r8,__tmp_reg__\n"
220  "lsl r16\n"
221  "rol r17\n"
222  "rol r18\n"
223  "rol r19\n"
224  "rol r20\n"
225  "rol r21\n"
226  "rol r22\n"
227  "rol r23\n"
228  "adc r16, __zero_reg__\n"
229  "lsl r16\n"
230  "rol r17\n"
231  "rol r18\n"
232  "rol r19\n"
233  "rol r20\n"
234  "rol r21\n"
235  "rol r22\n"
236  "rol r23\n"
237  "adc r16, __zero_reg__\n"
238  "lsl r16\n"
239  "rol r17\n"
240  "rol r18\n"
241  "rol r19\n"
242  "rol r20\n"
243  "rol r21\n"
244  "rol r22\n"
245  "rol r23\n"
246  "adc r16, __zero_reg__\n"
247  "eor r16,r8\n"
248  "eor r17,r9\n"
249  "eor r18,r10\n"
250  "eor r19,r11\n"
251  "eor r20,r12\n"
252  "eor r21,r13\n"
253  "eor r22,r14\n"
254  "eor r23,r15\n"
255  "mov __tmp_reg__,r25\n"
256  "inc __tmp_reg__\n"
257  "ldd r24,%5\n"
258  "cp __tmp_reg__,r24\n"
259  "brne 3f\n"
260  "rjmp 4f\n"
261  "3:\n"
262  "push r8\n"
263  "push r9\n"
264  "push r10\n"
265  "push r11\n"
266  "push r12\n"
267  "push r13\n"
268  "push r14\n"
269  "push r15\n"
270  "push r16\n"
271  "push r17\n"
272  "push r18\n"
273  "push r19\n"
274  "push r20\n"
275  "push r21\n"
276  "push r22\n"
277  "push r23\n"
278  "sbiw r30,8\n"
279  "ld r16,Z\n"
280  "ldd r17,Z+1\n"
281  "ldd r18,Z+2\n"
282  "ldd r19,Z+3\n"
283  "ldd r20,Z+4\n"
284  "ldd r21,Z+5\n"
285  "ldd r22,Z+6\n"
286  "ldd r23,Z+7\n"
287  "add r30,%A2\n"
288  "adc r31,__zero_reg__\n"
289  "ldd r15,Z+8\n"
290  "ldd r8,Z+9\n"
291  "ldd r9,Z+10\n"
292  "ldd r10,Z+11\n"
293  "ldd r11,Z+12\n"
294  "ldd r12,Z+13\n"
295  "ldd r13,Z+14\n"
296  "ldd r14,Z+15\n"
297  "add r8,r16\n"
298  "adc r9,r17\n"
299  "adc r10,r18\n"
300  "adc r11,r19\n"
301  "adc r12,r20\n"
302  "adc r13,r21\n"
303  "adc r14,r22\n"
304  "adc r15,r23\n"
305  "eor r8,r25\n"
306  "sub r30,%A2\n"
307  "sbc r31,__zero_reg__\n"
308  "add r30,%B2\n"
309  "adc r31,__zero_reg__\n"
310  "std Z+8,r8\n"
311  "std Z+9,r9\n"
312  "std Z+10,r10\n"
313  "std Z+11,r11\n"
314  "std Z+12,r12\n"
315  "std Z+13,r13\n"
316  "std Z+14,r14\n"
317  "std Z+15,r15\n"
318  "sub r30,%B2\n"
319  "sbc r31,__zero_reg__\n"
320  "lsl r16\n"
321  "rol r17\n"
322  "rol r18\n"
323  "rol r19\n"
324  "rol r20\n"
325  "rol r21\n"
326  "rol r22\n"
327  "rol r23\n"
328  "adc r16, __zero_reg__\n"
329  "lsl r16\n"
330  "rol r17\n"
331  "rol r18\n"
332  "rol r19\n"
333  "rol r20\n"
334  "rol r21\n"
335  "rol r22\n"
336  "rol r23\n"
337  "adc r16, __zero_reg__\n"
338  "lsl r16\n"
339  "rol r17\n"
340  "rol r18\n"
341  "rol r19\n"
342  "rol r20\n"
343  "rol r21\n"
344  "rol r22\n"
345  "rol r23\n"
346  "adc r16, __zero_reg__\n"
347  "eor r16,r8\n"
348  "eor r17,r9\n"
349  "eor r18,r10\n"
350  "eor r19,r11\n"
351  "eor r20,r12\n"
352  "eor r21,r13\n"
353  "eor r22,r14\n"
354  "eor r23,r15\n"
355  "st Z,r16\n"
356  "std Z+1,r17\n"
357  "std Z+2,r18\n"
358  "std Z+3,r19\n"
359  "std Z+4,r20\n"
360  "std Z+5,r21\n"
361  "std Z+6,r22\n"
362  "std Z+7,r23\n"
363  "ldi r24,8\n"
364  "add %A2,r24\n"
365  "add %B2,r24\n"
366  "ldi r24,0x1F\n"
367  "and %A2,r24\n"
368  "and %B2,r24\n"
369  "pop r23\n"
370  "pop r22\n"
371  "pop r21\n"
372  "pop r20\n"
373  "pop r19\n"
374  "pop r18\n"
375  "pop r17\n"
376  "pop r16\n"
377  "pop r15\n"
378  "pop r14\n"
379  "pop r13\n"
380  "pop r12\n"
381  "pop r11\n"
382  "pop r10\n"
383  "pop r9\n"
384  "pop r8\n"
385  "inc r25\n"
386  "rjmp 2b\n"
387  "4:\n"
388  "ldd r26,%A3\n"
389  "ldd r27,%B3\n"
390  "st X+,r15\n"
391  "st X+,r14\n"
392  "st X+,r13\n"
393  "st X+,r12\n"
394  "st X+,r11\n"
395  "st X+,r10\n"
396  "st X+,r9\n"
397  "st X+,r8\n"
398  "st X+,r23\n"
399  "st X+,r22\n"
400  "st X+,r21\n"
401  "st X+,r20\n"
402  "st X+,r19\n"
403  "st X+,r18\n"
404  "st X+,r17\n"
405  "st X,r16\n"
406  : : "x"(k), "z"(l), "r"(input), "Q"(output), "Q"(mb), "Q"(r)
407  : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
408  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "memory"
409  , "r24", "r25"
410  );
411 #else
412  uint64_t l[4];
413  uint64_t x, y, s;
414  uint8_t round;
415  uint8_t li_in = 0;
416  uint8_t li_out = rounds - 31;
417  uint8_t i = 0;
418 
419  // Copy the input block into the work registers.
420  unpack64(x, input);
421  unpack64(y, input + 8);
422 
423  // Prepare the key schedule.
424  memcpy(l, k + 1, li_out * sizeof(uint64_t));
425  s = k[0];
426 
427  // Perform all encryption rounds except the last.
428  for (round = rounds - 1; round > 0; --round, ++i) {
429  // Perform the round with the current key schedule word.
430  x = (rightRotate8_64(x) + y) ^ s;
431  y = leftRotate3_64(y) ^ x;
432 
433  // Calculate the next key schedule word.
434  l[li_out] = (s + rightRotate8_64(l[li_in])) ^ i;
435  s = leftRotate3_64(s) ^ l[li_out];
436  li_in = (li_in + 1) & 0x03;
437  li_out = (li_out + 1) & 0x03;
438  }
439 
440  // Perform the final round and copy to the output.
441  x = (rightRotate8_64(x) + y) ^ s;
442  y = leftRotate3_64(y) ^ x;
443  pack64(output, x);
444  pack64(output + 8, y);
445 #endif
446 }
447 
448 void SpeckTiny::decryptBlock(uint8_t *output, const uint8_t *input)
449 {
450  // Decryption is not supported by SpeckTiny. Use SpeckSmall instead.
451 }
452 
454 {
455  clean(k);
456 }
bool setKey(const uint8_t *key, size_t len)
Sets the key to use for future encryption and decryption operations.
Definition: SpeckTiny.cpp:109
void decryptBlock(uint8_t *output, const uint8_t *input)
Decrypts a single block using this cipher.
Definition: SpeckTiny.cpp:448
SpeckTiny()
Constructs a tiny-memory Speck block cipher with no initial key.
Definition: SpeckTiny.cpp:76
void clear()
Clears all security-sensitive state from this block cipher.
Definition: SpeckTiny.cpp:453
void encryptBlock(uint8_t *output, const uint8_t *input)
Encrypts a single block using this cipher.
Definition: SpeckTiny.cpp:156
size_t keySize() const
Default size of the key for this block cipher, in bytes.
Definition: SpeckTiny.cpp:91
size_t blockSize() const
Size of a single block processed by this cipher, in bytes.
Definition: SpeckTiny.cpp:86