enacl_nif.c 22.7 KB
Newer Older
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
1
2
3
4
#include "erl_nif.h"

#include <sodium.h>

5
6
7
8
#ifndef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
# error Requires dirty schedulers
#endif

9
/* Errors */
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
10
11
12
13
14
static
ERL_NIF_TERM nacl_error_tuple(ErlNifEnv *env, char *error_atom) {
	return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, error_atom));
}

15
16
17
18
19
20
21
/* Initialization */
static
int enif_crypto_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) {
	sodium_init();
	return 0;
}

22
/* Low-level functions (Hashing, String Equality, ...) */
23

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
24
25
26
27
static
ERL_NIF_TERM enif_crypto_hash(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary input;
	ErlNifBinary result;
28

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
29
30
31
	if ((argc != 1) || (!enif_inspect_iolist_as_binary(env, argv[0], &input))) {
		return enif_make_badarg(env);
	}
32

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
33
34
35
	if (!enif_alloc_binary(crypto_hash_BYTES, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
36

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
37
	crypto_hash(result.data, input.data, input.size);
38

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
39
40
41
	return enif_make_binary(env, &result);
}

42
43
44
45
static
ERL_NIF_TERM enif_crypto_verify_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary x,y;

46
	if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x))
47
	  || (!enif_inspect_binary(env, argv[1], &y))) {
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
		return enif_make_badarg(env);
	}

	if (x.size != 16 || y.size != 16) {
		return enif_make_badarg(env);
	}

	if (0 == crypto_verify_16(x.data, y.data)) {
		return enif_make_atom(env, "true");
	} else {
		return enif_make_atom(env, "false");
	}
}

static
ERL_NIF_TERM enif_crypto_verify_32(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary x,y;

66
67
	if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x))
	  || (!enif_inspect_binary(env, argv[1], &y))) {
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
		return enif_make_badarg(env);
	}

	if (x.size != 32 || y.size != 32) {
		return enif_make_badarg(env);
	}

	if (0 == crypto_verify_32(x.data, y.data)) {
		return enif_make_atom(env, "true");
	} else {
		return enif_make_atom(env, "false");
	}
}


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/* Public-key cryptography */
static
ERL_NIF_TERM enif_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_NONCEBYTES);
}

static
ERL_NIF_TERM enif_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_ZEROBYTES);
}

static
ERL_NIF_TERM enif_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_BOXZEROBYTES);
}

99
100
101
102
103
104
105
106
107
108
static
ERL_NIF_TERM enif_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_PUBLICKEYBYTES);
}

static
ERL_NIF_TERM enif_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_SECRETKEYBYTES);
}

109
110
111
112
113
static
ERL_NIF_TERM enif_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_box_BEFORENMBYTES);
}

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
114
115
116
static
ERL_NIF_TERM enif_crypto_box_keypair(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary pk, sk;
117

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
118
119
120
	if (argc != 0) {
		return enif_make_badarg(env);
	}
121

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
122
123
124
	if (!enif_alloc_binary(crypto_box_PUBLICKEYBYTES, &pk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
125

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
126
127
128
	if (!enif_alloc_binary(crypto_box_SECRETKEYBYTES, &sk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
129

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
130
	crypto_box_keypair(pk.data, sk.data);
131

132
	return enif_make_tuple2(env, enif_make_binary(env, &pk), enif_make_binary(env, &sk));
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
133
134
}

135
136
137
static
ERL_NIF_TERM enif_crypto_box(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary padded_msg, nonce, pk, sk, result;
138

139
140
141
	if (
	  (argc != 4) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) ||
142
143
144
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &pk)) ||
	  (!enif_inspect_binary(env, argv[3], &sk))) {
145
146
	  	return enif_make_badarg(env);
	}
147

148
149
150
151
152
153
154
	if (
	    (nonce.size != crypto_box_NONCEBYTES) ||
	    (pk.size != crypto_box_PUBLICKEYBYTES) ||
	    (sk.size != crypto_box_SECRETKEYBYTES) ||
	    (padded_msg.size < crypto_box_ZEROBYTES)) {
		return enif_make_badarg(env);
	}
155

156
157
158
	if (!enif_alloc_binary(padded_msg.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
159

160
	crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, pk.data, sk.data);
161

162
163
164
165
166
167
168
169
170
171
	return enif_make_sub_binary(
		env,
		enif_make_binary(env, &result),
		crypto_box_BOXZEROBYTES,
		padded_msg.size - crypto_box_BOXZEROBYTES);
}

static
ERL_NIF_TERM enif_crypto_box_open(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary padded_ciphertext, nonce, pk, sk, result;
172

173
174
175
	if (
	  (argc != 4) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
176
177
178
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &pk)) ||
	  (!enif_inspect_binary(env, argv[3], &sk))) {
179
180
		return enif_make_badarg(env);
	}
181

182
183
184
185
186
187
188
	if (
	  (nonce.size != crypto_box_NONCEBYTES) ||
	  (pk.size != crypto_box_PUBLICKEYBYTES) ||
	  (sk.size != crypto_box_SECRETKEYBYTES) ||
	  (padded_ciphertext.size < crypto_box_BOXZEROBYTES)) {
		return enif_make_badarg(env);
	}
189

190
191
192
	if (!enif_alloc_binary(padded_ciphertext.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
193

194
	if (crypto_box_open(result.data, padded_ciphertext.data, padded_ciphertext.size, nonce.data, pk.data, sk.data) != 0) {
195
		enif_release_binary(&result);
196
197
		return nacl_error_tuple(env, "failed_verification");
	}
198

199
200
201
202
203
204
	return enif_make_sub_binary(
		env,
		enif_make_binary(env, &result),
		crypto_box_ZEROBYTES,
		padded_ciphertext.size - crypto_box_ZEROBYTES);
}
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/* Precomputed crypto boxes */

static
ERL_NIF_TERM enif_crypto_box_beforenm(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary k, pk, sk;
	
	if (
	    (argc != 2) ||
	    (!enif_inspect_binary(env, argv[0], &pk)) ||
	    (!enif_inspect_binary(env, argv[1], &sk)) ||
	    (pk.size != crypto_box_PUBLICKEYBYTES) ||
	    (sk.size != crypto_box_SECRETKEYBYTES)) {
		return enif_make_badarg(env);
	}
	
	if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
	
	crypto_box_beforenm(k.data, pk.data, sk.data);
	
	return enif_make_binary(env, &k);
}

static
ERL_NIF_TERM enif_crypto_box_afternm(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary result, m, nonce, k;
	
	if (
	    (argc != 3) ||
	    (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
	    (!enif_inspect_binary(env, argv[1], &nonce)) ||
	    (!enif_inspect_binary(env, argv[2], &k)) ||
	    (m.size < crypto_box_ZEROBYTES) ||
	    (nonce.size != crypto_box_NONCEBYTES) ||
	    (k.size != crypto_box_BEFORENMBYTES)) {
		return enif_make_badarg(env);
	}
	
	if (!enif_alloc_binary(m.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
	
	crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data);
	
	return enif_make_sub_binary(
		env,
		enif_make_binary(env, &result),
		crypto_box_BOXZEROBYTES,
		m.size - crypto_box_BOXZEROBYTES);
}

static
ERL_NIF_TERM enif_crypto_box_open_afternm(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary result, m, nonce, k;
	
	if (
	    (argc != 3) ||
	    (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
	    (!enif_inspect_binary(env, argv[1], &nonce)) ||
	    (!enif_inspect_binary(env, argv[2], &k)) ||
	    (m.size < crypto_box_BOXZEROBYTES) ||
	    (nonce.size != crypto_box_NONCEBYTES) ||
	    (k.size != crypto_box_BEFORENMBYTES)) {
		return enif_make_badarg(env);
	}
	
	if (!enif_alloc_binary(m.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
	
	if (crypto_box_open_afternm(result.data, m.data, m.size, nonce.data, k.data)) {
		enif_release_binary(&result);
		return nacl_error_tuple(env, "failed_verification");
	}
	
	return enif_make_sub_binary(
		env,
		enif_make_binary(env, &result),
		crypto_box_ZEROBYTES,
		m.size - crypto_box_ZEROBYTES);
}

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/* Signing */
static
ERL_NIF_TERM enif_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_sign_PUBLICKEYBYTES);
}

static
ERL_NIF_TERM enif_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_sign_SECRETKEYBYTES);
}

static
ERL_NIF_TERM enif_crypto_sign_keypair(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary pk, sk;

	if (argc != 0) {
		return enif_make_badarg(env);
	}

	if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	crypto_sign_keypair(pk.data, sk.data);

318
	return enif_make_tuple2(env, enif_make_binary(env, &pk), enif_make_binary(env, &sk));
319
320
}

321
322
323
324
325
326
327
328
static
ERL_NIF_TERM enif_crypto_sign(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary m, sk, sm;
	unsigned long long smlen;

	if (
	  (argc != 2) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
329
	  (!enif_inspect_binary(env, argv[1], &sk))) {
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
		return enif_make_badarg(env);
	}

	if (sk.size != crypto_sign_SECRETKEYBYTES) {
		return enif_make_badarg(env);
	}

	if (!enif_alloc_binary(m.size + crypto_sign_BYTES, &sm)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	crypto_sign(sm.data, &smlen, m.data, m.size, sk.data);

	return enif_make_sub_binary(env, enif_make_binary(env, &sm), 0, smlen);
}

static
ERL_NIF_TERM enif_crypto_sign_open(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary m, sm, pk;
	unsigned long long mlen;

	if (
	  (argc != 2) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &sm)) ||
354
	  (!enif_inspect_binary(env, argv[1], &pk))) {
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
		return enif_make_badarg(env);
	}

	if (pk.size != crypto_sign_PUBLICKEYBYTES) {
		return enif_make_badarg(env);
	}

	if (!enif_alloc_binary(sm.size, &m)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	if (0 == crypto_sign_open(m.data, &mlen, sm.data, sm.size, pk.data)) {
		return enif_make_sub_binary(env, enif_make_binary(env, &m), 0, mlen);
	} else {
		enif_release_binary(&m);
		return nacl_error_tuple(env, "failed_verification");
	}
}

374
/* Secret key cryptography */
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
static
ERL_NIF_TERM enif_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_secretbox_NONCEBYTES);
}

static
ERL_NIF_TERM enif_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_secretbox_KEYBYTES);
}

static
ERL_NIF_TERM enif_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_secretbox_ZEROBYTES);
}

static
ERL_NIF_TERM enif_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_secretbox_BOXZEROBYTES);
}

396
397
398
399
400
401
402
403
404
405
static
ERL_NIF_TERM enif_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_stream_KEYBYTES);
}

static
ERL_NIF_TERM enif_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_stream_NONCEBYTES);
}

406
407
408
409
410
static
ERL_NIF_TERM enif_crypto_auth_BYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_auth_BYTES);
}

411
412
413
414
415
static
ERL_NIF_TERM enif_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_auth_KEYBYTES);
}

416
417
418
419
420
static
ERL_NIF_TERM enif_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_onetimeauth_BYTES);
}

421
422
423
424
425
static
ERL_NIF_TERM enif_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	return enif_make_int64(env, crypto_onetimeauth_KEYBYTES);
}

426
427
428
static
ERL_NIF_TERM enif_crypto_secretbox(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary key, nonce, padded_msg, padded_ciphertext;
429

430
431
432
	if (
	  (argc != 3) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) ||
433
434
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &key))) {
435
436
		return enif_make_badarg(env);
	}
437

438
439
440
441
442
443
	if (
	  (key.size != crypto_secretbox_KEYBYTES) ||
	  (nonce.size != crypto_secretbox_NONCEBYTES) ||
	  (padded_msg.size < crypto_secretbox_ZEROBYTES)) {
		return enif_make_badarg(env);
	}
444

445
446
447
	if (!enif_alloc_binary(padded_msg.size, &padded_ciphertext)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
448

449
450
451
452
453
	crypto_secretbox(
	  padded_ciphertext.data,
	  padded_msg.data, padded_msg.size,
	  nonce.data,
	  key.data);
454

455
456
457
458
459
460
461
462
463
	return enif_make_sub_binary(env,
		enif_make_binary(env, &padded_ciphertext),
		crypto_secretbox_BOXZEROBYTES,
		padded_msg.size - crypto_secretbox_BOXZEROBYTES);
}

static
ERL_NIF_TERM enif_crypto_secretbox_open(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary key, nonce, padded_ciphertext, padded_msg;
464

465
466
467
	if (
	  (argc != 3) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
468
469
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &key))) {
470
471
		return enif_make_badarg(env);
	}
472

473
474
475
476
477
478
	if (
	  (key.size != crypto_secretbox_KEYBYTES) ||
	  (nonce.size != crypto_secretbox_NONCEBYTES) ||
	  (padded_ciphertext.size < crypto_secretbox_BOXZEROBYTES)) {
		return enif_make_badarg(env);
	}
479

480
481
482
	if (!enif_alloc_binary(padded_ciphertext.size, &padded_msg)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
483

484
485
486
487
488
489
490
491
492
	if (crypto_secretbox_open(
	    padded_msg.data,
	    padded_ciphertext.data,
	    padded_ciphertext.size,
	    nonce.data,
	    key.data) != 0) {
		enif_release_binary(&padded_msg);
		return nacl_error_tuple(env, "failed_verification");
	}
493

494
495
496
497
498
499
	return enif_make_sub_binary(
	    env,
	    enif_make_binary(env, &padded_msg),
	    crypto_secretbox_ZEROBYTES,
	    padded_ciphertext.size - crypto_secretbox_ZEROBYTES);
}
500
501
502
503
504
505
506
507
508

static
ERL_NIF_TERM enif_crypto_stream(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary c, n, k;
	ErlNifUInt64 clen;

	if (
	  (argc != 3) ||
	  (!enif_get_uint64(env, argv[0], &clen)) ||
509
510
	  (!enif_inspect_binary(env, argv[1], &n)) ||
	  (!enif_inspect_binary(env, argv[2], &k))) {
511
512
		return enif_make_badarg(env);
	}
513

514
515
516
517
518
	if (
	  (k.size != crypto_stream_KEYBYTES) ||
	  (n.size != crypto_stream_NONCEBYTES)) {
		return enif_make_badarg(env);
	}
519

520
521
522
	if (!enif_alloc_binary(clen, &c)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
523

524
	crypto_stream(c.data, c.size, n.data, k.data);
525

526
527
528
529
530
531
	return enif_make_binary(env, &c);
}

static
ERL_NIF_TERM enif_crypto_stream_xor(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary c, m, n, k;
532

533
534
535
	if (
	  (argc != 3) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
536
537
	  (!enif_inspect_binary(env, argv[1], &n)) ||
	  (!enif_inspect_binary(env, argv[2], &k))) {
538
539
		return enif_make_badarg(env);
	}
540

541
542
543
544
545
	if (
	  (k.size != crypto_stream_KEYBYTES) ||
	  (n.size != crypto_stream_NONCEBYTES)) {
		return enif_make_badarg(env);
	}
546

547
548
549
	if (!enif_alloc_binary(m.size, &c)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
550

551
	crypto_stream_xor(c.data, m.data, m.size, n.data, k.data);
552

553
554
555
	return enif_make_binary(env, &c);
}

556
557
558
559
560
561
562
static
ERL_NIF_TERM enif_crypto_auth(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary a,m,k;

	if (
	  (argc != 2) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
563
	  (!enif_inspect_binary(env, argv[1], &k))) {
564
565
		return enif_make_badarg(env);
	}
566

567
568
569
	if (k.size != crypto_auth_KEYBYTES) {
		return enif_make_badarg(env);
	}
570

571
572
573
	if (!enif_alloc_binary(crypto_auth_BYTES, &a)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
574

575
	crypto_auth(a.data, m.data, m.size, k.data);
576

577
578
579
580
581
582
	return enif_make_binary(env, &a);
}

static
ERL_NIF_TERM enif_crypto_auth_verify(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary a, m, k;
583

584
585
	if (
	  (argc != 3) ||
586
	  (!enif_inspect_binary(env, argv[0], &a)) ||
587
	  (!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
588
	  (!enif_inspect_binary(env, argv[2], &k))) {
589
590
		return enif_make_badarg(env);
	}
591

592
593
594
595
596
	if (
	  (k.size != crypto_auth_KEYBYTES) ||
	  (a.size != crypto_auth_BYTES)) {
		return enif_make_badarg(env);
	}
597

598
599
600
601
602
603
	if (0 == crypto_auth_verify(a.data, m.data, m.size, k.data)) {
		return enif_make_atom(env, "true");
	} else {
		return enif_make_atom(env, "false");
	}
}
604
605
606
607
608
609
610
611

static
ERL_NIF_TERM enif_crypto_onetimeauth(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary a,m,k;

	if (
	  (argc != 2) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
612
	  (!enif_inspect_binary(env, argv[1], &k))) {
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
		return enif_make_badarg(env);
	}

	if (k.size != crypto_onetimeauth_KEYBYTES) {
		return enif_make_badarg(env);
	}

	if (!enif_alloc_binary(crypto_onetimeauth_BYTES, &a)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	crypto_onetimeauth(a.data, m.data, m.size, k.data);

	return enif_make_binary(env, &a);
}

static
ERL_NIF_TERM enif_crypto_onetimeauth_verify(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary a, m, k;

	if (
	  (argc != 3) ||
635
	  (!enif_inspect_binary(env, argv[0], &a)) ||
636
	  (!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
637
	  (!enif_inspect_binary(env, argv[2], &k))) {
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
		return enif_make_badarg(env);
	}

	if (
	  (k.size != crypto_onetimeauth_KEYBYTES) ||
	  (a.size != crypto_onetimeauth_BYTES)) {
		return enif_make_badarg(env);
	}

	if (0 == crypto_onetimeauth_verify(a.data, m.data, m.size, k.data)) {
		return enif_make_atom(env, "true");
	} else {
		return enif_make_atom(env, "false");
	}
}
653

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
static
ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[])
{
	size_t req_size;
	ErlNifBinary result;
	
	if ((argc != 1) || (!enif_get_uint64(env, argv[0], &req_size))) {
		return enif_make_badarg(env);
	}
	
	if (!enif_alloc_binary(req_size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
	
	randombytes(result.data, result.size);
	
	return enif_make_binary(env, &result);
}

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
/* Various other helper functions */

void uint64_pack(unsigned char *y, ErlNifUInt64 x)
{
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
	*y++ = x; x >>= 8;
}

ErlNifUInt64
uint64_unpack(const unsigned char *x)
{
	ErlNifUInt64 result;

	result = x[7];
	result <<= 8; result |= x[6];
	result <<= 8; result |= x[5];
	result <<= 8; result |= x[4];
	result <<= 8; result |= x[3];
	result <<= 8; result |= x[2];
	result <<= 8; result |= x[1];
	result <<= 8; result |= x[0];
	return result;
}

int
crypto_block(unsigned char *out, const unsigned char *in, const unsigned char *k)
{
	ErlNifUInt64 v0 = uint64_unpack(in + 0);
	ErlNifUInt64 v1 = uint64_unpack(in + 8);
	ErlNifUInt64 k0 = uint64_unpack(k + 0);
	ErlNifUInt64 k1 = uint64_unpack(k + 8);
	ErlNifUInt64 k2 = uint64_unpack(k + 16);
	ErlNifUInt64 k3 = uint64_unpack(k + 24);
	ErlNifUInt64 sum = 0;
	ErlNifUInt64 delta = 0x9e3779b97f4a7c15;
	int i;
	for (i = 0;i < 32;++i) {
		sum += delta;
		v0 += ((v1<<7) + k0) ^ (v1 + sum) ^ ((v1>>12) + k1);
		v1 += ((v0<<16) + k2) ^ (v0 + sum) ^ ((v0>>8) + k3);
	}
	uint64_pack(out + 0,v0);
	uint64_pack(out + 8,v1);

	return 0;
}

static
ERL_NIF_TERM enif_scramble_block_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[])
{
	ErlNifBinary in, out, key;
	
	if (
	  (argc != 2) ||
	  (!enif_inspect_binary(env, argv[0], &in)) ||
	  (!enif_inspect_binary(env, argv[1], &key)) ||
	  (in.size != 16) || (key.size != 32)) {
		return enif_make_badarg(env);
	}
	
	if (!enif_alloc_binary(in.size, &out)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
	
	crypto_block(out.data, in.data, key.data);
	
	return enif_make_binary(env, &out);
}

748
/* Tie the knot to the Erlang world */
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
749
static ErlNifFunc nif_funcs[] = {
750
751
752
	{"crypto_box_NONCEBYTES", 0, enif_crypto_box_NONCEBYTES},
	{"crypto_box_ZEROBYTES", 0, enif_crypto_box_ZEROBYTES},
	{"crypto_box_BOXZEROBYTES", 0, enif_crypto_box_BOXZEROBYTES},
753
754
	{"crypto_box_PUBLICKEYBYTES", 0, enif_crypto_box_PUBLICKEYBYTES},
	{"crypto_box_SECRETKEYBYTES", 0, enif_crypto_box_SECRETKEYBYTES},
755
	{"crypto_box_BEFORENMBYTES", 0, enif_crypto_box_BEFORENMBYTES},
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
756
	{"crypto_box_keypair", 0, enif_crypto_box_keypair},
757
	{"crypto_box_b", 4, enif_crypto_box},
758
	{"crypto_box", 4, enif_crypto_box, ERL_NIF_DIRTY_JOB_CPU_BOUND},
759
	{"crypto_box_open_b", 4, enif_crypto_box_open},
760
	{"crypto_box_open", 4, enif_crypto_box_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
761
762
763
	{"crypto_box_beforenm", 2, enif_crypto_box_beforenm},
	{"crypto_box_afternm", 3, enif_crypto_box_afternm},
	{"crypto_box_open_afternm", 3, enif_crypto_box_open_afternm},
764

765
766
767
	{"crypto_sign_PUBLICKEYBYTES", 0, enif_crypto_sign_PUBLICKEYBYTES},
	{"crypto_sign_SECRETKEYBYTES", 0, enif_crypto_sign_SECRETKEYBYTES},
	{"crypto_sign_keypair", 0, enif_crypto_sign_keypair},
768
	{"crypto_sign_b", 2, enif_crypto_sign},
769
	{"crypto_sign", 2, enif_crypto_sign, ERL_NIF_DIRTY_JOB_CPU_BOUND},
770
	{"crypto_sign_open_b", 2, enif_crypto_sign_open},
771
	{"crypto_sign_open", 2, enif_crypto_sign_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
772

773
774
775
776
	{"crypto_secretbox_NONCEBYTES", 0, enif_crypto_secretbox_NONCEBYTES},
	{"crypto_secretbox_ZEROBYTES", 0, enif_crypto_secretbox_ZEROBYTES},
	{"crypto_secretbox_BOXZEROBYTES", 0, enif_crypto_secretbox_BOXZEROBYTES},
	{"crypto_secretbox_KEYBYTES", 0, enif_crypto_secretbox_KEYBYTES},
777
	{"crypto_secretbox_b", 3, enif_crypto_secretbox},
778
	{"crypto_secretbox", 3, enif_crypto_secretbox, ERL_NIF_DIRTY_JOB_CPU_BOUND},
779
	{"crypto_secretbox_open_b", 3, enif_crypto_secretbox_open},
780
781
	{"crypto_secretbox_open", 3, enif_crypto_secretbox_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},

782
783
	{"crypto_stream_KEYBYTES", 0, enif_crypto_stream_KEYBYTES},
	{"crypto_stream_NONCEBYTES", 0, enif_crypto_stream_NONCEBYTES},
784
	{"crypto_stream_b", 3, enif_crypto_stream},
785
	{"crypto_stream", 3, enif_crypto_stream, ERL_NIF_DIRTY_JOB_CPU_BOUND},
786
	{"crypto_stream_xor_b", 3, enif_crypto_stream_xor},
787
788
	{"crypto_stream_xor", 3, enif_crypto_stream_xor, ERL_NIF_DIRTY_JOB_CPU_BOUND},

789
	{"crypto_auth_BYTES", 0, enif_crypto_auth_BYTES},
790
	{"crypto_auth_KEYBYTES", 0, enif_crypto_auth_KEYBYTES},
791
	{"crypto_auth_b", 2, enif_crypto_auth},
792
	{"crypto_auth", 2, enif_crypto_auth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
793
	{"crypto_auth_verify_b", 3, enif_crypto_auth_verify},
794
795
	{"crypto_auth_verify", 3, enif_crypto_auth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},

796
	{"crypto_onetimeauth_BYTES", 0, enif_crypto_onetimeauth_BYTES},
797
	{"crypto_onetimeauth_KEYBYTES", 0, enif_crypto_onetimeauth_KEYBYTES},
798
	{"crypto_onetimeauth_b", 2, enif_crypto_onetimeauth},
799
	{"crypto_onetimeauth", 2, enif_crypto_onetimeauth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
800
	{"crypto_onetimeauth_verify_b", 3, enif_crypto_onetimeauth_verify},
801
802
	{"crypto_onetimeauth_verify", 3, enif_crypto_onetimeauth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},

803
	{"crypto_hash_b", 1, enif_crypto_hash},
804
805
	{"crypto_hash", 1, enif_crypto_hash, ERL_NIF_DIRTY_JOB_CPU_BOUND},
	{"crypto_verify_16", 2, enif_crypto_verify_16},
806
807
808
	{"crypto_verify_32", 2, enif_crypto_verify_32},
	
	{"randombytes_b", 1, enif_randombytes},
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
809
810
811
	{"randombytes", 1, enif_randombytes, ERL_NIF_DIRTY_JOB_CPU_BOUND},
	
	{"scramble_block_16", 2, enif_scramble_block_16}
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
812
813
};

814
815


816
ERL_NIF_INIT(enacl_nif, nif_funcs, enif_crypto_load, NULL, NULL, NULL);