chacha.c
Go to the documentation of this file.
1 /**
2  * @file chacha.c
3  * @brief ChaCha encryption algorithm
4  *
6  *
8  *
10  *
11  * This file is part of CycloneCrypto Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33
34 //Dependencies
35 #include "core/crypto.h"
36 #include "cipher/chacha.h"
37
38 //Check crypto library configuration
39 #if (CHACHA_SUPPORT == ENABLED)
40
41 //ChaCha quarter-round function
42 #define CHACHA_QUARTER_ROUND(a, b, c, d) \
43 { \
44  a += b; \
45  d ^= a; \
46  d = ROL32(d, 16); \
47  c += d; \
48  b ^= c; \
49  b = ROL32(b, 12); \
50  a += b; \
51  d ^= a; \
52  d = ROL32(d, 8); \
53  c += d; \
54  b ^= c; \
55  b = ROL32(b, 7); \
56 }
57
58
59 /**
60  * @brief Initialize ChaCha context using the supplied key and nonce
61  * @param[in] context Pointer to the ChaCha context to initialize
62  * @param[in] nr Number of rounds to be applied (8, 12 or 20)
63  * @param[in] key Pointer to the key
64  * @param[in] keyLen Length of the key, in bytes (16 or 32)
65  * @param[in] nonce Pointer to the nonce
66  * @param[in] nonceLen Length of the nonce, in bytes (8 or 12)
67  * @return Error code
68  **/
69
70 error_t chachaInit(ChachaContext *context, uint_t nr, const uint8_t *key,
71  size_t keyLen, const uint8_t *nonce, size_t nonceLen)
72 {
73  uint32_t *w;
74
75  //Check parameters
76  if(context == NULL || key == NULL || nonce == NULL)
78
79  //The number of rounds must be 8, 12 or 20
80  if(nr != 8 && nr != 12 && nr != 20)
82
83  //Save the number of rounds to be applied
84  context->nr = nr;
85
86  //Point to the state
87  w = context->state;
88
89  //Check the length of the key
90  if(keyLen == 16)
91  {
92  //The first four input words are constants
93  w[0] = 0x61707865;
94  w[1] = 0x3120646E;
95  w[2] = 0x79622D36;
96  w[3] = 0x6B206574;
97
98  //Input words 4 through 7 are taken from the 128-bit key, by reading
99  //the bytes in little-endian order, in 4-byte chunks
101  w[5] = LOAD32LE(key + 4);
102  w[6] = LOAD32LE(key + 8);
103  w[7] = LOAD32LE(key + 12);
104
105  //Input words 8 through 11 are taken from the 128-bit key, again by
106  //reading the bytes in little-endian order, in 4-byte chunks
108  w[9] = LOAD32LE(key + 4);
109  w[10] = LOAD32LE(key + 8);
110  w[11] = LOAD32LE(key + 12);
111  }
112  else if(keyLen == 32)
113  {
114  //The first four input words are constants
115  w[0] = 0x61707865;
116  w[1] = 0x3320646E;
117  w[2] = 0x79622D32;
118  w[3] = 0x6B206574;
119
120  //Input words 4 through 11 are taken from the 256-bit key, by reading
121  //the bytes in little-endian order, in 4-byte chunks
123  w[5] = LOAD32LE(key + 4);
124  w[6] = LOAD32LE(key + 8);
125  w[7] = LOAD32LE(key + 12);
126  w[8] = LOAD32LE(key + 16);
127  w[9] = LOAD32LE(key + 20);
128  w[10] = LOAD32LE(key + 24);
129  w[11] = LOAD32LE(key + 28);
130  }
131  else
132  {
133  //Invalid key length
135  }
136
137  //Check the length of the nonce
138  if(nonceLen == 8)
139  {
140  //Input words 12 and 13 are a block counter, with word 12
141  //overflowing into word 13
142  w[12] = 0;
143  w[13] = 0;
144
145  //Input words 14 and 15 are taken from an 64-bit nonce, by reading
146  //the bytes in little-endian order, in 4-byte chunks
148  w[15] = LOAD32LE(nonce + 4);
149  }
150  else if(nonceLen == 12)
151  {
152  //Input word 12 is a block counter
153  w[12] = 0;
154
155  //Input words 13 to 15 are taken from an 96-bit nonce, by reading
156  //the bytes in little-endian order, in 4-byte chunks
158  w[14] = LOAD32LE(nonce + 4);
159  w[15] = LOAD32LE(nonce + 8);
160  }
161  else
162  {
163  //Invalid nonce length
165  }
166
167  //The keystream block is empty
168  context->pos = 0;
169
170  //No error to report
171  return NO_ERROR;
172 }
173
174
175 /**
176  * @brief Encrypt/decrypt data with the ChaCha algorithm
177  * @param[in] context Pointer to the ChaCha context
178  * @param[in] input Pointer to the data to encrypt/decrypt (optional)
179  * @param[in] output Pointer to the resulting data (optional)
180  * @param[in] length Number of bytes to be processed
181  **/
182
183 void chachaCipher(ChachaContext *context, const uint8_t *input,
184  uint8_t *output, size_t length)
185 {
186  uint_t i;
187  uint_t n;
188  uint8_t *k;
189
190  //Encryption loop
191  while(length > 0)
192  {
193  //Check whether a new keystream block must be generated
194  if(context->pos == 0 || context->pos >= 64)
195  {
196  //ChaCha successively calls the ChaCha block function, with the same key
197  //and nonce, and with successively increasing block counter parameters
198  chachaProcessBlock(context);
199
200  //Increment block counter
201  context->state[12]++;
202
203  //Propagate the carry if necessary
204  if(context->state[12] == 0)
205  {
206  context->state[13]++;
207  }
208
209  //Rewind to the beginning of the keystream block
210  context->pos = 0;
211  }
212
213  //Compute the number of bytes to encrypt/decrypt at a time
214  n = MIN(length, 64 - context->pos);
215
216  //Valid output pointer?
217  if(output != NULL)
218  {
219  //Point to the keystream
220  k = (uint8_t *) context->block + context->pos;
221
222  //Valid input pointer?
223  if(input != NULL)
224  {
225  //XOR the input data with the keystream
226  for(i = 0; i < n; i++)
227  {
228  output[i] = input[i] ^ k[i];
229  }
230
232  input += n;
233  }
234  else
235  {
236  //Output the keystream
237  for(i = 0; i < n; i++)
238  {
239  output[i] = k[i];
240  }
241  }
242
244  output += n;
245  }
246
247  //Current position in the keystream block
248  context->pos += n;
249  //Remaining bytes to process
250  length -= n;
251  }
252 }
253
254
255 /**
256  * @brief Generate a keystream block
257  * @param[in] context Pointer to the ChaCha context
258  **/
259
261 {
262  uint_t i;
263  uint32_t *w;
264
265  //Point to the working state
266  w = (uint32_t *) context->block;
267
268  //Copy the state to the working state
269  for(i = 0; i < 16; i++)
270  {
271  w[i] = context->state[i];
272  }
273
274  //ChaCha runs 8, 12 or 20 rounds, alternating between column rounds and
275  //diagonal rounds
276  for(i = 0; i < context->nr; i += 2)
277  {
278  //The column rounds apply the quarter-round function to the four
279  //columns, from left to right
280  CHACHA_QUARTER_ROUND(w[0], w[4], w[8], w[12]);
281  CHACHA_QUARTER_ROUND(w[1], w[5], w[9], w[13]);
282  CHACHA_QUARTER_ROUND(w[2], w[6], w[10], w[14]);
283  CHACHA_QUARTER_ROUND(w[3], w[7], w[11], w[15]);
284
285  //The diagonal rounds apply the quarter-round function to the top-left,
286  //bottom-right diagonal, followed by the pattern shifted one place to
287  //the right, for three more quarter-rounds
288  CHACHA_QUARTER_ROUND(w[0], w[5], w[10], w[15]);
289  CHACHA_QUARTER_ROUND(w[1], w[6], w[11], w[12]);
290  CHACHA_QUARTER_ROUND(w[2], w[7], w[8], w[13]);
291  CHACHA_QUARTER_ROUND(w[3], w[4], w[9], w[14]);
292  }
293
294  //Add the original input words to the output words
295  for(i = 0; i < 16; i++)
296  {
297  w[i] += context->state[i];
298  }
299
300  //Serialize the result by sequencing the words one-by-one in little-endian
301  //order
302  for(i = 0; i < 16; i++)
303  {
304  w[i] = htole32(w[i]);
305  }
306 }
307
308 #endif
uint8_t length
Definition: dtls_misc.h:149
uint16_t w[3]
Definition: ethernet.h:166
size_t pos
Definition: chacha.h:52
void chachaCipher(ChachaContext *context, const uint8_t *input, uint8_t *output, size_t length)
Encrypt/decrypt data with the ChaCha algorithm.
Definition: chacha.c:183
uint_t nr
Definition: chacha.h:49
ChaCha encryption algorithm.
error_t chachaInit(ChachaContext *context, uint_t nr, const uint8_t *key, size_t keyLen, const uint8_t *nonce, size_t nonceLen)
Initialize ChaCha context using the supplied key and nonce.
Definition: chacha.c:70
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:42
#define htole32(value)
Definition: cpu_endian.h:406
void chachaProcessBlock(ChachaContext *context)
Generate a keystream block.
Definition: chacha.c:260
General definitions for cryptographic algorithms.
#define MIN(a, b)
Definition: os_port.h:62
ChaCha algorithm context.
Definition: chacha.h:47
#define CHACHA_QUARTER_ROUND(a, b, c, d)
Definition: chacha.c:42
uint8_t n
uint32_t state[16]
Definition: chacha.h:50