enacl_nif.c 23.8 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
		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");
	}
}

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* Curve 25519 */
static
ERL_NIF_TERM enif_crypto_curve25519_scalarmult(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary secret, basepoint, output;
	uint8_t bp[crypto_scalarmult_curve25519_BYTES];

	if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &secret))
			|| (!enif_inspect_binary(env, argv[1], &basepoint))
			|| (secret.size != crypto_scalarmult_curve25519_BYTES)
			|| (basepoint.size != crypto_scalarmult_curve25519_BYTES)) {
		return enif_make_badarg(env);
	}

	memcpy(bp, basepoint.data, crypto_scalarmult_curve25519_BYTES);

	/* Clear the high-bit. Better safe than sorry. */
	bp[31] &= 0x7f;

	if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &output)) {
		return nacl_error_tuple(env, "alloc_failed");
	}

	if (crypto_scalarmult_curve25519(output.data, secret.data, bp) < 0) {
		return nacl_error_tuple(env, "scalarmult_curve25519_failed");
	}

	return enif_make_binary(env, &output);
}
110

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* 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);
}

127
128
129
130
131
132
133
134
135
136
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);
}

137
138
139
140
141
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
142
143
144
static
ERL_NIF_TERM enif_crypto_box_keypair(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary pk, sk;
145

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
146
147
148
	if (argc != 0) {
		return enif_make_badarg(env);
	}
149

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
150
151
152
	if (!enif_alloc_binary(crypto_box_PUBLICKEYBYTES, &pk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
153

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
154
155
156
	if (!enif_alloc_binary(crypto_box_SECRETKEYBYTES, &sk)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
157

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

160
	return enif_make_tuple2(env, enif_make_binary(env, &pk), enif_make_binary(env, &sk));
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
161
162
}

163
164
165
static
ERL_NIF_TERM enif_crypto_box(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary padded_msg, nonce, pk, sk, result;
166

167
168
169
	if (
	  (argc != 4) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) ||
170
171
172
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &pk)) ||
	  (!enif_inspect_binary(env, argv[3], &sk))) {
173
174
	  	return enif_make_badarg(env);
	}
175

176
177
178
179
180
181
182
	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);
	}
183

184
185
186
	if (!enif_alloc_binary(padded_msg.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
187

188
	crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, pk.data, sk.data);
189

190
191
192
193
194
195
196
197
198
199
	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;
200

201
202
203
	if (
	  (argc != 4) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
204
205
206
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &pk)) ||
	  (!enif_inspect_binary(env, argv[3], &sk))) {
207
208
		return enif_make_badarg(env);
	}
209

210
211
212
213
214
215
216
	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);
	}
217

218
219
220
	if (!enif_alloc_binary(padded_ciphertext.size, &result)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
221

222
	if (0 != crypto_box_open(result.data, padded_ciphertext.data, padded_ciphertext.size, nonce.data, pk.data, sk.data)) {
223
		enif_release_binary(&result);
224
225
		return nacl_error_tuple(env, "failed_verification");
	}
226

227
228
229
230
231
232
	return enif_make_sub_binary(
		env,
		enif_make_binary(env, &result),
		crypto_box_ZEROBYTES,
		padded_ciphertext.size - crypto_box_ZEROBYTES);
}
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/* 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");
	}
	
305
	if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data, k.data)) {
306
307
308
309
310
311
312
313
314
315
316
		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);
}

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/* 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);

346
	return enif_make_tuple2(env, enif_make_binary(env, &pk), enif_make_binary(env, &sk));
347
348
}

349
350
351
352
353
354
355
356
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)) ||
357
	  (!enif_inspect_binary(env, argv[1], &sk))) {
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
		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)) ||
382
	  (!enif_inspect_binary(env, argv[1], &pk))) {
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
		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");
	}
}

402
/* Secret key cryptography */
403

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
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);
}

424
425
426
427
428
429
430
431
432
433
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);
}

434
435
436
437
438
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);
}

439
440
441
442
443
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);
}

444
445
446
447
448
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);
}

449
450
451
452
453
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);
}

454
455
456
static
ERL_NIF_TERM enif_crypto_secretbox(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
	ErlNifBinary key, nonce, padded_msg, padded_ciphertext;
457

458
459
460
	if (
	  (argc != 3) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) ||
461
462
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &key))) {
463
464
		return enif_make_badarg(env);
	}
465

466
467
468
469
470
471
	if (
	  (key.size != crypto_secretbox_KEYBYTES) ||
	  (nonce.size != crypto_secretbox_NONCEBYTES) ||
	  (padded_msg.size < crypto_secretbox_ZEROBYTES)) {
		return enif_make_badarg(env);
	}
472

473
474
475
	if (!enif_alloc_binary(padded_msg.size, &padded_ciphertext)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
476

477
478
479
480
481
	crypto_secretbox(
	  padded_ciphertext.data,
	  padded_msg.data, padded_msg.size,
	  nonce.data,
	  key.data);
482

483
484
485
486
487
488
489
490
491
	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;
492

493
494
495
	if (
	  (argc != 3) ||
	  (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
496
497
	  (!enif_inspect_binary(env, argv[1], &nonce)) ||
	  (!enif_inspect_binary(env, argv[2], &key))) {
498
499
		return enif_make_badarg(env);
	}
500

501
502
503
504
505
506
	if (
	  (key.size != crypto_secretbox_KEYBYTES) ||
	  (nonce.size != crypto_secretbox_NONCEBYTES) ||
	  (padded_ciphertext.size < crypto_secretbox_BOXZEROBYTES)) {
		return enif_make_badarg(env);
	}
507

508
509
510
	if (!enif_alloc_binary(padded_ciphertext.size, &padded_msg)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
511

512
513
514
515
516
517
518
519
520
	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");
	}
521

522
523
524
525
526
527
	return enif_make_sub_binary(
	    env,
	    enif_make_binary(env, &padded_msg),
	    crypto_secretbox_ZEROBYTES,
	    padded_ciphertext.size - crypto_secretbox_ZEROBYTES);
}
528
529
530
531
532
533
534
535
536

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)) ||
537
538
	  (!enif_inspect_binary(env, argv[1], &n)) ||
	  (!enif_inspect_binary(env, argv[2], &k))) {
539
540
		return enif_make_badarg(env);
	}
541

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

548
549
550
	if (!enif_alloc_binary(clen, &c)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
551

552
	crypto_stream(c.data, c.size, n.data, k.data);
553

554
555
556
557
558
559
	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;
560

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

569
570
571
572
573
	if (
	  (k.size != crypto_stream_KEYBYTES) ||
	  (n.size != crypto_stream_NONCEBYTES)) {
		return enif_make_badarg(env);
	}
574

575
576
577
	if (!enif_alloc_binary(m.size, &c)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
578

579
	crypto_stream_xor(c.data, m.data, m.size, n.data, k.data);
580

581
582
583
	return enif_make_binary(env, &c);
}

584
585
586
587
588
589
590
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)) ||
591
	  (!enif_inspect_binary(env, argv[1], &k))) {
592
593
		return enif_make_badarg(env);
	}
594

595
596
597
	if (k.size != crypto_auth_KEYBYTES) {
		return enif_make_badarg(env);
	}
598

599
600
601
	if (!enif_alloc_binary(crypto_auth_BYTES, &a)) {
		return nacl_error_tuple(env, "alloc_failed");
	}
602

603
	crypto_auth(a.data, m.data, m.size, k.data);
604

605
606
607
608
609
610
	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;
611

612
613
	if (
	  (argc != 3) ||
614
	  (!enif_inspect_binary(env, argv[0], &a)) ||
615
	  (!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
616
	  (!enif_inspect_binary(env, argv[2], &k))) {
617
618
		return enif_make_badarg(env);
	}
619

620
621
622
623
624
	if (
	  (k.size != crypto_auth_KEYBYTES) ||
	  (a.size != crypto_auth_BYTES)) {
		return enif_make_badarg(env);
	}
625

626
627
628
629
630
631
	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");
	}
}
632
633
634
635
636
637
638
639

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)) ||
640
	  (!enif_inspect_binary(env, argv[1], &k))) {
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
		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) ||
663
	  (!enif_inspect_binary(env, argv[0], &a)) ||
664
	  (!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
665
	  (!enif_inspect_binary(env, argv[2], &k))) {
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
		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");
	}
}
681

682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
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
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
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
/* 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);
}

776
/* Tie the knot to the Erlang world */
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
777
static ErlNifFunc nif_funcs[] = {
778
779
780
	{"crypto_box_NONCEBYTES", 0, enif_crypto_box_NONCEBYTES},
	{"crypto_box_ZEROBYTES", 0, enif_crypto_box_ZEROBYTES},
	{"crypto_box_BOXZEROBYTES", 0, enif_crypto_box_BOXZEROBYTES},
781
782
	{"crypto_box_PUBLICKEYBYTES", 0, enif_crypto_box_PUBLICKEYBYTES},
	{"crypto_box_SECRETKEYBYTES", 0, enif_crypto_box_SECRETKEYBYTES},
783
	{"crypto_box_BEFORENMBYTES", 0, enif_crypto_box_BEFORENMBYTES},
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
784
	{"crypto_box_keypair", 0, enif_crypto_box_keypair},
785
	{"crypto_box_b", 4, enif_crypto_box},
786
	{"crypto_box", 4, enif_crypto_box, ERL_NIF_DIRTY_JOB_CPU_BOUND},
787
	{"crypto_box_open_b", 4, enif_crypto_box_open},
788
	{"crypto_box_open", 4, enif_crypto_box_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
789
	{"crypto_box_beforenm", 2, enif_crypto_box_beforenm},
790
791
792
793
	{"crypto_box_afternm_b", 3, enif_crypto_box_afternm},
	{"crypto_box_afternm", 3, enif_crypto_box_afternm, ERL_NIF_DIRTY_JOB_CPU_BOUND},
	{"crypto_box_open_afternm_b", 3, enif_crypto_box_open_afternm},
	{"crypto_box_open_afternm", 3, enif_crypto_box_open_afternm, ERL_NIF_DIRTY_JOB_CPU_BOUND},
794

795
796
797
	{"crypto_sign_PUBLICKEYBYTES", 0, enif_crypto_sign_PUBLICKEYBYTES},
	{"crypto_sign_SECRETKEYBYTES", 0, enif_crypto_sign_SECRETKEYBYTES},
	{"crypto_sign_keypair", 0, enif_crypto_sign_keypair},
798
	{"crypto_sign_b", 2, enif_crypto_sign},
799
	{"crypto_sign", 2, enif_crypto_sign, ERL_NIF_DIRTY_JOB_CPU_BOUND},
800
	{"crypto_sign_open_b", 2, enif_crypto_sign_open},
801
	{"crypto_sign_open", 2, enif_crypto_sign_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
802

803
804
805
806
	{"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},
807
	{"crypto_secretbox_b", 3, enif_crypto_secretbox},
808
	{"crypto_secretbox", 3, enif_crypto_secretbox, ERL_NIF_DIRTY_JOB_CPU_BOUND},
809
	{"crypto_secretbox_open_b", 3, enif_crypto_secretbox_open},
810
811
	{"crypto_secretbox_open", 3, enif_crypto_secretbox_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},

812
813
	{"crypto_stream_KEYBYTES", 0, enif_crypto_stream_KEYBYTES},
	{"crypto_stream_NONCEBYTES", 0, enif_crypto_stream_NONCEBYTES},
814
	{"crypto_stream_b", 3, enif_crypto_stream},
815
	{"crypto_stream", 3, enif_crypto_stream, ERL_NIF_DIRTY_JOB_CPU_BOUND},
816
	{"crypto_stream_xor_b", 3, enif_crypto_stream_xor},
817
818
	{"crypto_stream_xor", 3, enif_crypto_stream_xor, ERL_NIF_DIRTY_JOB_CPU_BOUND},

819
	{"crypto_auth_BYTES", 0, enif_crypto_auth_BYTES},
820
	{"crypto_auth_KEYBYTES", 0, enif_crypto_auth_KEYBYTES},
821
	{"crypto_auth_b", 2, enif_crypto_auth},
822
	{"crypto_auth", 2, enif_crypto_auth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
823
	{"crypto_auth_verify_b", 3, enif_crypto_auth_verify},
824
825
	{"crypto_auth_verify", 3, enif_crypto_auth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},

826
	{"crypto_onetimeauth_BYTES", 0, enif_crypto_onetimeauth_BYTES},
827
	{"crypto_onetimeauth_KEYBYTES", 0, enif_crypto_onetimeauth_KEYBYTES},
828
	{"crypto_onetimeauth_b", 2, enif_crypto_onetimeauth},
829
	{"crypto_onetimeauth", 2, enif_crypto_onetimeauth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
830
	{"crypto_onetimeauth_verify_b", 3, enif_crypto_onetimeauth_verify},
831
832
	{"crypto_onetimeauth_verify", 3, enif_crypto_onetimeauth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},

833
	{"crypto_hash_b", 1, enif_crypto_hash},
834
835
	{"crypto_hash", 1, enif_crypto_hash, ERL_NIF_DIRTY_JOB_CPU_BOUND},
	{"crypto_verify_16", 2, enif_crypto_verify_16},
836
	{"crypto_verify_32", 2, enif_crypto_verify_32},
837
838
839

	{"crypto_curve25519_scalarmult", 2, enif_crypto_curve25519_scalarmult},

840
	{"randombytes_b", 1, enif_randombytes},
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
841
842
843
	{"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
844
845
};

846
847


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