unet-cli: strip initial newline in usage message
[project/unetd.git] / chacha20.c
1
2 /*
3 chacha-merged.c version 20080118
4 D. J. Bernstein
5 Public domain.
6 */
7
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "utils.h"
12 #include "chacha20.h"
13
14 struct chacha_ctx {
15 uint32_t input[16];
16 };
17
18 #define LOAD32_LE(SRC) get_unaligned_le32(SRC)
19
20 #define STORE32_LE(DST, W) store32_le((DST), (W))
21
22 static inline void
23 store32_le(uint8_t dst[4], uint32_t w)
24 {
25 dst[0] = (uint8_t) w; w >>= 8;
26 dst[1] = (uint8_t) w; w >>= 8;
27 dst[2] = (uint8_t) w; w >>= 8;
28 dst[3] = (uint8_t) w;
29 }
30
31
32 #define ROTL32(X, B) rotl32((X), (B))
33 static inline uint32_t
34 rotl32(const uint32_t x, const int b)
35 {
36 return (x << b) | (x >> (32 - b));
37 }
38
39 typedef struct chacha_ctx chacha_ctx;
40
41 #define U32C(v) (v##U)
42
43 #define U32V(v) ((uint32_t)(v) &U32C(0xFFFFFFFF))
44
45 #define ROTATE(v, c) (ROTL32(v, c))
46 #define XOR(v, w) ((v) ^ (w))
47 #define PLUS(v, w) (U32V((v) + (w)))
48 #define PLUSONE(v) (PLUS((v), 1))
49
50 #define QUARTERROUND(a, b, c, d) \
51 a = PLUS(a, b); \
52 d = ROTATE(XOR(d, a), 16); \
53 c = PLUS(c, d); \
54 b = ROTATE(XOR(b, c), 12); \
55 a = PLUS(a, b); \
56 d = ROTATE(XOR(d, a), 8); \
57 c = PLUS(c, d); \
58 b = ROTATE(XOR(b, c), 7);
59
60 static void
61 chacha_keysetup(chacha_ctx *ctx, const uint8_t *k)
62 {
63 ctx->input[0] = U32C(0x61707865);
64 ctx->input[1] = U32C(0x3320646e);
65 ctx->input[2] = U32C(0x79622d32);
66 ctx->input[3] = U32C(0x6b206574);
67 ctx->input[4] = LOAD32_LE(k + 0);
68 ctx->input[5] = LOAD32_LE(k + 4);
69 ctx->input[6] = LOAD32_LE(k + 8);
70 ctx->input[7] = LOAD32_LE(k + 12);
71 ctx->input[8] = LOAD32_LE(k + 16);
72 ctx->input[9] = LOAD32_LE(k + 20);
73 ctx->input[10] = LOAD32_LE(k + 24);
74 ctx->input[11] = LOAD32_LE(k + 28);
75 }
76
77 static void
78 chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter)
79 {
80 ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0);
81 ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4);
82 ctx->input[14] = LOAD32_LE(iv + 0);
83 ctx->input[15] = LOAD32_LE(iv + 4);
84 }
85
86 static void
87 chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c,
88 unsigned long long bytes)
89 {
90 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
91 x15;
92 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
93 j15;
94 uint8_t *ctarget = NULL;
95 uint8_t tmp[64];
96 unsigned int i;
97
98 if (!bytes) {
99 return; /* LCOV_EXCL_LINE */
100 }
101 j0 = ctx->input[0];
102 j1 = ctx->input[1];
103 j2 = ctx->input[2];
104 j3 = ctx->input[3];
105 j4 = ctx->input[4];
106 j5 = ctx->input[5];
107 j6 = ctx->input[6];
108 j7 = ctx->input[7];
109 j8 = ctx->input[8];
110 j9 = ctx->input[9];
111 j10 = ctx->input[10];
112 j11 = ctx->input[11];
113 j12 = ctx->input[12];
114 j13 = ctx->input[13];
115 j14 = ctx->input[14];
116 j15 = ctx->input[15];
117
118 for (;;) {
119 if (bytes < 64) {
120 memset(tmp, 0, 64);
121 for (i = 0; i < bytes; ++i) {
122 tmp[i] = m[i];
123 }
124 m = tmp;
125 ctarget = c;
126 c = tmp;
127 }
128 x0 = j0;
129 x1 = j1;
130 x2 = j2;
131 x3 = j3;
132 x4 = j4;
133 x5 = j5;
134 x6 = j6;
135 x7 = j7;
136 x8 = j8;
137 x9 = j9;
138 x10 = j10;
139 x11 = j11;
140 x12 = j12;
141 x13 = j13;
142 x14 = j14;
143 x15 = j15;
144 for (i = 20; i > 0; i -= 2) {
145 QUARTERROUND(x0, x4, x8, x12)
146 QUARTERROUND(x1, x5, x9, x13)
147 QUARTERROUND(x2, x6, x10, x14)
148 QUARTERROUND(x3, x7, x11, x15)
149 QUARTERROUND(x0, x5, x10, x15)
150 QUARTERROUND(x1, x6, x11, x12)
151 QUARTERROUND(x2, x7, x8, x13)
152 QUARTERROUND(x3, x4, x9, x14)
153 }
154 x0 = PLUS(x0, j0);
155 x1 = PLUS(x1, j1);
156 x2 = PLUS(x2, j2);
157 x3 = PLUS(x3, j3);
158 x4 = PLUS(x4, j4);
159 x5 = PLUS(x5, j5);
160 x6 = PLUS(x6, j6);
161 x7 = PLUS(x7, j7);
162 x8 = PLUS(x8, j8);
163 x9 = PLUS(x9, j9);
164 x10 = PLUS(x10, j10);
165 x11 = PLUS(x11, j11);
166 x12 = PLUS(x12, j12);
167 x13 = PLUS(x13, j13);
168 x14 = PLUS(x14, j14);
169 x15 = PLUS(x15, j15);
170
171 x0 = XOR(x0, LOAD32_LE(m + 0));
172 x1 = XOR(x1, LOAD32_LE(m + 4));
173 x2 = XOR(x2, LOAD32_LE(m + 8));
174 x3 = XOR(x3, LOAD32_LE(m + 12));
175 x4 = XOR(x4, LOAD32_LE(m + 16));
176 x5 = XOR(x5, LOAD32_LE(m + 20));
177 x6 = XOR(x6, LOAD32_LE(m + 24));
178 x7 = XOR(x7, LOAD32_LE(m + 28));
179 x8 = XOR(x8, LOAD32_LE(m + 32));
180 x9 = XOR(x9, LOAD32_LE(m + 36));
181 x10 = XOR(x10, LOAD32_LE(m + 40));
182 x11 = XOR(x11, LOAD32_LE(m + 44));
183 x12 = XOR(x12, LOAD32_LE(m + 48));
184 x13 = XOR(x13, LOAD32_LE(m + 52));
185 x14 = XOR(x14, LOAD32_LE(m + 56));
186 x15 = XOR(x15, LOAD32_LE(m + 60));
187
188 j12 = PLUSONE(j12);
189 /* LCOV_EXCL_START */
190 if (!j12) {
191 j13 = PLUSONE(j13);
192 }
193 /* LCOV_EXCL_STOP */
194
195 STORE32_LE(c + 0, x0);
196 STORE32_LE(c + 4, x1);
197 STORE32_LE(c + 8, x2);
198 STORE32_LE(c + 12, x3);
199 STORE32_LE(c + 16, x4);
200 STORE32_LE(c + 20, x5);
201 STORE32_LE(c + 24, x6);
202 STORE32_LE(c + 28, x7);
203 STORE32_LE(c + 32, x8);
204 STORE32_LE(c + 36, x9);
205 STORE32_LE(c + 40, x10);
206 STORE32_LE(c + 44, x11);
207 STORE32_LE(c + 48, x12);
208 STORE32_LE(c + 52, x13);
209 STORE32_LE(c + 56, x14);
210 STORE32_LE(c + 60, x15);
211
212 if (bytes <= 64) {
213 if (bytes < 64) {
214 for (i = 0; i < (unsigned int) bytes; ++i) {
215 ctarget[i] = c[i]; /* ctarget cannot be NULL */
216 }
217 }
218 ctx->input[12] = j12;
219 ctx->input[13] = j13;
220
221 return;
222 }
223 bytes -= 64;
224 c += 64;
225 m += 64;
226 }
227 }
228
229 void chacha20_encrypt_msg(void *msg, size_t len, const void *nonce, const void *key)
230 {
231 struct chacha_ctx ctx;
232
233 chacha_keysetup(&ctx, key);
234 chacha_ivsetup(&ctx, nonce, NULL);
235 chacha20_encrypt_bytes(&ctx, msg, msg, len);
236 }