Skip to content
This repository was archived by the owner on Jun 6, 2021. It is now read-only.

Commit dc11be3

Browse files
committed
Make "random" cloaking deterministic
This uses SipHash and adds a prf_key config option. auxiliary/siphash.c is the unmodified SipHash reference implementation, taken from https://github.com/veorq/SipHash Set syn::prf_key to a string of 32 random hex digits in the configuration to use this feature.
1 parent 2497348 commit dc11be3

File tree

5 files changed

+246
-8
lines changed

5 files changed

+246
-8
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ endif
2020
%.so: %.c syn.h
2121
gcc -std=c99 -Wall $(CFLAGS_WERROR) -O1 -ggdb3 -fPIC $(ATHEME_CFLAGS) -shared -o$@ $<
2222

23+
util.so: util.c auxiliary/siphash.c
24+
gcc -std=c99 -Wall $(CFLAGS_WERROR) -O1 -ggdb3 -fPIC $(ATHEME_CFLAGS) -shared -o$@ $^
25+
2326
.PHONY: install
2427

2528
install: $(MODULES)

auxiliary/siphash.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
SipHash reference C implementation
3+
4+
Copyright (c) 2012-2016 Jean-Philippe Aumasson
5+
6+
Copyright (c) 2012-2014 Daniel J. Bernstein <[email protected]>
7+
8+
To the extent possible under law, the author(s) have dedicated all copyright
9+
and related and neighboring rights to this software to the public domain
10+
worldwide. This software is distributed without any warranty.
11+
12+
You should have received a copy of the CC0 Public Domain Dedication along
13+
with
14+
this software. If not, see
15+
<http://creativecommons.org/publicdomain/zero/1.0/>.
16+
*/
17+
#include <assert.h>
18+
#include <stdint.h>
19+
#include <stdio.h>
20+
#include <string.h>
21+
22+
/* default: SipHash-2-4 */
23+
#define cROUNDS 2
24+
#define dROUNDS 4
25+
26+
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
27+
28+
#define U32TO8_LE(p, v) \
29+
(p)[0] = (uint8_t)((v)); \
30+
(p)[1] = (uint8_t)((v) >> 8); \
31+
(p)[2] = (uint8_t)((v) >> 16); \
32+
(p)[3] = (uint8_t)((v) >> 24);
33+
34+
#define U64TO8_LE(p, v) \
35+
U32TO8_LE((p), (uint32_t)((v))); \
36+
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
37+
38+
#define U8TO64_LE(p) \
39+
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
40+
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
41+
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
42+
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
43+
44+
#define SIPROUND \
45+
do { \
46+
v0 += v1; \
47+
v1 = ROTL(v1, 13); \
48+
v1 ^= v0; \
49+
v0 = ROTL(v0, 32); \
50+
v2 += v3; \
51+
v3 = ROTL(v3, 16); \
52+
v3 ^= v2; \
53+
v0 += v3; \
54+
v3 = ROTL(v3, 21); \
55+
v3 ^= v0; \
56+
v2 += v1; \
57+
v1 = ROTL(v1, 17); \
58+
v1 ^= v2; \
59+
v2 = ROTL(v2, 32); \
60+
} while (0)
61+
62+
#ifdef DEBUG
63+
#define TRACE \
64+
do { \
65+
printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \
66+
(uint32_t)v0); \
67+
printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \
68+
(uint32_t)v1); \
69+
printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \
70+
(uint32_t)v2); \
71+
printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \
72+
(uint32_t)v3); \
73+
} while (0)
74+
#else
75+
#define TRACE
76+
#endif
77+
78+
int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k,
79+
uint8_t *out, const size_t outlen) {
80+
81+
assert((outlen == 8) || (outlen == 16));
82+
uint64_t v0 = 0x736f6d6570736575ULL;
83+
uint64_t v1 = 0x646f72616e646f6dULL;
84+
uint64_t v2 = 0x6c7967656e657261ULL;
85+
uint64_t v3 = 0x7465646279746573ULL;
86+
uint64_t k0 = U8TO64_LE(k);
87+
uint64_t k1 = U8TO64_LE(k + 8);
88+
uint64_t m;
89+
int i;
90+
const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
91+
const int left = inlen & 7;
92+
uint64_t b = ((uint64_t)inlen) << 56;
93+
v3 ^= k1;
94+
v2 ^= k0;
95+
v1 ^= k1;
96+
v0 ^= k0;
97+
98+
if (outlen == 16)
99+
v1 ^= 0xee;
100+
101+
for (; in != end; in += 8) {
102+
m = U8TO64_LE(in);
103+
v3 ^= m;
104+
105+
TRACE;
106+
for (i = 0; i < cROUNDS; ++i)
107+
SIPROUND;
108+
109+
v0 ^= m;
110+
}
111+
112+
switch (left) {
113+
case 7:
114+
b |= ((uint64_t)in[6]) << 48;
115+
case 6:
116+
b |= ((uint64_t)in[5]) << 40;
117+
case 5:
118+
b |= ((uint64_t)in[4]) << 32;
119+
case 4:
120+
b |= ((uint64_t)in[3]) << 24;
121+
case 3:
122+
b |= ((uint64_t)in[2]) << 16;
123+
case 2:
124+
b |= ((uint64_t)in[1]) << 8;
125+
case 1:
126+
b |= ((uint64_t)in[0]);
127+
break;
128+
case 0:
129+
break;
130+
}
131+
132+
v3 ^= b;
133+
134+
TRACE;
135+
for (i = 0; i < cROUNDS; ++i)
136+
SIPROUND;
137+
138+
v0 ^= b;
139+
140+
if (outlen == 16)
141+
v2 ^= 0xee;
142+
else
143+
v2 ^= 0xff;
144+
145+
TRACE;
146+
for (i = 0; i < dROUNDS; ++i)
147+
SIPROUND;
148+
149+
b = v0 ^ v1 ^ v2 ^ v3;
150+
U64TO8_LE(out, b);
151+
152+
if (outlen == 8)
153+
return 0;
154+
155+
v1 ^= 0xdd;
156+
157+
TRACE;
158+
for (i = 0; i < dROUNDS; ++i)
159+
SIPROUND;
160+
161+
b = v0 ^ v1 ^ v2 ^ v3;
162+
U64TO8_LE(out + 8, b);
163+
164+
return 0;
165+
}

facilities.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ void facility_newuser(hook_user_nick_t *data)
501501
syn_debug(2, "Random cloaking used for %s, but I couldn't find a session marker in %s", u->nick, new_vhost);
502502
break;
503503
}
504-
strncpy(randstart, get_random_host_part(), new_vhost + HOSTLEN - randstart);
504+
strncpy(randstart, get_random_host_part(u), new_vhost + HOSTLEN - randstart);
505505
facility_set_cloak(u, new_vhost);
506506
break;
507507
}

syn.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static inline void use_syn_main_symbols(module_t *m)
1818
}
1919

2020
const char* (*decode_hex_ip)(const char *);
21-
const char* (*get_random_host_part)();
21+
const char* (*get_random_host_part)(user_t *);
2222
const char* (*encode_ident_for_host)(const char *);
2323
time_t (*syn_parse_duration)(const char *);
2424
const char* (*syn_format_expiry)(time_t);

util.c

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
#include "atheme.h"
22
#include "syn.h"
33

4+
#define PRF_KEY_LEN 16
5+
#define PRF_KEY_HEX_LEN (PRF_KEY_LEN * 2)
6+
#define PRF_OUT_LEN 16
7+
8+
char *prf_key_hex = NULL;
9+
uint8_t prf_key[PRF_KEY_LEN];
10+
bool prf_ready = false;
11+
412
const char *_decode_hex_ip(const char *hex)
513
{
614
static char buf[16];
@@ -20,17 +28,35 @@ const char *_decode_hex_ip(const char *hex)
2028
return buf;
2129
}
2230

23-
const char *_get_random_host_part()
31+
const char *_get_random_host_part(user_t *u)
2432
{
25-
static char buf[19];
33+
static char buf[PRF_OUT_LEN + 3];
2634

2735
strcpy(buf, "x-");
2836

29-
for (int i=2; i < 18; ++i)
37+
if (!prf_ready)
3038
{
31-
buf[i] = 'a' + rand() % 26;
39+
syn_debug(2, "PRF key not configured, falling back to random cloaking");
40+
for (size_t i = 0; i < PRF_OUT_LEN; ++i)
41+
{
42+
buf[i + 2] = 'a' + rand() % 26;
43+
}
3244
}
33-
buf[18] = 0;
45+
else
46+
{
47+
int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k,
48+
uint8_t *out, const size_t outlen);
49+
50+
uint8_t out[PRF_OUT_LEN];
51+
siphash((unsigned char*)u->uid, strlen(u->uid), prf_key, out, PRF_OUT_LEN);
52+
53+
for (size_t i=0; i < PRF_OUT_LEN; ++i)
54+
{
55+
buf[i + 2] = 'a' + out[i] % 26;
56+
}
57+
}
58+
59+
buf[PRF_OUT_LEN + 2] = 0;
3460
return buf;
3561
}
3662

@@ -128,9 +154,53 @@ const char *_syn_format_expiry(time_t t)
128154
return expirybuf;
129155
}
130156

157+
static void syn_util_config_ready(void *unused)
158+
{
159+
if (prf_key_hex == NULL)
160+
{
161+
slog(LG_ERROR, "syn/util: could not find 'prf_key' configuration entry");
162+
prf_ready = false;
163+
return;
164+
}
165+
166+
if (strlen(prf_key_hex) != PRF_KEY_HEX_LEN)
167+
{
168+
slog(LG_ERROR, "syn/util: prf_key must be exactly %d hex digits", PRF_KEY_HEX_LEN);
169+
prf_ready = false;
170+
return;
171+
}
172+
173+
// This could be done in a single big sscanf, but let's not do that
174+
for (size_t i = 0; i < PRF_KEY_LEN; i++)
175+
{
176+
if (sscanf(prf_key_hex + (i * 2), "%2" SCNx8, &prf_key[i]) != 1)
177+
{
178+
slog(LG_ERROR, "syn/util: failed to parse prf_key - must be string of hex digits");
179+
prf_ready = false;
180+
return;
181+
}
182+
}
183+
184+
prf_ready = true;
185+
}
186+
187+
static void mod_init(struct module *m)
188+
{
189+
use_syn_main_symbols(m);
190+
191+
add_dupstr_conf_item("PRF_KEY", &syn->conf_table, 0, &prf_key_hex, NULL);
192+
hook_add_config_ready(syn_util_config_ready);
193+
}
194+
195+
static void mod_deinit(enum module_unload_intent unused)
196+
{
197+
del_conf_item("PRF_KEY", &syn->conf_table);
198+
hook_del_config_ready(syn_util_config_ready);
199+
}
200+
131201
DECLARE_MODULE_V1
132202
(
133-
"syn/util", false, NULL, NULL,
203+
"syn/util", false, mod_init, mod_deinit,
134204
"$Revision$",
135205
"Stephen Bennett <stephen -at- freenode.net>"
136206
);

0 commit comments

Comments
 (0)