enacl.erl 26.1 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
	sign_open/2,
38
39
40
	sign_detached/2,
	sign_verify_detached/3,

41
42
	box_seal/2,
	box_seal_open/3
43
44
]).

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

	stream_key_size/0,
	stream_nonce_size/0,
54
	stream/3,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
55
56
57
	stream_xor/3,

	auth_key_size/0,
58
	auth_size/0,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
59
60
61
62
	auth/2,
	auth_verify/3,

	onetime_auth_key_size/0,
63
	onetime_auth_size/0,
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
64
65
	onetime_auth/2,
	onetime_auth_verify/3
66
67
]).

68
69
%% Curve 25519.
-export([
70
	curve25519_scalarmult/1, curve25519_scalarmult/2
71
72
]).

Alexander Færøy's avatar
Alexander Færøy committed
73
74
75
76
77
78
79
80
81
%% 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
]).

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

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

94
-export([
95
	verify/0
96
97
]).

98
%% Definitions of system budgets
99
100
%% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are
%% described in the README.md file.
101
102
-define(HASH_SIZE, 4 * 1024).
-define(HASH_REDUCTIONS, 66).
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
-define(RANDOMBYTES_SIZE, 1024).
118
119
120
121
122
123
-define(RANDOMBYTES_REDUCTIONS, 66).

%% Constants used throughout the code base
-define(CRYPTO_BOX_ZEROBYTES, 32).
-define(P_ZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 32 bytes of 0
-define(CRYPTO_BOX_BOXZEROBYTES, 16).
124
-define(P_BOXZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>).  %% 16 bytes
125

126
127
128
129
-define(CRYPTO_SECRETBOX_ZEROBYTES, 32).
-define(S_ZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 32 bytes
-define(CRYPTO_SECRETBOX_BOXZEROBYTES, 16).
-define(S_BOXZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 16 bytes
130
131
132
133
134
135
136
-define(CRYPTO_STREAM_KEYBYTES, 32).
-define(CRYPTO_STREAM_NONCEBYTES, 24).

%% @doc Verify makes sure the constants defined in libsodium matches ours
verify() ->
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()), ?P_ZEROBYTES),
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_box_BOXZEROBYTES()), ?P_BOXZEROBYTES),
137
138
139
140
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_secretbox_ZEROBYTES()), ?S_ZEROBYTES),
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_secretbox_BOXZEROBYTES()),
    	?S_BOXZEROBYTES),
    
141
142
143
144
    Verifiers = [
        {crypto_stream_KEYBYTES, ?CRYPTO_STREAM_KEYBYTES},
        {crypto_stream_NONCEBYTES, ?CRYPTO_STREAM_NONCEBYTES},
        {crypto_box_ZEROBYTES, ?CRYPTO_BOX_ZEROBYTES},
145
146
147
148
        {crypto_box_BOXZEROBYTES, ?CRYPTO_BOX_BOXZEROBYTES},
        {crypto_secretbox_ZEROBYTES, ?CRYPTO_SECRETBOX_ZEROBYTES},
        {crypto_secretbox_BOXZEROBYTES, ?CRYPTO_SECRETBOX_BOXZEROBYTES}
    ],
149
150
151
152
153
154
155
    run_verifiers(Verifiers).
    
run_verifiers([]) -> ok;
run_verifiers([{V, R} | Vs]) ->
    case enacl_nif:V() of
        R -> run_verifiers(Vs);
        Other -> {error, {verifier, V, {R, '/=', Other}}}
156
157
    end.

158
159
160
equals(X,X) -> true;
equals(X,Y) -> {X, '/=', Y}.

161
162
%% Low level helper functions
%% -----------------
163

164
%% @doc hash/1 hashes data into a cryptographically secure checksum.
165
%%
166
%% <p>Given an iodata(), `Data' of any size, run a cryptographically secure hash algorithm to
167
168
169
170
171
%% 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
172
  when Data :: iodata(),
173
174
       Checksum :: binary().

175
hash(Bin) ->
176
    case iolist_size(Bin) of
177
178
179
180
        K when K =< ?HASH_SIZE ->
            bump(enacl_nif:crypto_hash_b(Bin), ?HASH_REDUCTIONS, ?HASH_SIZE, K);
        _ ->
            enacl_nif:crypto_hash(Bin)
181
    end.
182

183
%% @doc verify_16/2 implements constant time 16-byte binary() verification
184
%%
185
186
187
188
189
190
%% <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>
191
%% <p>The functions take binary() values and not iolist() values since the latter would convert in non-constant time</p>
192
193
194
%% <p>Verification returns a boolean. `true' if the strings match, `false' otherwise.</p>
%% @end
-spec verify_16(binary(), binary()) -> boolean().
195
196
verify_16(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_16(X, Y);
verify_16(_, _) -> error(badarg).
197

198
%% @doc verify_32/2 implements constant time 32-byte iolist() verification
199
%%
200
%% This function works as {@link verify_16/2} but does so on 32 byte strings. Same caveats apply.
201
202
%% @end
-spec verify_32(binary(), binary()) -> boolean().
203
204
verify_32(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_32(X, Y);
verify_32(_, _) -> error(badarg).
205
206
207

%% Public Key Crypto
%% ---------------------
208
%% @doc box_keypair/0 creates a new Public/Secret keypair.
209
%%
210
211
%% 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.
212
%% @end.
213
-spec box_keypair() -> #{ atom() => binary() }.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
214
box_keypair() ->
215
216
	{PK, SK} = enacl_nif:crypto_box_keypair(),
	#{ public => PK, secret => SK}.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
217

218

219
%% @doc box/4 encrypts+authenticates a message to another party.
220
221
222
%%
%% 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.
223
224
%% @end
-spec box(Msg, Nonce, PK, SK) -> CipherText
225
  when Msg :: iodata(),
226
227
228
229
       Nonce :: binary(),
       PK :: binary(),
       SK :: binary(),
       CipherText :: binary().
230
box(Msg, Nonce, PK, SK) ->
231
    enacl_nif:crypto_box([?P_ZEROBYTES, Msg], Nonce, PK, SK).
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
232

233
%% @doc box_open/4 decrypts+verifies a message from another party.
234
235
236
%%
%% 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
237
%% message.
238
%% @end
239
-spec box_open(CipherText, Nonce, PK, SK) -> {ok, Msg} | {error, failed_verification}
240
  when CipherText :: iodata(),
241
242
243
244
       Nonce :: binary(),
       PK :: binary(),
       SK :: binary(),
       Msg :: binary().
245
box_open(CipherText, Nonce, PK, SK) ->
246
247
248
    case enacl_nif:crypto_box_open([?P_BOXZEROBYTES, CipherText], Nonce, PK, SK) of
        {error, Err} -> {error, Err};
        Bin when is_binary(Bin) -> {ok, Bin}
249
250
    end.

251
252
253
254
255
256
257
258
259
260
%% @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.
261

262
%% @doc box_afternm/3 works like `box/4' but uses a precomputed key
263
%%
264
265
266
267
268
269
270
271
272
273
274
275
276
%% 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 ->
277
            bump(enacl_nif:crypto_box_afternm_b([?P_ZEROBYTES, Msg], Nonce, Key),
278
279
            	?BOX_AFTERNM_REDUCTIONS, ?BOX_AFTERNM_SIZE, K);
        _ ->
280
            enacl_nif:crypto_box_afternm([?P_ZEROBYTES, Msg], Nonce, Key)
281
282
283
    end.

%% @doc box_open_afternm/3 works like `box_open/4` but uses a precomputed key
284
%%
285
286
287
288
289
290
291
292
293
294
295
296
297
298
%% 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 =
299
            case enacl_nif:crypto_box_open_afternm_b([?P_BOXZEROBYTES, CipherText], Nonce, Key) of
300
301
302
303
304
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end,
           bump(R, ?BOX_AFTERNM_REDUCTIONS, ?BOX_AFTERNM_SIZE, K);
        _ ->
305
            case enacl_nif:crypto_box_open_afternm([?P_BOXZEROBYTES, CipherText], Nonce, Key) of
306
307
308
309
310
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
            end
    end.

311
%% @doc box_nonce_size/0 return the byte-size of the nonce
312
%%
313
314
315
%% Used to obtain the size of the nonce.
%% @end.
-spec box_nonce_size() -> pos_integer().
316
317
318
box_nonce_size() ->
	enacl_nif:crypto_box_NONCEBYTES().

319
320
%% @private
-spec box_public_key_bytes() -> pos_integer().
321
322
box_public_key_bytes() ->
	enacl_nif:crypto_box_PUBLICKEYBYTES().
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
323

324
325
326
327
%% @private
box_beforenm_bytes() ->
	enacl_nif:crypto_box_BEFORENMBYTES().

328
329
%% Signatures

330
331
332
%% @private
sign_keypair_public_size() ->
    enacl_nif:crypto_sign_PUBLICKEYBYTES().
333

334
335
336
337
%% @private
sign_keypair_secret_size() ->
    enacl_nif:crypto_sign_SECRETKEYBYTES().

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

%% @doc sign/2 signs a message with a digital signature identified by a secret key.
348
%%
349
350
351
352
%% 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
353
    M :: iodata(),
354
355
    SK :: binary(),
    SM :: binary().
356
sign(M, SK) ->
357
    enacl_nif:crypto_sign(M, SK).
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
373
   case enacl_nif:crypto_sign_open(SM, PK) of
       M when is_binary(M) -> {ok, M};
       {error, Err} -> {error, Err}
374
    end.
375

376
377
378
379
380
381
382
383
384
%% @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().
385
sign_detached(M, SK) ->
386
    enacl_nif:crypto_sign_detached(M, SK).
387
388
389
390
391
392

%% @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'.
393
-spec sign_verify_detached(SIG, M, PK) -> {ok, M} | {error, failed_verification}
394
395
396
397
  when
    SIG :: binary(),
    M   :: iodata(),
    PK  :: binary().
398
sign_verify_detached(SIG, M, PK) ->
399
    case enacl_nif:crypto_sign_verify_detached(SIG, M, PK) of
400
        true -> {ok, M};
401
402
        false -> {error, failed_verification}
    end.
403

404
405
%% @private
-spec box_secret_key_bytes() -> pos_integer().
406
407
408
box_secret_key_bytes() ->
	enacl_nif:crypto_box_SECRETKEYBYTES().

409
410
411
412
413
414
%% @doc seal_box/2 encrypts an anonymous message to another party.
%%
%% Encrypt a `Msg' to a party using his public key, `PK'. This generates an ephemeral
%% keypair and then uses `box'. Ephemeral public key will sent to other party. Returns the 
%% enciphered message `SealedCipherText' which includes ephemeral public key at head.
%% @end
415
-spec box_seal(Msg, PK) -> SealedCipherText
416
417
418
  when Msg :: iodata(),
       PK :: binary(),
       SealedCipherText :: binary().
419
box_seal(Msg, PK) ->
420
    enacl_nif:crypto_box_seal(Msg, PK).
421
 
422
423
424
425
426
427
%% @doc seal_box_open/3 decrypts+check message integrity from an unknown sender.
%%
%% Decrypt a `SealedCipherText' which contains an ephemeral public key from another party
%% into a `Msg' using that key and your public and secret keys, `PK' and `SK'. Returns the
%% plaintext message.
%% @end
428
-spec box_seal_open(SealedCipherText, PK, SK) -> {ok, Msg} | {error, failed_verification}
429
430
431
432
  when SealedCipherText :: iodata(),
      PK :: binary(),
      SK :: binary(),
      Msg :: binary().
433
box_seal_open(SealedCipherText, PK, SK) ->
434
435
436
    case enacl_nif:crypto_box_seal_open(SealedCipherText, PK, SK) of
        {error, Err} -> {error, Err};
        Bin when is_binary(Bin) -> {ok, Bin}
437
    end.
438

439
%% @doc secretbox/3 encrypts a message with a key
440
%%
441
442
443
444
445
446
447
448
449
%% 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
450

451
452
453
secretbox(Msg, Nonce, Key) ->
    case iolist_size(Msg) of
        K when K =< ?SECRETBOX_SIZE ->
454
          bump(enacl_nif:crypto_secretbox_b([?S_ZEROBYTES, Msg], Nonce, Key),
455
456
457
458
               ?SECRETBOX_REDUCTIONS,
               ?SECRETBOX_SIZE,
               K);
        _ ->
459
          enacl_nif:crypto_secretbox([?S_ZEROBYTES, Msg], Nonce, Key)
460
    end.
461
%% @doc secretbox_open/3 opens a sealed box.
462
%%
463
464
465
466
467
468
469
470
471
472
473
474
%% 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 ->
475
          R = case enacl_nif:crypto_secretbox_open_b([?S_BOXZEROBYTES, CipherText],
476
477
478
479
480
481
                                                     Nonce, Key) of
                  {error, Err} -> {error, Err};
                  Bin when is_binary(Bin) -> {ok, Bin}
              end,
          bump(R, ?SECRETBOX_OPEN_REDUCTIONS, ?SECRETBOX_SIZE, K);
        _ ->
482
          case enacl_nif:crypto_secretbox_open([?S_BOXZEROBYTES, CipherText], Nonce, Key) of
483
484
485
486
              {error, Err} -> {error, Err};
              Bin when is_binary(Bin) -> {ok, Bin}
          end
   end.
487

488
489
490
491
%% @doc secretbox_nonce_size/0 returns the size of the secretbox nonce
%%
%% When encrypting with a secretbox, the nonce must have this size
%% @end
492
493
secretbox_nonce_size() ->
    enacl_nif:crypto_secretbox_NONCEBYTES().
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
494

495
496
497
498
%% @doc secretbox_key_size/0 returns the size of the secretbox key
%%
%% When encrypting with a secretbox, the key must have this size
%% @end
499
500
501
secretbox_key_size() ->
    enacl_nif:crypto_secretbox_KEYBYTES().

Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
502
503
504
%% @doc stream_nonce_size/0 returns the byte size of the nonce for streams
%% @end
-spec stream_nonce_size() -> pos_integer().
505
stream_nonce_size() -> ?CRYPTO_STREAM_NONCEBYTES.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
506
507
508
509

%% @doc stream_key_size/0 returns the byte size of the key for streams
%% @end
-spec stream_key_size() -> pos_integer().
510
stream_key_size() -> ?CRYPTO_STREAM_KEYBYTES.
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
511
512

%% @doc stream/3 produces a cryptographic stream suitable for secret-key encryption
513
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
514
515
516
517
518
519
520
521
522
523
524
525
%% <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().
526
527
528
529
530
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);
531
532
533
534
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
535
%% @doc stream_xor/3 encrypts a plaintext message into ciphertext
536
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
537
538
539
540
541
%% 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
542
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
543
544
545
    Nonce :: binary(),
    Key :: binary(),
    CipherText :: binary().
546
stream_xor(Msg, Nonce, Key) ->
547
548
549
550
551
552
553
554
555
    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
556
557
558
559
560
561

%% @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().

562
563
564
565
566
%% @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
567
%% @doc auth/2 produces an authenticator (MAC) for a message
568
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
569
570
571
572
573
%% 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
574
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
575
576
    Key :: binary(),
    Authenticator :: binary().
577
578
579
580
581
582
583
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
584
585

%% @doc auth_verify/3 verifies an authenticator for a message
586
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
587
588
589
590
591
592
%% 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(),
593
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
594
    Key :: binary().
595
596
597
598
599
600
601
602
603
604
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
605
606

%% @doc onetime_auth/2 produces a ONE-TIME authenticator for a message
607
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
608
%% This function works like {@link auth/2} except that the key must not be used again for subsequent messages. That is, the pair
609
%% `{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
610
611
612
%% @end
-spec onetime_auth(Msg, Key) -> Authenticator
  when
613
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
614
615
    Key :: binary(),
    Authenticator :: binary().
616
617
618
619
620
621
622
623
624
625
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
626
627

%% @doc onetime_auth_verify/3 verifies an ONE-TIME authenticator for a message
628
%%
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
629
%% Given an `Authenticator', a `Msg' and a `Key'; verify that the MAC for the pair `{Msg, Key}' is really `Authenticator'. Returns
630
%% 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
631
632
633
634
635
%% 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(),
636
    Msg :: iodata(),
Jesper Louis Andersen's avatar
Jesper Louis Andersen committed
637
    Key :: binary().
638
639
640
641
642
643
644
645
646
647
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
648

649
650
651
652
653
%% @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
654
655
656
657
658
%% @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().

659
660
661
662
663
664
665
666
%% 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).

667
668
669
670
671
672
673
%% @doc curve25519_scalarmult/1 avoids messing up arguments.
%% Takes as input a map `#{ secret := Secret, base_point := BasePoint }' in order to avoid
%% messing up the calling order.
%% @end
curve25519_scalarmult(#{ secret := Secret, base_point := BasePoint }) ->
    curve25519_scalarmult(Secret, BasePoint).

Alexander Færøy's avatar
Alexander Færøy committed
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
%% 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().

708
709
710
%% Obtaining random bytes

%% @doc randombytes/1 produces a stream of random bytes of the given size
711
%%
712
713
714
715
716
717
718
719
720
721
%% 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
722
-spec randombytes(non_neg_integer()) -> binary().
723
724
725
726
727
randombytes(N) when N =< ?RANDOMBYTES_SIZE ->
    bump(enacl_nif:randombytes_b(N), ?RANDOMBYTES_REDUCTIONS, ?RANDOMBYTES_SIZE, N);
randombytes(N) ->
    enacl_nif:randombytes(N).

728
%% Helpers
729

730
731
732
733
%% @doc bump/4 bumps a reduction budget linearly before returning the result
%% It is used for the on-scheduler variants of functions in order to make sure there
%% is a realistic apporach to handling the reduction counts of the system.
%% @end
734
bump(Res, Budget, Max, Sz) ->
735
736
    Reds =  (Budget * Sz) div Max,
    erlang:bump_reductions(max(1, Reds)),
737
    Res.