docs: authors: add Doug as minor contr. (thanks)
[netsniff-ng.git] / src / curve.c
blob3e31fc06ffc443c21ea46f1a38fe120d46dc7131
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <syslog.h>
14 #include <limits.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/stat.h>
20 #include "built_in.h"
21 #include "xmalloc.h"
22 #include "curve.h"
23 #include "xutils.h"
24 #include "xio.h"
25 #include "die.h"
26 #include "mtrand.h"
27 #include "curvetun.h"
28 #include "locking.h"
29 #include "crypto_verify_32.h"
30 #include "crypto_box_curve25519xsalsa20poly1305.h"
31 #include "crypto_scalarmult_curve25519.h"
33 /* Some parts derived from public domain code from curveprotect project */
35 #define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm
36 #define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm
37 #define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm
39 #define NONCE_LENGTH 16 /* size of taia */
40 #define NONCE_OFFSET (crypto_box_curve25519xsalsa20poly1305_NONCEBYTES - NONCE_LENGTH)
42 void curve25519_selftest(void)
44 /* Test from the NaCl library */
45 int i;
46 unsigned char alicesk[32] = {
47 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,
48 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
49 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
50 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a
52 unsigned char bobpk[32] = {
53 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4,
54 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37,
55 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,
56 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f
58 unsigned char nonce[24] = {
59 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73,
60 0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6,
61 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37
63 /* API requires first 32 bytes to be 0 */
64 unsigned char m[163] = {
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5,
70 0xcf, 0x14, 0x13, 0x16, 0xeb, 0xeb, 0x0c, 0x7b,
71 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4,
72 0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc,
73 0xe5, 0xec, 0xba, 0xaf, 0x33, 0xbd, 0x75, 0x1a,
74 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29,
75 0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4,
76 0x1d, 0xb6, 0x6c, 0xce, 0x31, 0x4a, 0xdb, 0x31,
77 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d,
78 0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57,
79 0xe2, 0xf6, 0x55, 0x6a, 0xd6, 0xb1, 0x31, 0x8a,
80 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde,
81 0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd,
82 0x49, 0x24, 0xca, 0x1c, 0x60, 0x90, 0x2e, 0x52,
83 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40,
84 0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64,
85 0x5e, 0x07, 0x05
87 unsigned char c[163];
88 unsigned char result[147] = {
89 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5,
90 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9,
91 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73,
92 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce,
93 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4,
94 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a,
95 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b,
96 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72,
97 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2,
98 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38,
99 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a,
100 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae,
101 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea,
102 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda,
103 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde,
104 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3,
105 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6,
106 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74,
107 0xe3, 0x55, 0xa5
110 crypto_box_curve25519xsalsa20poly1305(c, m, 163, nonce, bobpk, alicesk);
112 for (i = 16; i < 163; ++i) {
113 if (c[i] != result[i - 16])
114 panic("PANIC: crypto selftest failed at pos %d "
115 "(%u != %u)! :-(\n", i, c[i], result[i]);
119 static int hexdigit(char x)
121 if (x >= '0' && x <= '9')
122 return x - '0';
123 if (x >= 'a' && x <= 'f')
124 return 10 + (x - 'a');
125 if (x >= 'A' && x <= 'F')
126 return 10 + (x - 'A');
127 return -1;
130 int curve25519_pubkey_hexparse_32(unsigned char *y, size_t ylen,
131 const char *x, size_t len)
133 int seen_digits = 0, seen_colons = 0;
135 if (!x || !y || ylen != 32)
136 return 0;
138 while (len > 0 && seen_digits != 32) {
139 int digit0, digit1;
141 if (x[0] == '\0')
142 break;
143 if (x[0] == ':') {
144 seen_colons++;
145 --len;
146 x++;
147 continue;
150 digit0 = hexdigit(x[0]);
151 if (digit0 == -1)
152 return 0;
154 digit1 = hexdigit(x[1]);
155 if (digit1 == -1)
156 return 0;
158 *y++ = digit1 + 16 * digit0;
160 seen_digits++;
161 --len;
162 x += 2;
165 if (/*x[0] != '\0' ||*/ seen_digits != 32 || seen_colons != 31)
166 return 0;
168 return 1;
171 int curve25519_alloc_or_maybe_die(struct curve25519_struct *c)
173 if (!c)
174 return -EINVAL;
176 c->enc_buf_size = TUNBUFF_SIZ;
177 c->dec_buf_size = TUNBUFF_SIZ;
179 c->enc_buf = xmalloc_aligned(c->enc_buf_size, 16);
180 c->dec_buf = xmalloc_aligned(c->dec_buf_size, 16);
182 spinlock_init(&c->enc_lock);
183 spinlock_init(&c->dec_lock);
185 mt_init_by_seed_rand_array();
187 return 0;
190 void curve25519_free(void *vc)
192 struct curve25519_struct *c = vc;
194 if (!c)
195 return;
197 memset(c->enc_buf, 0, c->enc_buf_size);
198 memset(c->dec_buf, 0, c->dec_buf_size);
200 xfree(c->enc_buf);
201 xfree(c->dec_buf);
203 spinlock_destroy(&c->enc_lock);
204 spinlock_destroy(&c->dec_lock);
207 int curve25519_proto_init(struct curve25519_proto *p, unsigned char *pubkey_remote,
208 size_t len, char *home, int server)
210 int fd;
211 ssize_t ret;
212 char path[PATH_MAX];
213 unsigned char secretkey_own[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
214 unsigned char publickey_own[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
216 if (!pubkey_remote ||
217 len != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
218 return -EINVAL;
220 memset(path, 0, sizeof(path));
221 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
223 fd = open_or_die(path, O_RDONLY);
225 ret = read(fd, secretkey_own, sizeof(secretkey_own));
226 if (ret != sizeof(secretkey_own)) {
227 xmemset(secretkey_own, 0, sizeof(secretkey_own));
228 panic("Cannot read private key!\n");
231 close(fd);
233 crypto_scalarmult_curve25519_base(publickey_own, secretkey_own);
235 if (!crypto_verify_32(publickey_own, pubkey_remote)) {
236 xmemset(secretkey_own, 0, sizeof(secretkey_own));
237 xmemset(publickey_own, 0, sizeof(publickey_own));
238 panic("PANIC: remote end has same public key as you have!!!\n");
241 crypto_box_beforenm(p->key, pubkey_remote, secretkey_own);
243 xmemset(p->enonce, 0, sizeof(p->enonce));
244 xmemset(p->dnonce, 0, sizeof(p->dnonce));
246 xmemset(secretkey_own, 0, sizeof(secretkey_own));
247 xmemset(publickey_own, 0, sizeof(publickey_own));
249 return 0;
252 ssize_t curve25519_encode(struct curve25519_struct *c, struct curve25519_proto *p,
253 unsigned char *plaintext, size_t size,
254 unsigned char **chipertext)
256 int ret, i;
257 ssize_t done = size;
258 struct taia packet_taia;
260 spinlock_lock(&c->enc_lock);
262 if (unlikely(size > c->enc_buf_size)) {
263 spinlock_unlock(&c->enc_lock);
264 return -ENOMEM;
267 taia_now(&packet_taia);
268 taia_pack(p->enonce + NONCE_OFFSET, &packet_taia);
270 memset(c->enc_buf, 0, c->enc_buf_size);
272 ret = crypto_box_afternm(c->enc_buf, plaintext, size,
273 p->enonce, p->key);
274 if (unlikely(ret)) {
275 spinlock_unlock(&c->enc_lock);
276 return -EIO;
279 memcpy(c->enc_buf + crypto_box_boxzerobytes - NONCE_LENGTH,
280 p->enonce + NONCE_OFFSET, NONCE_LENGTH);
282 for (i = 0; i < crypto_box_boxzerobytes - NONCE_LENGTH; ++i)
283 c->enc_buf[i] = (uint8_t) mt_rand_int32();
285 (*chipertext) = c->enc_buf;
287 spinlock_unlock(&c->enc_lock);
289 return done;
292 ssize_t curve25519_decode(struct curve25519_struct *c, struct curve25519_proto *p,
293 unsigned char *chipertext, size_t size,
294 unsigned char **plaintext, struct taia *arrival_taia)
296 int ret;
297 ssize_t done = size;
298 struct taia packet_taia, __arrival_taia;
300 spinlock_lock(&c->dec_lock);
302 if (unlikely(size > c->dec_buf_size)) {
303 spinlock_unlock(&c->dec_lock);
304 return -ENOMEM;
307 if (unlikely(size < crypto_box_boxzerobytes + NONCE_LENGTH)) {
308 spinlock_unlock(&c->dec_lock);
309 return 0;
311 if (arrival_taia == NULL) {
312 taia_now(&__arrival_taia);
313 arrival_taia = &__arrival_taia;
316 taia_unpack(chipertext + crypto_box_boxzerobytes - NONCE_LENGTH,
317 &packet_taia);
318 if (is_good_taia(arrival_taia, &packet_taia) == 0) {
319 /* Ignoring packet */
320 spinlock_unlock(&c->dec_lock);
321 syslog(LOG_ERR, "Bad packet time! Dropping connection!\n");
322 return 0;
325 memcpy(p->dnonce + NONCE_OFFSET,
326 chipertext + crypto_box_boxzerobytes - NONCE_LENGTH,
327 NONCE_LENGTH);
329 memset(c->dec_buf, 0, c->dec_buf_size);
331 ret = crypto_box_open_afternm(c->dec_buf, chipertext, size,
332 p->dnonce, p->key);
333 if (unlikely(ret)) {
334 spinlock_unlock(&c->dec_lock);
335 return -EIO;
338 (*plaintext) = c->dec_buf;
340 spinlock_unlock(&c->dec_lock);
342 return done;