enacl.erl 26.3 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
%% Ed 25519.
-export([
	crypto_sign_ed25519_keypair/0,
	crypto_sign_ed25519_public_to_curve25519/1,
	crypto_sign_ed25519_secret_to_curve25519/1,
78
	crypto_sign_ed25519_sk_to_pk/1,
Alexander Færøy's avatar
Alexander Færøy committed
79 80 81 82
	crypto_sign_ed25519_public_size/0,
	crypto_sign_ed25519_secret_size/0
]).

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

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

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

99
%% Definitions of system budgets
100 101
%% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are
%% described in the README.md file.
102
-define(HASH_SIZE, 4 * 1024).
103
-define(HASH_REDUCTIONS, 17 * 2).
104
-define(BOX_BEFORENM_REDUCTIONS, 60).
105 106 107 108 109 110 111 112 113 114 115
-define(BOX_AFTERNM_SIZE, 8 * 1024).
-define(BOX_AFTERNM_REDUCTIONS, 17 * 2).
-define(SECRETBOX_SIZE, 8 * 1024).
-define(SECRETBOX_REDUCTIONS, 17 * 2).
-define(SECRETBOX_OPEN_REDUCTIONS, 17 * 2).
-define(STREAM_SIZE, 16 * 1024).
-define(STREAM_REDUCTIONS, 17 * 2).
-define(AUTH_SIZE, 4 * 1024).
-define(AUTH_REDUCTIONS, 17 * 2).
-define(ONETIME_AUTH_SIZE, 16 * 1024).
-define(ONETIME_AUTH_REDUCTIONS, 16 * 2).
116 117
-define(ED25519_PUBLIC_TO_CURVE_REDS, 20 * 2).
-define(ED25519_SECRET_TO_CURVE_REDS, 20 * 2).
118 119 120 121 122

%% 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).
123
-define(P_BOXZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>).  %% 16 bytes
124

125 126 127 128
-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
129 130 131 132 133 134 135
-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),
136 137 138 139
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_secretbox_ZEROBYTES()), ?S_ZEROBYTES),
    true = equals(binary:copy(<<0>>, enacl_nif:crypto_secretbox_BOXZEROBYTES()),
    	?S_BOXZEROBYTES),
    
140 141 142 143
    Verifiers = [
        {crypto_stream_KEYBYTES, ?CRYPTO_STREAM_KEYBYTES},
        {crypto_stream_NONCEBYTES, ?CRYPTO_STREAM_NONCEBYTES},
        {crypto_box_ZEROBYTES, ?CRYPTO_BOX_ZEROBYTES},
144 145 146 147
        {crypto_box_BOXZEROBYTES, ?CRYPTO_BOX_BOXZEROBYTES},
        {crypto_secretbox_ZEROBYTES, ?CRYPTO_SECRETBOX_ZEROBYTES},
        {crypto_secretbox_BOXZEROBYTES, ?CRYPTO_SECRETBOX_BOXZEROBYTES}
    ],
148 149 150 151 152 153 154
    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}}}
155 156
    end.

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

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

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

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

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

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

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

217

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

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

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

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

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

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

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

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

327 328
%% Signatures

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

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

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

%% @doc sign/2 signs a message with a digital signature identified by a secret key.
347
%%
348 349 350 351
%% 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
352
    M :: iodata(),
353 354
    SK :: binary(),
    SM :: binary().
355
sign(M, SK) ->
356
    enacl_nif:crypto_sign(M, SK).
357 358

%% @doc sign_open/2 opens a digital signature
359
%%
360 361 362
%% 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.
363 364 365
%% @end
-spec sign_open(SM, PK) -> {ok, M} | {error, failed_verification}
  when
366
    SM :: iodata(),
367 368
    PK :: binary(),
    M :: binary().
369
sign_open(SM, PK) ->
370 371 372
   case enacl_nif:crypto_sign_open(SM, PK) of
       M when is_binary(M) -> {ok, M};
       {error, Err} -> {error, Err}
373
    end.
374

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

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

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

408 409 410 411 412 413
%% @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
414
-spec box_seal(Msg, PK) -> SealedCipherText
415 416 417
  when Msg :: iodata(),
       PK :: binary(),
       SealedCipherText :: binary().
418
box_seal(Msg, PK) ->
419
    enacl_nif:crypto_box_seal(Msg, PK).
420
 
421 422 423 424 425 426
%% @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
427
-spec box_seal_open(SealedCipherText, PK, SK) -> {ok, Msg} | {error, failed_verification}
428 429 430 431
  when SealedCipherText :: iodata(),
      PK :: binary(),
      SK :: binary(),
      Msg :: binary().
432
box_seal_open(SealedCipherText, PK, SK) ->
433 434 435
    case enacl_nif:crypto_box_seal_open(SealedCipherText, PK, SK) of
        {error, Err} -> {error, Err};
        Bin when is_binary(Bin) -> {ok, Bin}
436
    end.
437

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

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

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

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

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

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

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

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

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

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

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

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

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

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

666 667 668 669 670 671 672
%% @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
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
%% 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) ->
690 691 692
	R = enacl_nif:crypto_sign_ed25519_public_to_curve25519(PublicKey),
	erlang:bump_reductions(?ED25519_PUBLIC_TO_CURVE_REDS),
	R.
Alexander Færøy's avatar
Alexander Færøy committed
693 694 695 696 697 698

%% @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) ->
699 700 701
	R = enacl_nif:crypto_sign_ed25519_secret_to_curve25519(SecretKey),
	erlang:bump_reductions(?ED25519_SECRET_TO_CURVE_REDS),
	R.
Alexander Færøy's avatar
Alexander Færøy committed
702

703 704 705 706 707 708 709
%% @doc crypto_sign_ed25519_sk_to_pk/1 computes a given Ed 25519 public key
%% from a secret key.
%% @end
-spec crypto_sign_ed25519_sk_to_pk(SecretKey :: binary()) -> binary().
crypto_sign_ed25519_sk_to_pk(SecretKey) ->
	enacl_nif:crypto_sign_ed25519_sk_to_pk(SecretKey).

Alexander Færøy's avatar
Alexander Færøy committed
710 711 712 713 714 715 716 717
-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().

718 719 720
%% Obtaining random bytes

%% @doc randombytes/1 produces a stream of random bytes of the given size
721
%%
722 723 724 725 726 727 728 729 730 731
%% 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
732
-spec randombytes(non_neg_integer()) -> binary().
733 734 735
randombytes(N) ->
    enacl_nif:randombytes(N).

736
%% Helpers
737

738 739 740 741
%% @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
742
bump(Res, Budget, Max, Sz) ->
743 744
    Reds =  (Budget * Sz) div Max,
    erlang:bump_reductions(max(1, Reds)),
745
    Res.