1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /* Adopted from the public domain code in NaCl by djb. */
6 
7 #include <string.h>
8 #include <stdio.h>
9 
10 #include "prtypes.h"
11 #include "secport.h"
12 #include "chacha20.h"
13 
14 #if defined(_MSC_VER)
15 #pragma intrinsic(_lrotl)
16 #define ROTL32(x, n) _lrotl(x, n)
17 #else
18 #define ROTL32(x, n) ((x << n) | (x >> ((8 * sizeof x) - n)))
19 #endif
20 
21 #define ROTATE(v, c) ROTL32((v), (c))
22 
23 #define U32TO8_LITTLE(p, v)          \
24     {                                \
25         (p)[0] = ((v)) & 0xff;       \
26         (p)[1] = ((v) >> 8) & 0xff;  \
27         (p)[2] = ((v) >> 16) & 0xff; \
28         (p)[3] = ((v) >> 24) & 0xff; \
29     }
30 #define U8TO32_LITTLE(p)                                \
31     (((PRUint32)((p)[0])) | ((PRUint32)((p)[1]) << 8) | \
32      ((PRUint32)((p)[2]) << 16) | ((PRUint32)((p)[3]) << 24))
33 
34 #define QUARTERROUND(x, a, b, c, d) \
35     x[a] = x[a] + x[b];             \
36     x[d] = ROTATE(x[d] ^ x[a], 16); \
37     x[c] = x[c] + x[d];             \
38     x[b] = ROTATE(x[b] ^ x[c], 12); \
39     x[a] = x[a] + x[b];             \
40     x[d] = ROTATE(x[d] ^ x[a], 8);  \
41     x[c] = x[c] + x[d];             \
42     x[b] = ROTATE(x[b] ^ x[c], 7);
43 
44 static void
ChaChaCore(unsigned char output[64],const PRUint32 input[16],int num_rounds)45 ChaChaCore(unsigned char output[64], const PRUint32 input[16], int num_rounds)
46 {
47     PRUint32 x[16];
48     int i;
49 
50     PORT_Memcpy(x, input, sizeof(PRUint32) * 16);
51     for (i = num_rounds; i > 0; i -= 2) {
52         QUARTERROUND(x, 0, 4, 8, 12)
53         QUARTERROUND(x, 1, 5, 9, 13)
54         QUARTERROUND(x, 2, 6, 10, 14)
55         QUARTERROUND(x, 3, 7, 11, 15)
56         QUARTERROUND(x, 0, 5, 10, 15)
57         QUARTERROUND(x, 1, 6, 11, 12)
58         QUARTERROUND(x, 2, 7, 8, 13)
59         QUARTERROUND(x, 3, 4, 9, 14)
60     }
61 
62     for (i = 0; i < 16; ++i) {
63         x[i] = x[i] + input[i];
64     }
65     for (i = 0; i < 16; ++i) {
66         U32TO8_LITTLE(output + 4 * i, x[i]);
67     }
68 }
69 
70 static const unsigned char sigma[16] = "expand 32-byte k";
71 
72 void
ChaCha20XOR(unsigned char * out,const unsigned char * in,unsigned int inLen,const unsigned char key[32],const unsigned char nonce[12],uint32_t counter)73 ChaCha20XOR(unsigned char *out, const unsigned char *in, unsigned int inLen,
74             const unsigned char key[32], const unsigned char nonce[12],
75             uint32_t counter)
76 {
77     unsigned char block[64];
78     PRUint32 input[16];
79     unsigned int i;
80 
81     input[4] = U8TO32_LITTLE(key + 0);
82     input[5] = U8TO32_LITTLE(key + 4);
83     input[6] = U8TO32_LITTLE(key + 8);
84     input[7] = U8TO32_LITTLE(key + 12);
85 
86     input[8] = U8TO32_LITTLE(key + 16);
87     input[9] = U8TO32_LITTLE(key + 20);
88     input[10] = U8TO32_LITTLE(key + 24);
89     input[11] = U8TO32_LITTLE(key + 28);
90 
91     input[0] = U8TO32_LITTLE(sigma + 0);
92     input[1] = U8TO32_LITTLE(sigma + 4);
93     input[2] = U8TO32_LITTLE(sigma + 8);
94     input[3] = U8TO32_LITTLE(sigma + 12);
95 
96     input[12] = counter;
97     input[13] = U8TO32_LITTLE(nonce + 0);
98     input[14] = U8TO32_LITTLE(nonce + 4);
99     input[15] = U8TO32_LITTLE(nonce + 8);
100 
101     while (inLen >= 64) {
102         ChaChaCore(block, input, 20);
103         for (i = 0; i < 64; i++) {
104             out[i] = in[i] ^ block[i];
105         }
106 
107         input[12]++;
108         inLen -= 64;
109         in += 64;
110         out += 64;
111     }
112 
113     if (inLen > 0) {
114         ChaChaCore(block, input, 20);
115         for (i = 0; i < inLen; i++) {
116             out[i] = in[i] ^ block[i];
117         }
118     }
119 }
120