Skip to content

Commit 6e1898f

Browse files
committed
add chacha20 implementation
Signed-off-by: Felix Fietkau <[email protected]>
1 parent 45a4814 commit 6e1898f

File tree

5 files changed

+293
-18
lines changed

5 files changed

+293
-18
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ELSE()
3030
SET(ubus "")
3131
ENDIF()
3232

33-
ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c)
33+
ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c chacha20.c)
3434
TARGET_LINK_LIBRARIES(unet ubox)
3535

3636
ADD_EXECUTABLE(unetd ${SOURCES})

chacha20.c

+236
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
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+
}

chacha20.h

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright (C) 2022 Felix Fietkau <[email protected]>
4+
*/
5+
#ifndef __UNETD_CHACHA20_H
6+
#define __UNETD_CHACHA20_H
7+
8+
#define CHACHA20_NONCE_SIZE 8
9+
#define CHACHA20_KEY_SIZE 32
10+
11+
void chacha20_encrypt_msg(void *msg, size_t len, const void *nonce, const void *key);
12+
13+
#endif

siphash.h

+9-17
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,13 @@
1616
#include <stdint.h>
1717
#include <stdlib.h>
1818
#include <stdbool.h>
19-
#include <libubox/utils.h>
19+
#include "utils.h"
2020

2121
#define SIPHASH_ALIGNMENT __alignof__(uint64_t)
2222
typedef struct {
2323
uint64_t key[2];
2424
} siphash_key_t;
2525

26-
static inline uint16_t get_unaligned_le16(const uint8_t *p)
27-
{
28-
return p[0] | p[1] << 8;
29-
}
30-
31-
static inline uint32_t get_unaligned_le32(const uint8_t *p)
32-
{
33-
return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
34-
}
35-
36-
static inline uint64_t get_unaligned_le64(const uint8_t *p)
37-
{
38-
return (uint64_t)get_unaligned_le32(p + 4) << 32 |
39-
get_unaligned_le32(p);
40-
}
41-
4226
static inline bool siphash_key_is_zero(const siphash_key_t *key)
4327
{
4428
return !(key->key[0] | key->key[1]);
@@ -54,4 +38,12 @@ static inline void siphash_to_le64(void *dest, const void *data, size_t len,
5438
*(uint64_t *)dest = cpu_to_le64(hash);
5539
}
5640

41+
static inline void siphash_to_be64(void *dest, const void *data, size_t len,
42+
const siphash_key_t *key)
43+
{
44+
uint64_t hash = siphash(data, len, key);
45+
46+
*(uint64_t *)dest = cpu_to_be64(hash);
47+
}
48+
5749
#endif /* _LINUX_SIPHASH_H */

utils.h

+34
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
#ifndef __UNETD_UTILS_H
66
#define __UNETD_UTILS_H
77

8+
#include <string.h>
89
#include <netinet/in.h>
10+
#include <libubox/utils.h>
911

1012
struct nl_msg;
1113

@@ -84,6 +86,38 @@ static inline void bitmask_set_val(uint32_t *mask, unsigned int i, bool val)
8486
bitmask_clear(mask, i);
8587
}
8688

89+
static inline uint16_t get_unaligned_be16(const uint8_t *p)
90+
{
91+
return p[1] | p[0] << 8;
92+
}
93+
94+
static inline uint32_t get_unaligned_be32(const uint8_t *p)
95+
{
96+
return p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24;
97+
}
98+
99+
static inline uint64_t get_unaligned_be64(const uint8_t *p)
100+
{
101+
return (uint64_t)get_unaligned_be32(p) << 32 |
102+
get_unaligned_be32(p + 4);
103+
}
104+
105+
static inline uint16_t get_unaligned_le16(const uint8_t *p)
106+
{
107+
return p[0] | p[1] << 8;
108+
}
109+
110+
static inline uint32_t get_unaligned_le32(const uint8_t *p)
111+
{
112+
return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
113+
}
114+
115+
static inline uint64_t get_unaligned_le64(const uint8_t *p)
116+
{
117+
return (uint64_t)get_unaligned_le32(p + 4) << 32 |
118+
get_unaligned_le32(p);
119+
}
120+
87121
int rtnl_init(void);
88122
int rtnl_call(struct nl_msg *msg);
89123

0 commit comments

Comments
 (0)