Line data Source code
1 : /*
2 : chacha-merged.c version 20080118
3 : D. J. Bernstein
4 : Public domain.
5 : */
6 :
7 : typedef unsigned char u8;
8 : typedef unsigned int u32;
9 :
10 : typedef struct
11 : {
12 : u32 input[16]; /* could be compressed */
13 : } chacha_ctx;
14 :
15 : #define U8C(v) (v##U)
16 : #define U32C(v) (v##U)
17 :
18 : #define U8V(v) ((u8)(v) & U8C(0xFF))
19 : #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
20 :
21 : #define ROTL32(v, n) \
22 : (U32V((v) << (n)) | ((v) >> (32 - (n))))
23 :
24 : #define U8TO32_LITTLE(p) \
25 : (((u32)((p)[0]) ) | \
26 : ((u32)((p)[1]) << 8) | \
27 : ((u32)((p)[2]) << 16) | \
28 : ((u32)((p)[3]) << 24))
29 :
30 : #define U32TO8_LITTLE(p, v) \
31 : do { \
32 : (p)[0] = U8V((v) ); \
33 : (p)[1] = U8V((v) >> 8); \
34 : (p)[2] = U8V((v) >> 16); \
35 : (p)[3] = U8V((v) >> 24); \
36 : } while (0)
37 :
38 : #define ROTATE(v,c) (ROTL32(v,c))
39 : #define XOR(v,w) ((v) ^ (w))
40 : #define PLUS(v,w) (U32V((v) + (w)))
41 : #define PLUSONE(v) (PLUS((v),1))
42 :
43 : #define QUARTERROUND(a,b,c,d) \
44 : a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
45 : c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
46 : a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
47 : c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
48 :
49 : static const char sigma[16] = "expand 32-byte k";
50 : static const char tau[16] = "expand 16-byte k";
51 :
52 : static void
53 0 : chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
54 : {
55 : const char *constants;
56 :
57 0 : x->input[4] = U8TO32_LITTLE(k + 0);
58 0 : x->input[5] = U8TO32_LITTLE(k + 4);
59 0 : x->input[6] = U8TO32_LITTLE(k + 8);
60 0 : x->input[7] = U8TO32_LITTLE(k + 12);
61 0 : if (kbits == 256) { /* recommended */
62 0 : k += 16;
63 : constants = sigma;
64 0 : } else { /* kbits == 128 */
65 : constants = tau;
66 : }
67 0 : x->input[8] = U8TO32_LITTLE(k + 0);
68 0 : x->input[9] = U8TO32_LITTLE(k + 4);
69 0 : x->input[10] = U8TO32_LITTLE(k + 8);
70 0 : x->input[11] = U8TO32_LITTLE(k + 12);
71 0 : x->input[0] = U8TO32_LITTLE(constants + 0);
72 0 : x->input[1] = U8TO32_LITTLE(constants + 4);
73 0 : x->input[2] = U8TO32_LITTLE(constants + 8);
74 0 : x->input[3] = U8TO32_LITTLE(constants + 12);
75 0 : }
76 :
77 : static void
78 0 : chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
79 : {
80 0 : x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
81 0 : x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
82 0 : x->input[14] = U8TO32_LITTLE(iv + 0);
83 0 : x->input[15] = U8TO32_LITTLE(iv + 4);
84 0 : }
85 :
86 : static void
87 0 : chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
88 : {
89 : u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
90 : u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
91 : u8 *ctarget = NULL;
92 0 : u8 tmp[64];
93 : u_int i;
94 :
95 0 : if (!bytes) return;
96 :
97 0 : j0 = x->input[0];
98 0 : j1 = x->input[1];
99 0 : j2 = x->input[2];
100 0 : j3 = x->input[3];
101 0 : j4 = x->input[4];
102 0 : j5 = x->input[5];
103 0 : j6 = x->input[6];
104 0 : j7 = x->input[7];
105 0 : j8 = x->input[8];
106 0 : j9 = x->input[9];
107 0 : j10 = x->input[10];
108 0 : j11 = x->input[11];
109 0 : j12 = x->input[12];
110 0 : j13 = x->input[13];
111 0 : j14 = x->input[14];
112 0 : j15 = x->input[15];
113 :
114 0 : for (;;) {
115 0 : if (bytes < 64) {
116 0 : for (i = 0;i < bytes;++i) tmp[i] = m[i];
117 0 : m = tmp;
118 : ctarget = c;
119 : c = tmp;
120 0 : }
121 : x0 = j0;
122 : x1 = j1;
123 : x2 = j2;
124 : x3 = j3;
125 : x4 = j4;
126 : x5 = j5;
127 : x6 = j6;
128 : x7 = j7;
129 : x8 = j8;
130 : x9 = j9;
131 : x10 = j10;
132 : x11 = j11;
133 : x12 = j12;
134 : x13 = j13;
135 : x14 = j14;
136 : x15 = j15;
137 0 : for (i = 20;i > 0;i -= 2) {
138 0 : QUARTERROUND( x0, x4, x8,x12)
139 0 : QUARTERROUND( x1, x5, x9,x13)
140 0 : QUARTERROUND( x2, x6,x10,x14)
141 0 : QUARTERROUND( x3, x7,x11,x15)
142 0 : QUARTERROUND( x0, x5,x10,x15)
143 0 : QUARTERROUND( x1, x6,x11,x12)
144 0 : QUARTERROUND( x2, x7, x8,x13)
145 0 : QUARTERROUND( x3, x4, x9,x14)
146 : }
147 0 : x0 = PLUS(x0,j0);
148 0 : x1 = PLUS(x1,j1);
149 0 : x2 = PLUS(x2,j2);
150 0 : x3 = PLUS(x3,j3);
151 0 : x4 = PLUS(x4,j4);
152 0 : x5 = PLUS(x5,j5);
153 0 : x6 = PLUS(x6,j6);
154 0 : x7 = PLUS(x7,j7);
155 0 : x8 = PLUS(x8,j8);
156 0 : x9 = PLUS(x9,j9);
157 0 : x10 = PLUS(x10,j10);
158 0 : x11 = PLUS(x11,j11);
159 0 : x12 = PLUS(x12,j12);
160 0 : x13 = PLUS(x13,j13);
161 0 : x14 = PLUS(x14,j14);
162 0 : x15 = PLUS(x15,j15);
163 :
164 : #ifndef KEYSTREAM_ONLY
165 0 : x0 = XOR(x0,U8TO32_LITTLE(m + 0));
166 0 : x1 = XOR(x1,U8TO32_LITTLE(m + 4));
167 0 : x2 = XOR(x2,U8TO32_LITTLE(m + 8));
168 0 : x3 = XOR(x3,U8TO32_LITTLE(m + 12));
169 0 : x4 = XOR(x4,U8TO32_LITTLE(m + 16));
170 0 : x5 = XOR(x5,U8TO32_LITTLE(m + 20));
171 0 : x6 = XOR(x6,U8TO32_LITTLE(m + 24));
172 0 : x7 = XOR(x7,U8TO32_LITTLE(m + 28));
173 0 : x8 = XOR(x8,U8TO32_LITTLE(m + 32));
174 0 : x9 = XOR(x9,U8TO32_LITTLE(m + 36));
175 0 : x10 = XOR(x10,U8TO32_LITTLE(m + 40));
176 0 : x11 = XOR(x11,U8TO32_LITTLE(m + 44));
177 0 : x12 = XOR(x12,U8TO32_LITTLE(m + 48));
178 0 : x13 = XOR(x13,U8TO32_LITTLE(m + 52));
179 0 : x14 = XOR(x14,U8TO32_LITTLE(m + 56));
180 0 : x15 = XOR(x15,U8TO32_LITTLE(m + 60));
181 : #endif
182 :
183 0 : j12 = PLUSONE(j12);
184 0 : if (!j12) {
185 0 : j13 = PLUSONE(j13);
186 : /* stopping at 2^70 bytes per nonce is user's responsibility */
187 0 : }
188 :
189 0 : U32TO8_LITTLE(c + 0,x0);
190 0 : U32TO8_LITTLE(c + 4,x1);
191 0 : U32TO8_LITTLE(c + 8,x2);
192 0 : U32TO8_LITTLE(c + 12,x3);
193 0 : U32TO8_LITTLE(c + 16,x4);
194 0 : U32TO8_LITTLE(c + 20,x5);
195 0 : U32TO8_LITTLE(c + 24,x6);
196 0 : U32TO8_LITTLE(c + 28,x7);
197 0 : U32TO8_LITTLE(c + 32,x8);
198 0 : U32TO8_LITTLE(c + 36,x9);
199 0 : U32TO8_LITTLE(c + 40,x10);
200 0 : U32TO8_LITTLE(c + 44,x11);
201 0 : U32TO8_LITTLE(c + 48,x12);
202 0 : U32TO8_LITTLE(c + 52,x13);
203 0 : U32TO8_LITTLE(c + 56,x14);
204 0 : U32TO8_LITTLE(c + 60,x15);
205 :
206 0 : if (bytes <= 64) {
207 0 : if (bytes < 64) {
208 0 : for (i = 0;i < bytes;++i) ctarget[i] = c[i];
209 : }
210 0 : x->input[12] = j12;
211 0 : x->input[13] = j13;
212 0 : return;
213 : }
214 0 : bytes -= 64;
215 0 : c += 64;
216 : #ifndef KEYSTREAM_ONLY
217 0 : m += 64;
218 : #endif
219 : }
220 0 : }
|