enacl.erl 24.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
%%% @doc Module enacl implements bindings to the NaCl/libsodium crypto-library
%%% <p>This module implements NIF bindings to the library known as NaCl (pronounced "salt").
%%% The NaCl library provides a sane cryptographic interface to the world in an attempt to
%%% make it harder to abuse and misuse cryptographic primitives.</p>
%%% <p>This module implements an Erlang-idiomatic API to the underlying library. If in doubt
%%% about a primitive, always consult the underlying documentation.</p>
%%% <p>There are two libraries in existence: NaCl and libsodium, the latter being a more
%%% portable variant of the NaCl library. The C-level API is interchangeable so we can run
%%% on any of these underlying libraries as seen from the Erlang world. We simply have to
%%% restrict ourselves to the portion of the code base which is overlapping.</p>
%%% <p><b>Warning:</b> The cryptographic strength of your implementation is no stronger than
%%% plaintext cryptography unless you take care in using these primitives correctly. Hence,
%%% implementors should use these primitives with that in mind.</p>
14
%%% <p><b>Note:</b> All functions will fail with a `badarg' error if given incorrect
15
%%% parameters.</p>
16
%%% @end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
17
18
-module(enacl).

19
%% Public key crypto
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
20
-export([
21
22
23
	box_keypair/0,
	box/4,
	box_open/4,
24
25
26
27
	box_beforenm/2,
	box_afternm/3,
	box_open_afternm/3,

28
29
	box_nonce_size/0,
	box_public_key_bytes/0,
30
	box_secret_key_bytes/0,
31
	box_beforenm_bytes/0,
32

33
34
	sign_keypair_public_size/0,
	sign_keypair_secret_size/0,
35
36
	sign_keypair/0,
	sign/2,
37
38
39
	sign_open/2,
        sign_detached/2,
        sign_verify_detached/3
40
41
]).

42
43
%% Secret key crypto
-export([
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
44
45
	secretbox_key_size/0,
	secretbox_nonce_size/0,
46
47
	secretbox/3,
	secretbox_open/3,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
48
49
50

	stream_key_size/0,
	stream_nonce_size/0,
51
	stream/3,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
52
53
54
	stream_xor/3,

	auth_key_size/0,
55
	auth_size/0,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
56
57
58
59
	auth/2,
	auth_verify/3,

	onetime_auth_key_size/0,
60
	onetime_auth_size/0,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
61
62
	onetime_auth/2,
	onetime_auth_verify/3
63
64
]).

65
66
67
68
69
%% Curve 25519.
-export([
	curve25519_scalarmult/2
]).

Alexander Færøy's avatar
Alexander Færøy committed
70
71
72
73
74
75
76
77
78
%% Ed 25519.
-export([
	crypto_sign_ed25519_keypair/0,
	crypto_sign_ed25519_public_to_curve25519/1,
	crypto_sign_ed25519_secret_to_curve25519/1,
	crypto_sign_ed25519_public_size/0,
	crypto_sign_ed25519_secret_size/0
]).

79
%% Low-level functions
80
-export([
81
82
83
	hash/1,
	verify_16/2,
	verify_32/2
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
84
85
]).

86
87
88
89
90
%% Libsodium specific functions (which are also part of the "undocumented" interface to NaCl
-export([
	randombytes/1
]).

91
92
93
94
95
%% Other helper functions
-export([
	reds/1
]).

96
%% Definitions of system budgets
97
98
%% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are
%% described in the README.md file.
99
-define(HASH_SIZE, 32 * 1024).
100
-define(HASH_REDUCTIONS, 104 * 2).
101
-define(BOX_SIZE, 32 * 1024).
102
-define(BOX_REDUCTIONS, 115 * 2).
103
104
105
-define(BOX_BEFORENM_REDUCTIONS, 60).
-define(BOX_AFTERNM_SIZE, 64 * 1024).
-define(BOX_AFTERNM_REDUCTIONS, 110 * 2).
106
-define(SIGN_SIZE, 16 * 1024).
107
-define(SIGN_REDUCTIONS, 160 * 2).
108
-define(SECRETBOX_SIZE, 64 * 1024).
109
110
-define(SECRETBOX_REDUCTIONS, 107 * 2).
-define(SECRETBOX_OPEN_REDUCTIONS, 51 * 2).
111
-define(STREAM_SIZE, 128 * 1024).
112
-define(STREAM_REDUCTIONS, 120 * 2).
113
-define(AUTH_SIZE, 32 * 1024).
114
-define(AUTH_REDUCTIONS, 102 * 2).
115
-define(ONETIME_AUTH_SIZE, 128 * 1024).
116
-define(ONETIME_AUTH_REDUCTIONS, 105 * 2).
117
118
-define(RANDOMBYTES_SIZE, 1024).
-define(RANDOMBYTES_REDUCTIONS, 200).
119

120
121
%% @doc reds/1 counts the number of reductions and scheduler yields for a thunk
%%
122
123
%% Count reductions and number of scheduler yields for Fun. Fun is assumed
%% to be one of the above exor variants.
124
125
%% @end
-spec reds(fun (() -> any())) -> #{ atom() => any() }.
126
127
128
129
130
131
132
133
134
reds(Fun) ->
    Parent = self(),
    Pid = spawn(fun() ->
                        Self = self(),
                        Start = os:timestamp(),
                        R0 = process_info(Self, reductions),
                        Fun(),
                        R1 = process_info(Self, reductions),
                        T = timer:now_diff(os:timestamp(), Start),
135
136
                        Parent ! {Self,#{ time_diff => T, after_reductions => R1, before_reductions => R0}}
                    end),
137
138
139
140
141
    receive
        {Pid,Result} ->
            Result
    end.

142
143
%% Low level helper functions
%% -----------------
144

145
%% @doc hash/1 hashes data into a cryptographically secure checksum.
146
%%
147
%% <p>Given an iodata(), `Data' of any size, run a cryptographically secure hash algorithm to
148
149
150
151
152
%% produce a checksum of the data. This can be used to verify the integrity of a data block
%% since the checksum have the properties of cryptographic hashes in general.</p>
%% <p>The currently selected primitive (Nov. 2014) is SHA-512</p>
%% @end
-spec hash(Data) -> Checksum
153
  when Data :: iodata(),
154
155
       Checksum :: binary().

156
hash(Bin) ->
157
    case iolist_size(Bin) of
158
159
160
161
        K when K =< ?HASH_SIZE ->
            bump(enacl_nif:crypto_hash_b(Bin), ?HASH_REDUCTIONS, ?HASH_SIZE, K);
        _ ->
            enacl_nif:crypto_hash(Bin)
162
    end.
163

164
%% @doc verify_16/2 implements constant time 16-byte binary() verification
165
%%
166
167
168
169
170
171
%% <p>A subtle problem in cryptographic software are timing attacks where an attacker exploits
%% early exist in string verification if the strings happen to mismatch. This allows the
%% attacker to time how long verification took and thus learn the structure of the desired
%% string to use. The verify_16/2 call will check two 16 byte strings for equality while
%% guaranteeing the equality operation is constant time.</p>
%% <p>If the strings are not exactly 16 bytes, the comparison function will fail with badarg.</p>
172
%% <p>The functions take binary() values and not iolist() values since the latter would convert in non-constant time</p>
173
174
175
%% <p>Verification returns a boolean. `true' if the strings match, `false' otherwise.</p>
%% @end
-spec verify_16(binary(), binary()) -> boolean().
176
177
verify_16(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_16(X, Y);
verify_16(_, _) -> error(badarg).
178

179
%% @doc verify_32/2 implements constant time 32-byte iolist() verification
180
%%
181
%% This function works as {@link verify_16/2} but does so on 32 byte strings. Same caveats apply.
182
183
%% @end
-spec verify_32(binary(), binary()) -> boolean().
184
185
verify_32(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_32(X, Y);
verify_32(_, _) -> error(badarg).
186
187
188

%% Public Key Crypto
%% ---------------------
189
%% @doc box_keypair/0 creates a new Public/Secret keypair.
190
%%
191
192
%% Generates and returns a new key pair for the Box encryption scheme. The return value is a
%% map in order to avoid using the public key as a secret key and vice versa.
193
%% @end.
194
-spec box_keypair() -> #{ atom() => binary() }.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
195
box_keypair() ->
196
197
	{PK, SK} = enacl_nif:crypto_box_keypair(),
	#{ public => PK, secret => SK}.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
198

199
%% @doc box/4 encrypts+authenticates a message to another party.
200
201
202
%%
%% Encrypt a `Msg' to the party identified by public key `PK' using your own secret key `SK' to
%% authenticate yourself. Requires a `Nonce' in addition. Returns the ciphered message.
203
204
%% @end
-spec box(Msg, Nonce, PK, SK) -> CipherText
205
  when Msg :: iodata(),
206
207
208
209
       Nonce :: binary(),
       PK :: binary(),
       SK :: binary(),
       CipherText :: binary().
210
box(Msg, Nonce, PK, SK) ->
211
212
213
214
215
216
    case iolist_size(Msg) of
        K when K =< ?BOX_SIZE ->
            bump(enacl_nif:crypto_box_b([p_zerobytes(), Msg], Nonce, PK, SK), ?BOX_REDUCTIONS, ?BOX_SIZE, K);
        _ ->
            enacl_nif:crypto_box([p_zerobytes(), Msg], Nonce, PK, SK)
    end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
217

218
%% @doc box_open/4 decrypts+verifies a message from another party.
219
220
221
%%
%% Decrypt a `CipherText' into a `Msg' given the other partys public key `PK' and your secret
%% key `SK'. Also requires the same nonce as was used by the other party. Returns the plaintext
222
%% message.
223
%% @end
224
-spec box_open(CipherText, Nonce, PK, SK) -> {ok, Msg} | {error, failed_verification}
225
  when CipherText :: iodata(),
226
227
228
229
       Nonce :: binary(),
       PK :: binary(),
       SK :: binary(),
       Msg :: binary().
230
box_open(CipherText, Nonce, PK, SK) ->
231
232
233
234
235
236
237
238
239
240
241
242
243
    case iolist_size(CipherText) of
        K when K =< ?BOX_SIZE ->
           R =
            case enacl_nif:crypto_box_open_b([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end,
           bump(R, ?BOX_REDUCTIONS, ?BOX_SIZE, K);
        _ ->
            case enacl_nif:crypto_box_open([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end
244
245
    end.

246
247
248
249
250
251
252
253
254
255
%% @doc box_beforenm/2 precomputes a box shared key for a PK/SK keypair
%% @end
-spec box_beforenm(PK, SK) -> binary()
    when
      PK :: binary(),
      SK :: binary().
box_beforenm(PK, SK) ->
    R = enacl_nif:crypto_box_beforenm(PK, SK),
    erlang:bump_reductions(?BOX_BEFORENM_REDUCTIONS),
    R.
256

257
%% @doc box_afternm/3 works like `box/4' but uses a precomputed key
258
%%
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
%% Calling `box_afternm(M, Nonce, K)' for a precomputed key `K = box_beforenm(PK, SK)' works exactly as
%% if you had called `box(M, Nonce, PK, SK)'. Except that it avoids computations in the elliptic curve Curve25519,
%% and thus is a much faster operation.
%% @end
-spec box_afternm(Msg, Nonce, K) -> CipherText
  when
    Msg :: iodata(),
    Nonce :: binary(),
    K :: binary(),
    CipherText :: binary().
box_afternm(Msg, Nonce, Key) ->
    case iolist_size(Msg) of
        K when K =< ?BOX_AFTERNM_SIZE ->
            bump(enacl_nif:crypto_box_afternm_b([p_zerobytes(), Msg], Nonce, Key),
            	?BOX_AFTERNM_REDUCTIONS, ?BOX_AFTERNM_SIZE, K);
        _ ->
            enacl_nif:crypto_box_afternm([p_zerobytes(), Msg], Nonce, Key)
    end.

%% @doc box_open_afternm/3 works like `box_open/4` but uses a precomputed key
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
305
%% Calling `box_open_afternm(M, Nonce, K)' for a precomputed key `K = box_beforenm(PK, SK)' works exactly as
%% if you had called `box_open(M, Nonce, PK, SK)'. Except the operation is much faster as it avoids costly
%% computations in the elliptic curve Curve25519.
%% @end
-spec box_open_afternm(CT, Nonce, K) -> {ok, Msg} | {error, failed_verification}
  when
    CT :: binary(),
    Nonce :: binary(),
    K :: binary(),
    Msg :: binary().
box_open_afternm(CipherText, Nonce, Key) ->
    case iolist_size(CipherText) of
        K when K =< ?BOX_AFTERNM_SIZE ->
           R =
            case enacl_nif:crypto_box_open_afternm_b([p_box_zerobytes(), CipherText], Nonce, Key) of
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end,
           bump(R, ?BOX_AFTERNM_REDUCTIONS, ?BOX_AFTERNM_SIZE, K);
        _ ->
            case enacl_nif:crypto_box_open_afternm([p_box_zerobytes(), CipherText], Nonce, Key) of
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end
    end.

306
%% @doc box_nonce_size/0 return the byte-size of the nonce
307
%%
308
309
310
%% Used to obtain the size of the nonce.
%% @end.
-spec box_nonce_size() -> pos_integer().
311
312
313
box_nonce_size() ->
	enacl_nif:crypto_box_NONCEBYTES().

314
315
%% @private
-spec box_public_key_bytes() -> pos_integer().
316
317
box_public_key_bytes() ->
	enacl_nif:crypto_box_PUBLICKEYBYTES().
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
318

319
320
321
322
%% @private
box_beforenm_bytes() ->
	enacl_nif:crypto_box_BEFORENMBYTES().

323
324
%% Signatures

325
326
327
%% @private
sign_keypair_public_size() ->
    enacl_nif:crypto_sign_PUBLICKEYBYTES().
328

329
330
331
332
%% @private
sign_keypair_secret_size() ->
    enacl_nif:crypto_sign_SECRETKEYBYTES().

333
%% @doc sign_keypair/0 returns a signature keypair for signing
334
%%
335
336
%% The returned value is a map in order to make it harder to misuse keys.
%% @end
337
-spec sign_keypair() -> #{ atom() => binary() }.
338
sign_keypair() ->
339
    {PK, SK} = enacl_nif:crypto_sign_keypair(),
340
341
342
    #{ public => PK, secret => SK}.

%% @doc sign/2 signs a message with a digital signature identified by a secret key.
343
%%
344
345
346
347
%% Given a message `M' and a secret key `SK' the function will sign the message and return a signed message `SM'.
%% @end
-spec sign(M, SK) -> SM
  when
348
    M :: iodata(),
349
350
    SK :: binary(),
    SM :: binary().
351
sign(M, SK) ->
352
353
354
355
356
357
    case iolist_size(M) of
      K when K =< ?SIGN_SIZE ->
        bump(enacl_nif:crypto_sign_b(M, SK), ?SIGN_REDUCTIONS, ?SIGN_SIZE, K);
      _ ->
        enacl_nif:crypto_sign(M, SK)
    end.
358
359

%% @doc sign_open/2 opens a digital signature
360
%%
361
362
363
%% Given a signed message `SM' and a public key `PK', verify that the message has the
%% right signature. Returns either `{ok, M}' or `{error, failed_verification}' depending
%% on the correctness of the signature.
364
365
366
%% @end
-spec sign_open(SM, PK) -> {ok, M} | {error, failed_verification}
  when
367
    SM :: iodata(),
368
369
    PK :: binary(),
    M :: binary().
370
sign_open(SM, PK) ->
371
372
    case iolist_size(SM) of
        K when K =< ?SIGN_SIZE ->
373
          R = case enacl_nif:crypto_sign_open_b(SM, PK) of
374
375
376
377
378
379
380
381
382
                  M when is_binary(M) -> {ok, M};
                  {error, Err} -> {error, Err}
              end,
          bump(R, ?SIGN_REDUCTIONS, ?SIGN_SIZE, byte_size(SM));
        _ ->
          case enacl_nif:crypto_sign_open(SM, PK) of
              M when is_binary(M) -> {ok, M};
              {error, Err} -> {error, Err}
          end
383
    end.
384

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
%% @doc sign_detached/2 computes a digital signature given a message and a secret key.
%%
%% Given a message `M' and a secret key `SK' the function will compute the digital signature `DS'.
%% @end
-spec sign_detached(M, SK) -> DS
  when
    M  :: iodata(),
    SK :: binary(),
    DS :: binary().
sign_detached(M, SK) -> enacl_nif:crypto_sign_detached(M, SK).

%% @doc sign_verify_detached/3 verifies the given signature against the given
%% message for the given public key.
%%
%% Given a signature `SIG', a message `M', and a public key `PK', the function computes
%% true iff the `SIG' is valid for `M' and `PK'.
-spec sign_verify_detached(SIG, M, PK) -> boolean()
  when
    SIG :: binary(),
    M   :: iodata(),
    PK  :: binary().
sign_verify_detached(SIG, M, PK) -> enacl_nif:crypto_sign_verify_detached(SIG, M, PK).

408
409
%% @private
-spec box_secret_key_bytes() -> pos_integer().
410
411
412
box_secret_key_bytes() ->
	enacl_nif:crypto_box_SECRETKEYBYTES().

413
%% @doc secretbox/3 encrypts a message with a key
414
%%
415
416
417
418
419
420
421
422
423
%% Given a `Msg', a `Nonce' and a `Key' encrypt the message with the Key while taking the
%% nonce into consideration. The function returns the Box obtained from the encryption.
%% @end
-spec secretbox(Msg, Nonce, Key) -> Box
  when
    Msg :: iodata(),
    Nonce :: binary(),
    Key :: binary(),
    Box :: binary().
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
424

425
426
427
428
429
430
431
432
433
secretbox(Msg, Nonce, Key) ->
    case iolist_size(Msg) of
        K when K =< ?SECRETBOX_SIZE ->
          bump(enacl_nif:crypto_secretbox_b([s_zerobytes(), Msg], Nonce, Key),
               ?SECRETBOX_REDUCTIONS,
               ?SECRETBOX_SIZE,
               K);
        _ ->
          enacl_nif:crypto_secretbox([s_zerobytes(), Msg], Nonce, Key)
434
    end.
435
%% @doc secretbox_open/3 opens a sealed box.
436
%%
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
%% Given a boxed `CipherText' and given we know the used `Nonce' and `Key' we can open the box
%% to obtain the `Msg` within. Returns either `{ok, Msg}' or `{error, failed_verification}'.
%% @end
-spec secretbox_open(CipherText, Nonce, Key) -> {ok, Msg} | {error, failed_verification}
  when
    CipherText :: iodata(),
    Nonce :: binary(),
    Key :: binary(),
    Msg :: binary().
secretbox_open(CipherText, Nonce, Key) ->
    case iolist_size(CipherText) of
        K when K =< ?SECRETBOX_SIZE ->
          R = case enacl_nif:crypto_secretbox_open_b([s_box_zerobytes(), CipherText],
                                                     Nonce, Key) of
                  {error, Err} -> {error, Err};
                  Bin when is_binary(Bin) -> {ok, Bin}
              end,
          bump(R, ?SECRETBOX_OPEN_REDUCTIONS, ?SECRETBOX_SIZE, K);
        _ ->
          case enacl_nif:crypto_secretbox_open([s_box_zerobytes(), CipherText], Nonce, Key) of
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
          end
   end.
461

462
463
464
465
%% @doc secretbox_nonce_size/0 returns the size of the secretbox nonce
%%
%% When encrypting with a secretbox, the nonce must have this size
%% @end
466
467
secretbox_nonce_size() ->
    enacl_nif:crypto_secretbox_NONCEBYTES().
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
468

469
470
471
472
%% @doc secretbox_key_size/0 returns the size of the secretbox key
%%
%% When encrypting with a secretbox, the key must have this size
%% @end
473
474
475
secretbox_key_size() ->
    enacl_nif:crypto_secretbox_KEYBYTES().

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
476
477
478
479
480
481
482
483
484
485
486
%% @doc stream_nonce_size/0 returns the byte size of the nonce for streams
%% @end
-spec stream_nonce_size() -> pos_integer().
stream_nonce_size() -> enacl_nif:crypto_stream_NONCEBYTES().

%% @doc stream_key_size/0 returns the byte size of the key for streams
%% @end
-spec stream_key_size() -> pos_integer().
stream_key_size() -> enacl_nif:crypto_stream_KEYBYTES().

%% @doc stream/3 produces a cryptographic stream suitable for secret-key encryption
487
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
488
489
490
491
492
493
494
495
496
497
498
499
%% <p>Given a positive `Len' a `Nonce' and a `Key', the stream/3 function will return an unpredictable cryptographic stream of bytes
%% based on this output. In other words, the produced stream is indistinguishable from a random stream. Using this stream one
%% can XOR it with a message in order to produce a encrypted message.</p>
%% <p><b>Note:</b>  You need to use different Nonce values for different messages. Otherwise the same stream is produced and thus
%% the messages will have predictability which in turn makes the encryption scheme fail.</p>
%% @end
-spec stream(Len, Nonce, Key) -> CryptoStream
  when
    Len :: non_neg_integer(),
    Nonce :: binary(),
    Key :: binary(),
    CryptoStream :: binary().
500
501
502
503
504
stream(Len, Nonce, Key) when is_integer(Len), Len >= 0, Len =< ?STREAM_SIZE ->
    bump(enacl_nif:crypto_stream_b(Len, Nonce, Key),
         ?STREAM_REDUCTIONS,
         ?STREAM_SIZE,
         Len);
505
506
507
508
stream(Len, Nonce, Key) when is_integer(Len), Len >= 0 ->
    enacl_nif:crypto_stream(Len, Nonce, Key);
stream(_, _, _) -> error(badarg).

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
509
%% @doc stream_xor/3 encrypts a plaintext message into ciphertext
510
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
511
512
513
514
515
%% The stream_xor/3 function works by using the {@link stream/3} api to XOR a message with the cryptographic stream. The same
%% caveat applies: the nonce must be new for each sent message or the system fails to work.
%% @end
-spec stream_xor(Msg, Nonce, Key) -> CipherText
  when
516
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
517
518
519
    Nonce :: binary(),
    Key :: binary(),
    CipherText :: binary().
520
stream_xor(Msg, Nonce, Key) ->
521
522
523
524
525
526
527
528
529
    case iolist_size(Msg) of
      K when K =< ?STREAM_SIZE ->
        bump(enacl_nif:crypto_stream_xor_b(Msg, Nonce, Key),
             ?STREAM_REDUCTIONS,
             ?STREAM_SIZE,
             K);
      _ ->
        enacl_nif:crypto_stream_xor(Msg, Nonce, Key)
    end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
530
531
532
533
534
535

%% @doc auth_key_size/0 returns the byte-size of the authentication key
%% @end
-spec auth_key_size() -> pos_integer().
auth_key_size() -> enacl_nif:crypto_auth_KEYBYTES().

536
537
538
539
540
%% @doc auth_size/0 returns the byte-size of the authenticator
%% @end
-spec auth_size() -> pos_integer().
auth_size() -> enacl_nif:crypto_auth_BYTES().

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
541
%% @doc auth/2 produces an authenticator (MAC) for a message
542
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
543
544
545
546
547
%% Given a `Msg' and a `Key' produce a MAC/Authenticator for that message. The key can be reused for several such Msg/Authenticator pairs.
%% An eavesdropper will not learn anything extra about the message structure.
%% @end
-spec auth(Msg, Key) -> Authenticator
  when
548
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
549
550
    Key :: binary(),
    Authenticator :: binary().
551
552
553
554
555
556
557
auth(Msg, Key) ->
  case iolist_size(Msg) of
    K when K =< ?AUTH_SIZE ->
      bump(enacl_nif:crypto_auth_b(Msg, Key), ?AUTH_REDUCTIONS, ?AUTH_SIZE, K);
    _ ->
      enacl_nif:crypto_auth(Msg, Key)
  end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
558
559

%% @doc auth_verify/3 verifies an authenticator for a message
560
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
561
562
563
564
565
566
%% Given an `Authenticator', a `Msg' and a `Key'; verify that the MAC for the pair `{Msg, Key}' is really `Authenticator'. Returns
%% the value `true' if the verfication passes. Upon failure, the function returns `false'.
%% @end
-spec auth_verify(Authenticator, Msg, Key) -> boolean()
  when
    Authenticator :: binary(),
567
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
568
    Key :: binary().
569
570
571
572
573
574
575
576
577
578
auth_verify(A, M, K) ->
    case iolist_size(M) of
      K when K =< ?AUTH_SIZE ->
        bump(enacl_nif:crypto_auth_verify_b(A, M, K),
             ?AUTH_REDUCTIONS,
             ?AUTH_SIZE,
             K);
      _ ->
        enacl_nif:crypto_auth_verify(A, M, K)
    end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
579
580

%% @doc onetime_auth/2 produces a ONE-TIME authenticator for a message
581
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
582
%% This function works like {@link auth/2} except that the key must not be used again for subsequent messages. That is, the pair
583
%% `{Msg, Key}' is unique and only to be used once. The advantage is noticably faster execution.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
584
585
586
%% @end
-spec onetime_auth(Msg, Key) -> Authenticator
  when
587
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
588
589
    Key :: binary(),
    Authenticator :: binary().
590
591
592
593
594
595
596
597
598
599
onetime_auth(Msg, Key) ->
    case iolist_size(Msg) of
      K when K =< ?ONETIME_AUTH_SIZE ->
        bump(enacl_nif:crypto_onetimeauth_b(Msg, Key),
             ?ONETIME_AUTH_REDUCTIONS,
             ?ONETIME_AUTH_SIZE,
             K);
      _ ->
        enacl_nif:crypto_onetimeauth(Msg, Key)
    end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
600
601

%% @doc onetime_auth_verify/3 verifies an ONE-TIME authenticator for a message
602
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
603
%% Given an `Authenticator', a `Msg' and a `Key'; verify that the MAC for the pair `{Msg, Key}' is really `Authenticator'. Returns
604
%% the value `true' if the verification passes. Upon failure, the function returns `false'. Note the caveat from {@link onetime_auth/2}
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
605
606
607
608
609
%% applies: you are not allowed to ever use the same key again for another message.
%% @end
-spec onetime_auth_verify(Authenticator, Msg, Key) -> boolean()
  when
    Authenticator :: binary(),
610
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
611
    Key :: binary().
612
613
614
615
616
617
618
619
620
621
onetime_auth_verify(A, M, K) ->
    case iolist_size(M) of
      K when K =< ?ONETIME_AUTH_SIZE ->
        bump(enacl_nif:crypto_onetimeauth_verify_b(A, M, K),
             ?ONETIME_AUTH_REDUCTIONS,
             ?ONETIME_AUTH_SIZE,
             K);
      _ ->
        enacl_nif:crypto_onetimeauth_verify(A, M, K)
    end.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
622

623
624
625
626
627
%% @doc onetime_auth_size/0 returns the number of bytes of the one-time authenticator
%% @end
-spec onetime_auth_size() -> pos_integer().
onetime_auth_size() -> enacl_nif:crypto_onetimeauth_BYTES().

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
628
629
630
631
632
%% @doc onetime_auth_key_size/0 returns the byte-size of the onetime authentication key
%% @end
-spec onetime_auth_key_size() -> pos_integer().
onetime_auth_key_size() -> enacl_nif:crypto_onetimeauth_KEYBYTES().

633
634
635
636
637
638
639
640
%% Curve 25519 Crypto
%% ------------------
%% @doc curve25519_scalarmult/2 does a scalar multiplication between the Secret and the BasePoint.
%% @end.
-spec curve25519_scalarmult(Secret :: binary(), BasePoint :: binary()) -> binary().
curve25519_scalarmult(Secret, BasePoint) ->
	enacl_nif:crypto_curve25519_scalarmult(Secret, BasePoint).

Alexander Færøy's avatar
Alexander Færøy committed
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
%% Ed 25519 Crypto
%% ---------------
%% @doc crypto_sign_ed25519_keypair/0 creates a new Ed 25519 Public/Secret keypair.
%%
%% Generates and returns a new key pair for the Ed 25519 signature scheme. The return value is a
%% map in order to avoid using the public key as a secret key and vice versa.
%% @end
-spec crypto_sign_ed25519_keypair() -> #{ atom() => binary() }.
crypto_sign_ed25519_keypair() ->
	{PK, SK} = enacl_nif:crypto_sign_ed25519_keypair(),
	#{ public => PK, secret => SK }.

%% @doc crypto_sign_ed25519_public_to_curve25519/1 converts a given Ed 25519 public
%% key to a Curve 25519 public key.
%% @end
-spec crypto_sign_ed25519_public_to_curve25519(PublicKey :: binary()) -> binary().
crypto_sign_ed25519_public_to_curve25519(PublicKey) ->
	enacl_nif:crypto_sign_ed25519_public_to_curve25519(PublicKey).

%% @doc crypto_sign_ed25519_secret_to_curve25519/1 converts a given Ed 25519 secret
%% key to a Curve 25519 secret key.
%% @end
-spec crypto_sign_ed25519_secret_to_curve25519(SecretKey :: binary()) -> binary().
crypto_sign_ed25519_secret_to_curve25519(SecretKey) ->
	enacl_nif:crypto_sign_ed25519_secret_to_curve25519(SecretKey).

-spec crypto_sign_ed25519_public_size() -> pos_integer().
crypto_sign_ed25519_public_size() ->
	enacl_nif:crypto_sign_ed25519_PUBLICKEYBYTES().

-spec crypto_sign_ed25519_secret_size() -> pos_integer().
crypto_sign_ed25519_secret_size() ->
	enacl_nif:crypto_sign_ed25519_SECRETKEYBYTES().

675
676
677
%% Obtaining random bytes

%% @doc randombytes/1 produces a stream of random bytes of the given size
678
%%
679
680
681
682
683
684
685
686
687
688
%% The security properties of the random stream are that of the libsodium library. Specifically,
%% we use:
%%
%% * RtlGenRandom() on Windows systems
%% * arc4random() on OpenBSD and Bitrig
%% * /dev/urandom on other Unix environments
%%
%% It is up to you to pick a system with a appropriately strong (P)RNG for your purpose. We refer
%% you to the underlying system implementations for random data.
%% @end
689
-spec randombytes(non_neg_integer()) -> binary().
690
691
692
693
694
randombytes(N) when N =< ?RANDOMBYTES_SIZE ->
    bump(enacl_nif:randombytes_b(N), ?RANDOMBYTES_REDUCTIONS, ?RANDOMBYTES_SIZE, N);
randombytes(N) ->
    enacl_nif:randombytes(N).

695
%% Helpers
696
p_zerobytes() ->
697
	binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()).
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
698

699
p_box_zerobytes() ->
700
	binary:copy(<<0>>, enacl_nif:crypto_box_BOXZEROBYTES()).
701
702
703

s_zerobytes() ->
	binary:copy(<<0>>, enacl_nif:crypto_secretbox_ZEROBYTES()).
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
704

705
706
s_box_zerobytes() ->
	binary:copy(<<0>>, enacl_nif:crypto_secretbox_BOXZEROBYTES()).
707

708
bump(Res, Budget, Max, Sz) ->
709
710
    Reds =  (Budget * Sz) div Max,
    erlang:bump_reductions(max(1, Reds)),
711
    Res.