Compare commits

...

191 Commits

Author SHA1 Message Date
Hans Svensson
4eb7ec7008
Fix C-warnings (#10)
* .envrc is not for git

* Fix c code - avoid warnings

* Bump Erlang versions in Github workflows
2024-03-19 13:23:23 +01:00
Hans Svensson
a3d010ba62
Merge pull request #9 from aeternity/secretbox_easy_only
Add access to secretbox_easy/easy_open functions
2022-08-19 13:49:51 +02:00
Hans Svensson
fa94eaf6f6 Add access to secretbox_easy/easy_open functions
They are just a simplification of the secretbox API, thus it does
not provide any new functionality. But it helps mapping function
names to libsodium documentation.
2022-08-19 13:23:29 +02:00
seanhinde
67fceef42c
Merge pull request #8 from aeternity/mac-m1-support
on Darwin allow platform to decide arch
2021-11-19 12:15:07 +01:00
Sean Hinde
80e24670d9 on Darwin allow platform to decide arch 2021-11-16 15:08:23 +01:00
Hans Svensson
793ddb502f
Merge pull request #6 from aeternity/merge_upstream
Merge upstream
2021-10-08 10:49:36 +02:00
Hans Svensson
db9338e3d4 Merge remote-tracking branch 'upstream/master' into merge_upstream 2021-10-01 11:24:51 +02:00
Jesper Louis Andersen
46e2754a50 Disable macos again.
setup-beam only has ubuntu support...
2021-07-08 11:51:56 +02:00
Jesper Louis Andersen
ddc5d1269d Let us get macos into the build matrix 2021-07-08 11:50:01 +02:00
Jesper Louis Andersen
b229e9054b Document 1.2.1 2021-07-08 11:45:38 +02:00
Jesper Louis Andersen
c0afa5890d v1.2.1 2021-07-08 11:42:18 +02:00
Jesper Louis Andersen
20b230d693 Export types from enacl
A couple of types are useful from outside the enacl module. Export these.
2021-07-06 13:45:08 +02:00
Jesper Louis Andersen
47ff11e956 Quick run over documentation 2021-06-22 14:03:50 +02:00
Jesper Louis Andersen
ec64b0de73 Split up configuration 2021-06-19 12:40:53 +02:00
Jesper Louis Andersen
87f9270a6c Move actions to their own file. 2021-06-19 12:33:43 +02:00
Jesper Louis Andersen
756c222877 Reorder build a bit 2021-06-19 12:26:52 +02:00
Jesper Louis Andersen
a271797641 Update documentation. 2021-06-19 00:23:32 +02:00
Jesper Louis Andersen
458c4ca9bc Strengthen even more 2021-06-19 00:17:19 +02:00
Jesper Louis Andersen
6242282bfd cue fmt 2021-06-19 00:09:29 +02:00
Jesper Louis Andersen
d801018f23 Strengthen Cue a bit 2021-06-19 00:08:27 +02:00
Jesper Louis Andersen
bb1334d82f
Merge pull request #58 from paulo-ferraz-oliveira/feature/setup-beam
Allow for more flexibility in rebar3 version
2021-06-18 23:57:14 +02:00
Jesper Louis Andersen
9331ef974e
Sudo the libsodium installation too 2021-06-18 23:56:11 +02:00
Jesper Louis Andersen
129f5e2acf
Sudo apt-get update
This verifies we are in a proper image where we need to sudo in updates, etc.
2021-06-18 23:53:34 +02:00
Jesper Louis Andersen
36cab6aedb
Update ci.yaml
Hack in to push it forward
2021-06-18 23:51:10 +02:00
Paulo Oliveira
b81fa6f0d6 Allow for more flexibility in rebar3 version 2021-06-18 18:35:19 +01:00
Jesper Louis Andersen
e748552809 More CUE 2021-06-18 17:02:26 +02:00
Jesper Louis Andersen
f301929d75 Formatting 2021-06-18 14:33:49 +02:00
Jesper Louis Andersen
529d8f6033 Use types 2021-06-18 14:32:47 +02:00
Jesper Louis Andersen
8b8fe9fa98 More updates and learning. 2021-06-15 15:12:39 +02:00
Jesper Louis Andersen
8ac26c8161 Cleanup. 2021-06-15 15:10:13 +02:00
Jesper Louis Andersen
f8bd7f3565 Older version check. 2021-06-15 15:03:47 +02:00
Jesper Louis Andersen
61b83710b5 Test 22.3. 2021-06-15 15:02:21 +02:00
Jesper Louis Andersen
6cc2529023 Move more into base. 2021-06-15 15:00:59 +02:00
Jesper Louis Andersen
fe33927fb3 Only run on 24.0 for now. 2021-06-15 15:00:22 +02:00
Jesper Louis Andersen
b7034392bd Enable on all images. 2021-06-15 14:55:52 +02:00
Jesper Louis Andersen
c6f4e21c9a Actually do test. 2021-06-15 14:55:17 +02:00
Jesper Louis Andersen
e41634b75c Update apt-get database. 2021-06-15 14:53:42 +02:00
Jesper Louis Andersen
f879ec00a7 Image doesnt use libsodium. 2021-06-15 14:49:32 +02:00
Jesper Louis Andersen
ba69139283 New try. 2021-06-15 14:45:21 +02:00
Jesper Louis Andersen
ef049c921f Lets try sudo again, shall we? 2021-06-15 14:41:10 +02:00
Jesper Louis Andersen
aca072630e Need libsodium-dev and 23. 2021-06-15 14:38:34 +02:00
Jesper Louis Andersen
5f22892ce4 More QoL interaction. 2021-06-15 14:36:55 +02:00
Jesper Louis Andersen
e59656ebf6 fix sequence to dict. 2021-06-15 14:35:37 +02:00
Jesper Louis Andersen
f99c8643f0 Type correction. 2021-06-15 14:34:31 +02:00
Jesper Louis Andersen
3a4d000c56 Start utilizing cue tooling. 2021-06-15 14:32:40 +02:00
Jesper Louis Andersen
73a6462ef3 Fix apt-get install command, try without sudo. 2021-06-15 14:29:32 +02:00
Jesper Louis Andersen
0b8abb95d5 Actions. 2021-06-15 14:24:45 +02:00
Jesper Louis Andersen
3d9cc841eb v1.2.0 2021-06-15 13:29:58 +02:00
Jesper Louis Andersen
ea72835b50 Bump changelog 2021-06-15 13:10:51 +02:00
Jesper Louis Andersen
d6bd999c82 sign_verify_detached: guard against size
The code didn't properly do a size check on a detached signature. Now it
does.

While here, fix a problem with EQC tests, for the same piece of code.
2021-06-15 13:05:48 +02:00
Jesper Louis Andersen
0855ce2f55 Small documentation fixups 2021-06-15 13:03:30 +02:00
Jesper Louis Andersen
7f06675533 Add a CT for verify_detached 2021-06-15 13:02:06 +02:00
Jesper Louis Andersen
87282dc4f8 Fix signatures for final-verify 2021-06-14 17:17:19 +02:00
Jesper Louis Andersen
1bb0d59c7f Lorri direnv 2021-06-14 16:17:28 +02:00
Jesper Louis Andersen
442094df0d Use lorri for development 2021-06-14 16:17:19 +02:00
Hans Svensson
a45b433f88
Merge pull request #5 from aeternity/hs-fix_restart_issue
Fix NIF-load issue on init:restart
2021-01-07 11:21:15 +01:00
Bryan Paxton
868a14c25d Ensure we never return 1 from sodium_init() onload
sodium_init() will return 0 on success, -1 on failure, and 1 if sodium is
already loaded and initialized (which is not an error). In the case
where libsodium is already initialized and the system is restarted we
may return 1 from onload nif function resulting in a crash.

- change the call to sodium_init() to check for an error return (-1) and
  return -1 explicitly in this case, otherwise always return zero at the
  end of our onload function.
2021-01-06 13:08:32 +01:00
Jesper Louis Andersen
9919871e53 Update changelog 2020-08-29 18:23:34 +02:00
Jesper Louis Andersen
9bdb1ccf1b v1.1.1 2020-08-29 18:22:38 +02:00
Jesper Louis Andersen
57ad262ec8 More Markdownlint nitpicking 2020-08-27 14:24:01 +02:00
Jesper Louis Andersen
44f2220532 Markdownlint nitpicking 2020-08-27 14:19:50 +02:00
Jesper Louis Andersen
6ca6b0b22e Say hello to Erlang/OTP v23 2020-08-27 14:08:00 +02:00
Jesper Louis Andersen
d67e047859 Merge branch 'master' of github.com:jlouis/enacl into master 2020-08-27 14:06:41 +02:00
Jesper Louis Andersen
cbb06fc598
Merge pull request #51 from starbelly/fixup-enacl-nif-return
Ensure we never return 1 from sodium_init() onload
2020-08-27 14:06:07 +02:00
Bryan Paxton
0351de9882 add upgrade and unload handlers 2020-07-28 18:30:59 -05:00
Bryan Paxton
e18f9b7337 Ensure we never return 1 from sodium_init() onload
sodium_init() will return 0 on success, -1 on failure, and 1 if sodium is
already loaded and initialized (which is not an error). In the case
where libsodium is already initialized and the system is restarted we
may return 1 from onload nif function resulting in a crash.

- change the call to sodium_init() to check for an error return (-1) and
  return -1 explicitly in this case, otherwise always return zero at the
  end of our onload function.
2020-07-26 15:09:53 -05:00
Jesper Louis Andersen
b2c70ef6a3 v1.1.0 2020-06-09 13:37:05 +02:00
Jesper Louis Andersen
025b83a14b Prepare 1.1.0. 2020-06-09 13:35:43 +02:00
Jesper Louis Andersen
4b4ec373b1 Test pwhash in EQC. 2020-06-09 13:34:03 +02:00
Jesper Louis Andersen
7f7c667b28 Update the README a bit
The world-order is new, so update the README.
to reflect reality a bit more.
2020-06-09 12:27:47 +02:00
Jesper Louis Andersen
90be3aa2dd Use GCC 9.3.0 from nix 2020-06-09 12:17:23 +02:00
Jesper Louis Andersen
23bd40a4b3 Netpick the include path order 2020-06-09 12:16:59 +02:00
Jesper Louis Andersen
42fd03cde0 Update CONTRIBUTORS, CHANGELOG 2020-06-09 12:14:39 +02:00
Jesper Louis Andersen
9258d8b6ad Merge remote-tracking branch 'kuon/patch-2' 2020-06-09 12:11:13 +02:00
Jesper Louis Andersen
5ea33643da Merge remote-tracking branch 'kuon/patch-1' 2020-06-09 12:08:21 +02:00
Jesper Louis Andersen
a45d3863e0
Merge pull request #48 from kuon/patch-0
Add pwhash_SALTBYTES/0
2020-06-09 11:56:18 +02:00
Jesper Louis Andersen
82cd5d0361
Merge pull request #45 from starbelly:patch-1
Move rebar3_hex into project_plugins
2020-06-09 11:54:18 +02:00
Nicolas goy
4775270d76 Basic KDF functions 2020-04-19 19:07:23 +02:00
Nicolas goy
00f895b488 Allow specifying algorithm for pwhash 2020-04-17 14:31:35 +02:00
Nicolas goy
a001404877 Add pwhash_SALTBYTES/0 2020-04-17 13:52:33 +02:00
Bryan Paxton
812f05adcf
Move rebar3_hex into project_plugins
This change will prevent users from having to download rebar3_hex and all of it's dependencies.
2020-03-25 23:07:55 -05:00
Jesper Louis Andersen
5f95ee314f Implement EQC for secretstream 2020-03-07 15:10:58 +01:00
Jesper Louis Andersen
bde03dc557 Fix a dialyzer warning 2020-03-07 14:21:52 +01:00
Jesper Louis Andersen
061c3dfd65 Mention we have unit tests for secretstream 2020-03-07 12:26:20 +01:00
Jesper Louis Andersen
ec3af40ef8 Simple secretstream CT test case 2020-03-07 12:24:31 +01:00
Jesper Louis Andersen
8361450745 Format; release resources
In the push path, release resources
in a stack fashion. This avoids releasing
a binary incorrectly.
2020-03-07 12:01:27 +01:00
Jesper Louis Andersen
67fe9c7863 Track we have added secretstream support 2020-03-07 11:33:11 +01:00
Jesper Louis Andersen
55b3670fe7
Merge pull request #44 from spscream/master
Add crypto_secretstream_* functions.
2020-03-07 11:31:30 +01:00
Alexander Malaev
e32c923822 Add crypto_secretstream_* functions. 2020-03-02 10:28:45 +03:00
Jesper Louis Andersen
220ac6640a Fixup edoc compilation 2020-02-10 14:24:05 +01:00
Jesper Louis Andersen
218a6db09c More documentation. 2020-02-10 14:23:28 +01:00
Jesper Louis Andersen
2045ca8e09 Slightly better wording in documentation 2020-02-10 14:21:11 +01:00
Jesper Louis Andersen
8c13fc682e v1.0.0 2020-02-08 11:39:51 +01:00
Jesper Louis Andersen
24859776e4 Ready publishing of 1.0.0 2020-02-08 11:39:43 +01:00
Jesper Louis Andersen
1f7d553f75 Delete this sentence. It serves no purpose. 2020-02-06 16:18:25 +01:00
Jesper Louis Andersen
8e628a61fc Clean todo list 2020-02-06 16:06:21 +01:00
Jesper Louis Andersen
a3f112607c Document the notion of finalization 2020-02-06 16:06:02 +01:00
Jesper Louis Andersen
96b883ceba generichash finalization
Make sure we finalize properly in
generichash and check the alive
state of objects. If they are not
alive, return the general finalized
error.
2020-02-06 16:04:23 +01:00
Jesper Louis Andersen
d013a04a58 Manage the changelog. 2020-02-06 13:59:31 +01:00
Jesper Louis Andersen
fd87b9da39 Fix a bug in sign_init/0
The code path was wrong in a lot
of cases in sign_init/0 so even if it
succeeded it would return a failure.

Fixed by cleaning up the code.
2020-02-06 13:57:49 +01:00
Jesper Louis Andersen
cceef4530a Streamline naming
More changes before 1.0 with a
more direct naming scheme.
2020-02-06 13:57:07 +01:00
Jesper Louis Andersen
014d50cf47 Implement EQC for generic hashing, fix bug.
Turns out the interval we had in the
file were inverted and I was wrong
in an earlier commit. However, EQC
dutifully found the mistake, and it
is now corrected.
2020-02-06 12:18:47 +01:00
Jesper Louis Andersen
f580f6525b Streamline _open style calls
Those now return {ok, Msg} or
{error, term()} so you are kind of
forced to match on them. This is
likely to help with correctnes.
2020-02-06 11:48:57 +01:00
Jesper Louis Andersen
7999d08e9d Streamlining of secret and _verify
The secret key API is now streamlined.

Also, all verify-type functions are
now returning boolean() values.
This makes the API consistent.
2020-02-06 11:12:32 +01:00
Jesper Louis Andersen
1cb2c3a2a2 Extend pwhashing with limits
In the EQC tests, we generate limits at random and verify things work.
2020-02-05 13:41:19 +01:00
Jesper Louis Andersen
dea9ce62ed Rename constant to be in line with libsodium 2020-02-05 13:34:27 +01:00
Jesper Louis Andersen
41045fed85 Partially stream kx
Also while here, implement some EQC tests for it.
2020-02-05 13:16:35 +01:00
Jesper Louis Andersen
5d245797d2 Parallelize the ext tests 2020-02-05 13:15:54 +01:00
Jesper Louis Andersen
c26aeee413 Use an exit condition 2020-02-05 12:10:02 +01:00
Jesper Louis Andersen
78621356ec Split extension functions away 2020-02-05 12:08:28 +01:00
Jesper Louis Andersen
d06fff489d QuickCheck for randombytes
There are some new randombytes
functions. Implement these as EQC
properties.
2020-02-05 11:16:56 +01:00
Jesper Louis Andersen
c7720e6ab8 Streamline the AEAD API 2020-02-05 10:56:18 +01:00
Jesper Louis Andersen
b637ba307b Streamline generichash and pwhash 2020-02-04 17:50:56 +01:00
Jesper Louis Andersen
59b94439d1 Decide on an even better API 2020-02-04 14:00:02 +01:00
Jesper Louis Andersen
aa2c69529a Streamlines generichashThe multi-part hash API is nowreflecting the same crypto modulefunctions in style. This is easierto use for people, I believe. 2020-02-04 13:00:16 +01:00
Jesper Louis Andersen
71832cce4c Streamline sealed boxes 2020-02-04 12:44:47 +01:00
Jesper Louis Andersen
c791f602e9 Streamline returns in the public key API 2020-02-04 12:38:02 +01:00
Jesper Louis Andersen
2041cec2e8 Update the eqc suite.
Parameter order in
chacha20poly1305_ietf changed.

Fix this in the EQC tests.

While here, also do the Nonce
changes.
2020-02-03 14:58:52 +01:00
Jesper Louis Andersen
8ed8663dfe Correct ietf_decrypt
EQC Found a bug where parameters
where incorrectly passed. The CT
test suite passed, but randomized
tests found an error.
2020-02-03 14:57:42 +01:00
Jesper Louis Andersen
fc943a19c7 Go through the secret API as well 2020-01-24 22:17:24 +01:00
Jesper Louis Andersen
2b8b6224d8 Plug some memory leaks in the public API.
The problem is, like the other recent
patches, about properly releasing
binaries we have allocated but not
given to the VM for it to use.
2020-01-24 22:14:23 +01:00
Jesper Louis Andersen
4939f7bb23 Protect the signature ctx with a mutex
This is the same game as with the
generichash construction. We want
to protect it with a mutex so
different processes can safely do
work on the same resource.

While here, also move the _update
function onto the dirty scheduler.
It is by far the most expensive
operation, and why it wasn't there
in the first place is odd. This should
unblock the scheduler on long
sign-checks. It also move the
possible mutex block onto the
dirty scheduler thread, away from
the core schedulers, improving
latency in the system as a result.
2020-01-24 15:18:04 +01:00
Jesper Louis Andersen
7d8fdf69c0 Protect generichash by a mutex
While sodium is thread-safe, our
resources are not. Furthermore,
we might have an update call going
when someone decides to call
finalize and so on. It is not clever
to do so, but on the other hand
I want to protect against this.

While here, mark the mutexed
calls as dirty CPU. This avoids them
blocking the main scheduler and
only messes with the background
dirty threads, which is somewhat
more safe.

The consequence is that order
access to the resource is now
serialized. I don't think you should
do it, but it is now possible.
2020-01-24 14:48:21 +01:00
Jesper Louis Andersen
e4b35a7035 Flesh out changelog some more
This is a sort-of TODO list at the top of the list, but we use it to keep
track of what we need to do.
2020-01-22 22:23:23 +01:00
Jesper Louis Andersen
49a437347e Improve release naming
Make it obvious you are releasing both tx and rx.
2020-01-22 22:22:53 +01:00
Jesper Louis Andersen
018bf0f6fc Plug a large set of memory leaks in signing
If you fail, there are cases where binaries are not properly released.
This patch fixes them all in signing.
2020-01-22 22:22:29 +01:00
Jesper Louis Andersen
e67619a403 Update the naming scheme of AEAD xchacha20...
Since this AEAD construction variant is an IETF variant, reflect
this in the names of the functions.

This streamlines the API with the libsodium API.
2020-01-22 19:41:58 +01:00
Jesper Louis Andersen
7f857115bb Add aead IETF constructions
Since the chacha20poly1305 constructions were the IETF variants,
we renamed those so they follow the official library better. While
here, we also fixed the argument order of the files.
2020-01-21 14:16:24 +01:00
Jesper Louis Andersen
bdb4719f6d Fix AEAD parameter order / naming.
The order of parameters were in the wrong order. Make them equal
to the official order of libsodium.

While here, rename NONCEBYTES to NPUBBYTES so it reflects the
underlying names as well.
2020-01-21 13:57:39 +01:00
Jesper Louis Andersen
ab40d5bbf8 Rename fixups 2020-01-21 13:56:17 +01:00
Jesper Louis Andersen
92b91bd806 Rename "nacl_error_tuple" -> "enacl_error_tuple"
The new name is consistent where the old name was not.
2020-01-21 13:40:35 +01:00
Jesper Louis Andersen
fec24995d1 Clean up aead construction, plug mem-leak 2020-01-21 13:39:08 +01:00
Jesper Louis Andersen
899fbeefd3 Plug memory leaks in kx_ functions
If we, for some reason, fail to the error-path, then binaries allocated
are not being released properly back to the erlang runtime. Fix this
in the usual fashion by using a stack of undo-operations, and thread
them via goto.
2020-01-21 13:01:48 +01:00
Jesper Louis Andersen
d850b16d1b Fix multi-part signatures
Remove the signstate wrapper as it is not needed anyore.
2020-01-20 15:52:38 +01:00
Jesper Louis Andersen
a5e66ff204 Reap a #define 2020-01-20 15:38:42 +01:00
Jesper Louis Andersen
bf6fb6cf7b Split the remaining operations 2020-01-20 15:31:44 +01:00
Jesper Louis Andersen
fe478ea253 Header file fixupUse <erl_nif.h> since it is a system header.Also rearrange headers to be consistent. 2020-01-20 14:57:42 +01:00
Jesper Louis Andersen
460c5bddfd Rudimentary test of pwhash 2020-01-20 14:45:52 +01:00
Jesper Louis Andersen
d3c033c4e6 Split off password hashing 2020-01-20 14:38:20 +01:00
Jesper Louis Andersen
fddbefeabd Simple AEAD unit tests 2020-01-20 14:38:09 +01:00
Jesper Louis Andersen
2ea36a7352 Start an "Upcoming changes" list
We want to fix a number of problems in the library. So we write down
what we are going to do in order to make it clearer to people.
2020-01-20 14:37:47 +01:00
Jesper Louis Andersen
0427fa42ee Rename enif_crypto_ to enacl_crypto_
This is a better name which spits stuff appropriately.

We don't pollute the enif_ namespace.
2020-01-19 17:56:31 +01:00
Jesper Louis Andersen
f5b8a8eb3b Pull signing out to its own module 2020-01-19 17:38:42 +01:00
Jesper Louis Andersen
4eaef57a76 Rename AEAD routines from enif_* to enacl_* 2020-01-19 13:32:15 +01:00
Jesper Louis Andersen
3ee5a94caf Split off AEAD functions to a separate file 2020-01-19 13:29:32 +01:00
Jesper Louis Andersen
0047af286f Provide a test suite for Generichash 2020-01-19 12:08:17 +01:00
Jesper Louis Andersen
61345d0b6e Fix argument handling in generichash_final
If supplying 1 argument, it is in argv[0], not argv[1]
2020-01-19 12:08:05 +01:00
Jesper Louis Andersen
0f39bae64c Fix name of C function
The name of the generichash function was wrong, so it was not possible to find it when
loading the NIF.
2020-01-19 12:07:18 +01:00
Jesper Louis Andersen
d7e83dd569 Track outlen inside the generichash wrapper 2020-01-17 16:24:51 +01:00
Jesper Louis Andersen
df1b134f73 Track liveness stateReject updates to finalized generichash states. 2020-01-17 16:07:01 +01:00
Jesper Louis Andersen
f5918c0156 Fix compilation 2020-01-17 16:03:30 +01:00
Jesper Louis Andersen
463cae05d5 Bump for first additions 2020-01-17 16:03:16 +01:00
Jesper Louis Andersen
6e057cbd48 The sodium MIN/MAX values are incusive 2020-01-17 15:47:51 +01:00
Jesper Louis Andersen
d5bb24e671 Start splitting the library into its parts 2020-01-17 15:46:38 +01:00
Jesper Louis Andersen
a25b9a2684 Bump CHANGELOG 2020-01-16 15:55:59 +01:00
Jesper Louis Andersen
b7533d3b9c Release resources under failure
sign and generichash failed to release their resources under failure.

This can lead to subtle memory leaks in the very unlikely event
we can't initialize.
2020-01-16 15:45:42 +01:00
Jesper Louis Andersen
f43a730758 Merge branch 'multi-part-signatures' of github.com:hazy/enacl 2020-01-16 15:38:48 +01:00
Jesper Louis Andersen
0cfa88be32 Update changelog 2020-01-16 15:22:43 +01:00
Jesper Louis Andersen
3f284be0cb Merge branch 'sign-seed-keypair' of github.com:termoose/enacl 2020-01-16 15:21:50 +01:00
Jesper Louis Andersen
03bf3b30a1 Update changelog 2020-01-16 13:48:35 +01:00
Jesper Louis Andersen
6032b5839d Provide documentation 2020-01-16 13:47:41 +01:00
Jesper Louis Andersen
e6cb85fb24 Merge branch 'master' of github.com:syfgkjasdkn/enacl 2020-01-16 13:45:31 +01:00
Jesper Louis Andersen
288d51ace7 Bump changelog 2020-01-16 13:42:19 +01:00
Jesper Louis Andersen
25d411aa7d Merge branch 'fix-constant-and-more-tests' of github.com:aeternity/enacl 2020-01-16 13:27:58 +01:00
Jesper Louis Andersen
7f8e0a0e07 Merge branch 'xchacha20' of github.com:ECrownofFire/enacl 2020-01-16 13:15:54 +01:00
Jesper Louis Andersen
aaa5827613 Maintain CHANGELOG a bit 2020-01-15 16:17:44 +01:00
Jesper Louis Andersen
bb703d0c35 Bump CONTRIBUTORS 2020-01-15 16:17:00 +01:00
Jesper Louis Andersen
600020620b Merge branch 'master' of github.com:ECrownofFire/enacl 2020-01-15 16:11:30 +01:00
Jesper Louis Andersen
97ee4bbdcf Use randombytes_uint32
Better name. Says what you are getting.
2020-01-15 14:05:25 +01:00
Jesper Louis Andersen
3c8d54d87b Merge branch 'master' of github.com:jlouis/enacl 2020-01-15 14:01:32 +01:00
Jesper Louis Andersen
f9d6034e84 Implement missing random functions* enacl:randombytes_int32/0* enacl:randombytes_uniform/1 2020-01-15 13:56:00 +01:00
Jesper Louis Andersen
bc1af327e5 Bump .gitignore 2020-01-15 13:23:08 +01:00
Jesper Louis Andersen
6a30dc2825 Dump in some vscode helpers/settings 2020-01-15 13:23:01 +01:00
Jesper Louis Andersen
e66855c029 Use LLVM style C-formattting 2020-01-15 13:21:51 +01:00
Jesper Louis Andersen
745ff9ff75
Merge pull request #40 from tolbrino/tb-rebar3-win32
Add win32 support
2020-01-14 13:21:09 +01:00
Jesper Louis Andersen
885bc16374 Drop in a nix shell for easier handling. 2020-01-14 13:08:56 +01:00
Garry Hill
279c2c32c8
Add support for multi-part signatures 2019-11-20 12:11:21 +00:00
Ole Andre Birkedal
6f4a0c2521 Added bindings for crypto_sign_seed_keypair in libsodium 2019-06-15 14:29:15 +02:00
Tino Breddin
26180f42c0 Add win32 support
Replace Make-based compilation of the nif to using rebar's port
compiler.
2018-11-29 11:29:40 +01:00
ECrownofFire
2b183e1974
Add support for aead_xchacha20poly1305 2018-11-25 11:30:34 -05:00
alsdiufgoaiwuegflweuvflasjkdhvlajhsdfg666272727asfgfdsagdlsafg
3442655c5b add crypto_sign_ed25519_sk_to_pk 2018-11-22 13:04:24 +00:00
Jesper Louis Andersen
885662c069
Merge pull request #36 from aeternity/generichash_segfault
Generic hash state needs to be 64-byte aligned
2018-11-08 11:36:38 +01:00
Hans Svensson
1121321573 Generic hash state needs to be 64-byte aligned
At least according to:
  https://libsodium.gitbook.io/doc/hashing/generic_hashing

We noticed crashes when it was not 16-byte aligned - probably is
architecture dependent. This makes the safe choice and always 64-byte
align it.
2018-11-08 10:44:02 +01:00
ECrownofFire
4afa6fc093
Add checks for ops/mem limit sizes 2018-10-27 23:25:23 -04:00
ECrownofFire
26f4a40eb4
Mark pwhash functions as CPU bound 2018-10-27 23:25:16 -04:00
ECrownofFire
07bcd87294
Add choice of ops and mem limits to pwhash 2018-10-27 23:23:16 -04:00
ECrownofFire
d779071285
Add choice of ops and mem limits to pwhash_str
It natively checks atoms, which is kinda messy, but it avoids having to
export the libsodium pwhash constants, which is nice.
2018-10-27 23:22:55 -04:00
Thomas Arts
b3bbb2a910 Add tests for scalarmult
There appeared to be no tests for this function. The typical property for it is that scalarmultiplication is commutitative.
2018-06-13 07:04:01 +02:00
Thomas Arts
40fde1807b Variable is assigned but never used
This is just a warning, but elliminating warnings makes the code go cleanly through clang static code analyzer.
2018-06-13 07:03:04 +02:00
Thomas Arts
04b8fa3ecb Dangerous use of constant 2018-06-12 14:26:14 +02:00
Jesper Louis Andersen
f650c72b02 version bump 2018-05-21 17:52:25 +02:00
49 changed files with 5266 additions and 2128 deletions

3
.github/workflows/Makefile vendored Normal file
View File

@ -0,0 +1,3 @@
all:
cue export --out yaml > ci.yaml

37
.github/workflows/actions.cue vendored Normal file
View File

@ -0,0 +1,37 @@
package actions
#Name: string
#Branches: branches: [...string]
#Tags: tags: [...string]
#On: {
push?: #Branches
pull_request?: #Branches
page_build?: #Branches
}
#Action: "actions/checkout@v2" | "erlef/setup-beam@v1"
#Uses: {
uses: #Action
with?: {
...
}
}
#Run: {
name: string
run: string
}
#Steps: #Uses | #Run
#OS_Version: *"ubuntu-latest" | "macos-latest" | "windows_latest"
#Jobs: ci: {
name: string
"runs-on": string
strategy:
matrix: {
otp_vsn: [...string]
os: [...#OS_Version]
}
steps: [...#Steps]
}

34
.github/workflows/ci.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
name: build
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
ci:
name: Run checks and tests over ${{matrix.otp_vsn}} and ${{matrix.os}}
runs-on: ${{matrix.os}}
strategy:
matrix:
otp_vsn:
- "24.3"
- "25.3"
- "26.2"
os:
- ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp_vsn}}
rebar3-version: 3.16.1
- name: Update apt-get database
run: sudo apt-get update
- name: Install libsodium
run: sudo apt-get install -y libsodium-dev
- name: Compile source code
run: make compile
- name: Run the tests
run: make tests

21
.github/workflows/setup.cue vendored Normal file
View File

@ -0,0 +1,21 @@
package actions
name: #Name & "build"
on: #On & {
push: branches: [
_branch,
]
pull_request: branches: [
_branch,
]
}
jobs: #Jobs
jobs: ci: {
name: "Run checks and tests over ${{matrix.otp_vsn}} and ${{matrix.os}}"
"runs-on": "${{matrix.os}}"
strategy: matrix: {
otp_vsn: _versions.otp
os: ["ubuntu-latest"]
}
}

40
.github/workflows/steps.cue vendored Normal file
View File

@ -0,0 +1,40 @@
package actions
// Versions for simplicity
_versions: {
// The versions here have an underlying Debian/Ubuntu which support enough of
// libsodium to handle what enacl provides. Older versions will fail to compile
otp: ["22.3", "23.3", "24.0"]
rebar3: "3.16.1"
}
_branch: "master"
jobs: ci: steps:
[
{
uses: "actions/checkout@v2"
},
{
uses: "erlef/setup-beam@v1"
with: {
"otp-version": "${{matrix.otp_vsn}}"
"rebar3-version": _versions.rebar3
}
},
{
name: "Update apt-get database"
run: "sudo apt-get update"
},
{
name: "Install libsodium"
run: "sudo apt-get install -y libsodium-dev"
},
{
name: "Compile source code"
run: "make compile"
},
{
name: "Run the tests"
run: "make tests"
}]

6
.gitignore vendored
View File

@ -1,5 +1,6 @@
.rebar
.rebar3
.envrc
ebin
*.beam
*.o
@ -12,3 +13,8 @@ doc/*.png
doc/*.css
_build
/.eqc-info
priv/enacl_nif.dll
priv/enacl_nif.exp
priv/enacl_nif.lib
c_src/*.d

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/nix/store/fb30zc52va0g99q8qgv7kx4ngq163pii-gcc-wrapper-9.3.0/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"C_Cpp.errorSquiggles": "Disabled"
}

View File

@ -5,18 +5,139 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.2.1]
### Fixed [1.2.1]
- Export types from the `enacl` module so it can be referenced in other parts of your system (serokell.io)
## [1.2.0]
### Fixed [1.2.0]
- `sign_verify_detached/3` The code now verifies the size of signatures in detached mode. Before
this change, you could supply a larger binary and the code would only use the first `SIGNBYTES`
of the binary, assuming the signature were in there. Now, it fails with a badarg if the signature
doesn't match expectation in size.
## [1.1.1]
### Added [1.1.1]
- Introduce the ability to reload the enacl module (Bryan Paxton, @starbelly)
## [1.1.0]
### Added [1.1.0]
- Secretstream support was added to the API (Alexander Malaev)
- Add KDF functions (Nicolas Goy, @kuon)
- Add pwhash/5 specifying what algorithm to use for older compatibility (Nicolas Goy, @kuon)
### Changed [1.1.0]
- Remove rebar3_hex as a direct dependency (Bryan Paxton, @starbelly)
## [1.0.0]
### Compatibility [1.0.0]
- Some functions have been streamlined to badarg in certain cases where it made more
sense to do so than returning back an error to the caller.
- Functions generally don't return error values for internal errors. They now raise
exceptions when this happens. If you can't allocate a binary, there is usually not
much the programmer can do with that information, sans crashing.
- If you used `aead_chacha20poly1305_*` functions, please read through the changelog
carefully as we have made changes to these functions. TL;DR: look for
`aead_chacha20poly1305_ietf_*` but note it is *not* just a simple substitution
into your code.
- The `kx` constants have been renamed to follow libsodium one-to-one.
- All calls with `verify` now returns booleans. See `sign_verify_detached`, which
were changed by this.
- Many constants were changed to their underlying libsodium names.
### Removed [1.0.0]
- The functions of the form `aead_chacha20poly1305_*` were removed. They implement
the IETF variant, and the argument order for them were wrong. Also, they used
severely limited nonce values, which is somewhat dangerous. The `..._NONCEBYTES`
name was changed to the consistent `..._NPUBBYTES`.
### Added [1.0.0]
- Added `aead_chacha20poly1305_ietf_*` variants.
- Implement multipart signature support, by Garry Hill.
- Implement enacl:crypto_sign_seed_keypair/1, by Ole Andre Birkedal.
- Implement enacl:crypto_sign_ed25519_sk_to_pk/1, by an anonymous contribution.
- Added AEAD XChaCha20-Poly1305 support, thanks to Github/ECrownofFire.
- The Password Hash Generation functions now support memory and operations limits,
thanks to Github/ECrownofFire.
- Implement enacl:randombytes_uint32/0. Returns a random 32bit unsigned
integer, by means of the underlying random source.
- Implement enacl:randombytes_uniform/1. Takes up to a 32bit unsigned
integer and produces a uniform integer in the range [0..N). Note
that the implementation avoids the typical non-uniformness which
would be present on a modulus operation on the nearest power-of-two
integer.
- Added Win32 build support (Tino Breddin)
- Added a nix shell for easier development
### Changed [1.0.0]
- Started a split the C code over multiple files for easier maintenance.
- Rewrote the generichash routines to be more consistent. We are now more-or-less
following the style of the Erlang/OTP `crypto` library. While here, make sure
we clean up correctly and that we don't accidentally mis-ref-count data. The
code is a bit more goto heavy, but this style is surprisingly common in C code.
- Use sodium's dynamic memory allocators. These guarantee 64bit alignment, and also
provide guard pages around the allocation, somewhat protecting it. It adds some
page table pressure compared to the current code, but is easier to maintain and
much cleaner code.
- The code now rejects updates to generichash states which were already finalized.
- We now track the desired outlen of a generichash operation in the opaque NIF
resource rather than on the Erlang side. This avoids some checks in the code,
and streamlines a good deal of the interface.
- Split AEAD routines off from the main enacl_nif.c file
- Renamed many routines from enif_* to enacl_*. This better reflects where they live
in the code base, and avoids pollution of the enif_* "namespace".
- Split Sign Public Key routines from the rest. Modernize the handling of contexts.
- The multi-part generic hash routines now follow the structure of the crypto
modules multi-part constructions in API and style.
- The AEAD constructions have been streamlined so they follow the rules of libsodium
closer than before. In particular, some dead code has been removed as a result.
- Constants are now named by their libsodium counterpart. This should make it easier
to find the correct names given the libsodium documentation.
- Generichash now checks if a `_final` call has already happened and rejects further
hashing on the object. The rejection is an error: if you ever do this, your code
is definitely wrong and there is no recovery possible.
### Fixed [1.0.0]
- Fix a resource leak in generichash/sign init/update/final.
- Clang static analysis warnings (Thomas Arts).
- Replace a constant 31 with a computation from libsodium (Thomas Arts, from a security review).
- Some subtle memory leaks in the error path for kx operations were plugged.
- The multi-part generichash interface is now properly process/thread safe.
- The sign interface is now properly process/thread safe.
## [0.17.2]
### Fixed [0.17.2]
- Work around `rebar3 hex` publishing .so files
## [0.17.1]
### Fixed
### Fixed [0.17.1]
- Provide a fix for the `pwhash_str/x` functions. The C strings were
not properly handled wrt. NULL-termination and what the libsodium
library expects.
## [0.17.0]
### Added
### Added [0.17.0]
- Expose the AEAD ChaCha20 Poly1305 (IETF) functionality (Hans
Svensson / Quviq).
- Expose Curve25519 Scalar Multiplication over a base point in the
@ -28,11 +149,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
to verify the enacl library on embedded platforms and so on.
- Support generichash functions (Venkatakumar Srinivasan / Xaptum)
### Fixed
### Fixed [0.17.0]
- The type specification of generichash/2 and generichash/3 was
corrected (Technion)
### Changed
### Changed [0.17.0]
- Removed the experimental feature flag `ERL_NIF_DIRTY_JOB_CPU_BOUND`.
This breaks compatibility with older Erlang releases of dirty
schedulers, but prepares us correctly for the new releases where the
@ -50,24 +173,26 @@ Bump libsodium requirement to version 1.0.12. This gives us access to
a number of functions which are added recently and thus gives us
access to implement these from libsodium.
### Added
### Added [0.16.0]
- Add kx_* functions (Alexander Malaev)
- chacha stream functions added, siphash-2-4 added, unsafe_memzero/1
added (no attribution)
### Fixed
### Fixed [0.16.0]
- Do not use the dirty-scheduler test macro as it is gone.
## [0.15.0]
### Fixed
### Fixed [0.15.0]
- Using `enacl:sign_verify_detacted` on large iolists would fail to do
the correct thing due to a typo. This has been corrected. Also the
EQC tests have been extended to include large binary support to
capture these kinds of errors in the future.
### Changed
### Changed [0.15.0]
- Many dirty-scheduler tunings have been performed to make sure we
won't block a scheduler ever.
@ -83,33 +208,40 @@ a better citizen to other libraries and other parts of the system.
## [0.14.0]
### Added
### Added [0.14.0]
- Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr)
- Add support for libsodiums `crypto_sign_detached` (Joel Stanley,
Parnell Springmeyer)
### Changed
### Changed [0.14.0]
- Switch the tag names to the form `0.14.0` rather than `v0.14.0`. For
this release both tags are present, but from the next release on, it
won't be the case.
## [0.13.0]
### Fixed
### Fixed [0.13.0]
- Quell warnings from the C code
### Added
### Added [0.13.0]
- Add Ed 25519 utility API (Alexander Færøy)
- Add FreeBSD support for the NIF compilation (Ricardo Lanziano)
## [0.12.1]
### Changed
### Changed [0.12.1]
- Provide the `priv` directory for being able to properly build
without manual intervention.
## [0.12.0]
### Added
### Added [0.12.0]
- Introduce an extension interface for various necessary extensions to
the eNaCl system for handling the Tor network, thanks to Alexander
Færøy (ahf).
@ -119,12 +251,15 @@ a better citizen to other libraries and other parts of the system.
## [0.11.0]
### Added
### Added [0.11.0]
- Introduce NIF layer beforenm/afternm calls.
- Introduce the API for precomputed keys (beforenm/afternm calls).
- Use test cases which tries to inject `iodata()` rather than binaries
in all places where `iodata()` tend to be accepted.
### Fixed
### Fixed [0.11.0]
- Fix type for `enacl:box_open/4`. The specification was wrong which
results in errors in other applications using enacl.
@ -132,7 +267,8 @@ a better citizen to other libraries and other parts of the system.
Maintenance release. Fix some usability problems with the library.
### Fixed
### Fixed [0.10.2]
- Do not compile the C NIF code if there are no dirty scheduler
support in the Erlang system (Thanks to David N. Welton)
- Fix dialyzer warnings (Thanks Anthony Ramine)
@ -146,7 +282,7 @@ Maintenance release. Fix some usability problems with the library.
## [0.10.1]
### Added
### Added [0.10.1]
- This small patch-release provides tests for the `randombytes/1`
function call, and optimizes EQC tests to make it easier to implement
@ -162,15 +298,15 @@ included in this library.
Ultra-late beta; tuning for the last couple of functions which could
be nice to have.
### Added
### Added [0.10.0]
Added the function `randombytes/1` to obtain randombytes from the
operating system. The system uses the "best" applicable (P)RNG on the
target system:
* Windows: `RtlGenRandom()`
* OpenBSD, Bitrig: `arc4random()`
* Unix in general: `/dev/urandom`
- Windows: `RtlGenRandom()`
- OpenBSD, Bitrig: `arc4random()`
- Unix in general: `/dev/urandom`
Do note that on Linux and FreeBSD at the *least*, this is the best
thing you can do. Relying on `/dev/random` is almost always wrong and
@ -184,4 +320,3 @@ Ultra-late beta. Code probably works, but it requires some real-world
use before it is deemed entirely stable.
Initial release.

View File

@ -3,9 +3,15 @@ List of people who have contributed to the eNaCl source code:
Alexander Færøy
Alexander Malaev
Amir Ghassemi Nasr
Bryan Paxton
GitHub/ECrownofFire
Geller Bedoya
Jesper Louis Andersen
Joel Stanley
Konrad Zemek
Nicolas Goy
Parnell Springmeyer
Ricardo Lanziano
Tino Breddin
Venkatakumar Srinivasan

View File

@ -5,6 +5,10 @@ RUN_EQC=erl -pa _build/default/lib/enacl/ebin -noshell -s enacl_eqc -s init stop
compile:
$(REBAR) compile
.PHONY: tests
tests:
$(REBAR) ct
eqc_compile: compile
erlc -o _build/default/lib/enacl/ebin eqc_test/enacl_eqc.erl

View File

@ -6,17 +6,15 @@ Frank Denis took the source and made it far more portable in the
libsodium library. The enacl project is somewhat misnamed, as it uses
libsodium as the underlying driver.
Several Erlang ports of NaCl/libsodium exists, but this one is a
rewrite with the following foci:
## INSTALL/Requirements
## INSTALL/Requirements:
* New-ish Erlang installation. Tested back to version 22.3, but version 21 *may*
work as well.
* *Requires* the libsodium library, and has been tested with version
1.0.18. Lower versions might work, or they might fail to compile,
due to missing functionality. In particular, this means your libsodium installation
must be fairly recent as well.
* Erlang/OTP 17.3. This library *needs* the newest dirty scheduler
implementation. The library relies on dirty scheduler support in
order to handle long-running cryptography jobs, by moving them off
the main Erlang scheduler and letting the dirty schedulers handle
the work. This keeps the Erlang VM responsive.
* *Requires* the libsodium library, and at least in version 1.0.12.
*Note:* If installing on systems which cuts packages into
subpackages, make sure you also get the "-dev" package containing
the header files necessary in order to compile software linking to
@ -38,10 +36,10 @@ To build and run eqc-mini version of test execute:
make eqc_mini_run
## Features:
## Features
* Complete NaCl library, implementing all default functionality.
* Implements a small set of additional functionality from libsodium.
* Implements a large set of additional functionality from libsodium.
Most notably access to a proper CSPRNG random source
* Tests created by aggressive use of Erlang QuickCheck.
* NaCl is a very fast cryptographic library. That is,
@ -60,16 +58,12 @@ In addition, I would like to thank Steve Vinoski, Rickard Green, and
Sverker Eriksson for providing the Dirty Scheduler API in the first
place.
# USING:
## Usage
In general, consult the libsodium documentation at
https://download.libsodium.org/doc/
In general, consult the libsodium documentation at [Libsodium documentation](https://download.libsodium.org/doc/)
The original NaCl documentation is nowadays largely superceded by the
libsodium documentation, but it is still worth a visit
https://nacl.cr.yp.to
libsodium documentation, but it is still worth a visit [NaCl website](https://nacl.cr.yp.to)
but also note that our interface has full Edoc documentation,
generated by executing
@ -132,11 +126,11 @@ However, their correct use is still needed in order to be secure:
a foreign system as an oracle in order to learn the structure of a
string, breaking the cryptograhic system in the process.
# Versions
## Versions
See CHANGELOG.md
# Overview
## Overview
The NaCl cryptographic library provides a number of different
cryptographic primitives. In the following, we split up the different
@ -198,7 +192,7 @@ This implements cryptography where there is a shared secret key between parties.
* *String comparison:* Implements guaranteed constant-time string
comparisons to protect against timing attacks.
# Rationale
## Rationale
Doing crypto right in Erlang is not that easy. For one, the crypto
system has to be rather fast, which rules out Erlang as the main
@ -250,7 +244,7 @@ perhaps being able to switch faster. There are plans to rerun these
tests on OSX and Illumos as well, in order to investigate the numbers
on more platforms.
# Testing
## Testing
Every primitive has been stress-tested through the use of Erlang
QuickCheck with both *positive* and *negative* testing. This has been
@ -277,11 +271,8 @@ sure we have no memory leaks as they will show themselves under the
extensive QuickCheck test cases we run. It has been verified there are
no leaks in the code.
# Notes
## Notes
[0] Other people have worked on bits and pieces of NaCl. These are
just the 3 main authors. Please see the page
http://nacl.cr.yp.to
just the 3 main authors. Please see the page [NaCl](http://nacl.cr.yp.to)
for the full list of authors.

View File

@ -47,7 +47,7 @@ box() ->
#{ public := PK1} = enacl:box_keypair(),
#{ secret := SK2} = enacl:box_keypair(),
B = binary:copy(<<0>>, 1),
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
Nonce = binary:copy(<<0>>, enacl:box_NONCEBYTES()()),
box(B, Nonce, PK1, SK2, 10*1000).
box(_B, _Nonce, _PK1, _SK2, 0) -> ok;
@ -62,7 +62,7 @@ box_before_after() ->
box_beforenm(PK1, SK2, 10*1000),
R = enacl:box_beforenm(PK1, SK2),
B = binary:copy(<<0>>, 8192),
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
Nonce = binary:copy(<<0>>, enacl:box_NONCEBYTES()()),
box_afternm(B, Nonce, R, 10*1000),
ok.
@ -100,8 +100,8 @@ sign(Msg, SK, N) ->
secretbox() ->
Msg = binary:copy(<<0>>, 8192),
Nonce = binary:copy(<<0>>, enacl:secretbox_nonce_size()),
Key = binary:copy(<<0>>, enacl:secretbox_key_size()),
Nonce = binary:copy(<<0>>, enacl:secretbox_NONCEBYTES()()),
Key = binary:copy(<<0>>, enacl:secretbox_KEYBYTES()),
secretbox(Msg, Nonce, Key, 10*1000).
secretbox(_Msg, _Nonce, _Key, 0) -> ok;
@ -111,7 +111,7 @@ secretbox(Msg, Nonce, Key, N) ->
stream() ->
stream(16384, binary:copy(<<0>>, enacl:stream_nonce_size()), binary:copy(<<0>>, enacl:stream_key_size()), 10*1000).
stream(16384, binary:copy(<<0>>, enacl:stream_NONCEBYTES()), binary:copy(<<0>>, enacl:stream_KEYBYTES()), 10*1000).
stream(_L, _Nonce, _K, 0) -> ok;
stream(L, Nonce, K, N) ->
@ -120,7 +120,7 @@ stream(L, Nonce, K, N) ->
auth() ->
Msg = binary:copy(<<0>>, 4096),
Key = binary:copy(<<0>>, enacl:auth_key_size()),
Key = binary:copy(<<0>>, enacl:auth_KEYBYTES()),
auth(Msg, Key, 10*1000).
auth(_Msg, _Key, 0) -> ok;
@ -130,7 +130,7 @@ auth(Msg, Key, N) ->
onetime_auth() ->
Msg = binary:copy(<<0>>, 16384),
Key = binary:copy(<<0>>, enacl:onetime_auth_key_size()),
Key = binary:copy(<<0>>, enacl:onetime_auth_KEYBYTES()),
onetime_auth(Msg, Key, 10*1000).
onetime_auth(_Msg, _Key, 0) -> ok;

View File

@ -1,75 +0,0 @@
# Based on c_src.mk from erlang.mk by Loïc Hoguin <essen@ninenines.eu>
PROJECT ?= enacl_nif
ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s/erts-~s/include/\", [code:root_dir(), erlang:system_info(version)]).")
ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, include)]).")
ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, lib)]).")
C_SRC_DIR = $(CURDIR)
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so
# System type and C compiler/flags.
MACHINE_SYS := $(shell uname -m)
UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress
else ifeq ($(UNAME_SYS), FreeBSD)
CC ?= cc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -I /usr/local/include
CXXFLAGS ?= -O3 -finline-functions -Wall
LDFLAGS ?= -fPIC -L /usr/local/lib
else ifeq ($(UNAME_SYS), Linux)
CC ?= gcc
CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFLAGS ?= -O3 -finline-functions -Wall
else ifeq ($(UNAME_SYS), SunOS)
CC = gcc
CFLAGS ?= -m64 -I/opt/local/include -O2 -std=c99 -finline-functions -Wall -Wmissing-prototypes
CXXFALGS ?= -O2 -finline-function -Wall
LDFLAGS ?= -m64 -fPIC -L /opt/local/lib
endif
CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR)
LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lerl_interface -lei -lsodium
LDFLAGS += -shared
# Verbosity.
c_verbose_0 = @echo " C " $(?F);
c_verbose = $(c_verbose_$(V))
cpp_verbose_0 = @echo " CPP " $(?F);
cpp_verbose = $(cpp_verbose_$(V))
link_verbose_0 = @echo " LD " $(@F);
link_verbose = $(link_verbose_$(V))
SOURCES := $(shell find $(C_SRC_DIR) -type f \( -name "*.c" -o -name "*.C" -o -name "*.cc" -o -name "*.cpp" \))
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
$(C_SRC_OUTPUT): $(OBJECTS)
$(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT)
%.o: %.c
$(COMPILE_C) $(OUTPUT_OPTION) $<
%.o: %.cc
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
%.o: %.C
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
%.o: %.cpp
$(COMPILE_CPP) $(OUTPUT_OPTION) $<
clean:
@rm -f $(C_SRC_OUTPUT) $(OBJECTS)

242
c_src/aead.c Normal file
View File

@ -0,0 +1,242 @@
#include <sodium.h>
#include <erl_nif.h>
#include "aead.h"
#include "enacl.h"
/*
* AEAD ChaCha20 Poly1305
*/
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_KEYBYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_ABYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
return enif_make_int64(env,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX);
}
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary key, nonce, ad, message, ciphertext;
if (argc != 4)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &message))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &ad))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &nonce))
goto bad_arg;
if (!enif_inspect_binary(env, argv[3], &key))
goto bad_arg;
if (key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES)
goto bad_arg;
if (nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
goto bad_arg;
if (!enif_alloc_binary(message.size +
crypto_aead_chacha20poly1305_ietf_ABYTES,
&ciphertext)) {
goto err;
}
crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.data, NULL, message.data,
message.size, ad.data, ad.size,
NULL, nonce.data, key.data);
ret = enif_make_binary(env, &ciphertext);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_internal_error(env);
done:
return ret;
}
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary key, nonce, ad, message, ciphertext;
if (argc != 4)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &ciphertext))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &ad))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &nonce))
goto bad_arg;
if (!enif_inspect_binary(env, argv[3], &key))
goto bad_arg;
if (ciphertext.size < crypto_aead_chacha20poly1305_ietf_ABYTES)
goto bad_arg;
if (key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES)
goto bad_arg;
if (nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
goto bad_arg;
if (!enif_alloc_binary(ciphertext.size -
crypto_aead_chacha20poly1305_ietf_ABYTES,
&message)) {
return enacl_internal_error(env);
}
if (crypto_aead_chacha20poly1305_ietf_decrypt(
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
ad.size, nonce.data, key.data) != 0) {
ret = enacl_error_tuple(env, "failed_verification");
goto release;
}
ret = enif_make_binary(env, &message);
goto done;
bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&message);
done:
return ret;
}
/*
* AEAD XChaCha20 Poly1305
*/
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_ABYTES);
}
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
return enif_make_int64(env,
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX);
}
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, ad, message, ciphertext;
ERL_NIF_TERM ret;
if (argc != 4)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &message))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &ad))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &nonce))
goto bad_arg;
if (!enif_inspect_binary(env, argv[3], &key))
goto bad_arg;
if (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
goto bad_arg;
if (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
goto bad_arg;
if (!enif_alloc_binary(message.size +
crypto_aead_xchacha20poly1305_ietf_ABYTES,
&ciphertext)) {
goto err;
}
crypto_aead_xchacha20poly1305_ietf_encrypt(
ciphertext.data, NULL, message.data, message.size, ad.data, ad.size, NULL,
nonce.data, key.data);
ret = enif_make_binary(env, &ciphertext);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_internal_error(env);
done:
return ret;
}
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, ad, message, ciphertext;
ERL_NIF_TERM ret;
if (argc != 4)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &ciphertext))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &ad))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &nonce))
goto bad_arg;
if (!enif_inspect_binary(env, argv[3], &key))
goto bad_arg;
if (ciphertext.size < crypto_aead_xchacha20poly1305_ietf_ABYTES)
goto bad_arg;
if (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
goto bad_arg;
if (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
goto bad_arg;
if (!enif_alloc_binary(ciphertext.size -
crypto_aead_xchacha20poly1305_ietf_ABYTES,
&message)) {
return enacl_internal_error(env);
}
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
ad.size, nonce.data, key.data) != 0) {
ret = enacl_error_tuple(env, "failed_verification");
goto release;
}
ret = enif_make_binary(env, &message);
goto done;
bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&message);
done:
return ret;
}

46
c_src/aead.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef ENACL_AEAD_H
#define ENACL_AEAD_H
#include <erl_nif.h>
/* AEAD ChaCha20 Poly1305 */
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_chacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
/* AEAD XChaCha20 Poly1305 */
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_aead_xchacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

16
c_src/enacl.c Normal file
View File

@ -0,0 +1,16 @@
#include <erl_nif.h>
#include "enacl.h"
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *env, char *error_atom) {
return enif_make_tuple2(env, enif_make_atom(env, "error"),
enif_make_atom(env, error_atom));
}
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *env) {
return enif_raise_exception(env, enif_make_atom(env, "enacl_internal_error"));
}
ERL_NIF_TERM enacl_error_finalized(ErlNifEnv *env) {
return enif_raise_exception(env, enif_make_atom(env, "enacl_finalized"));
}

15
c_src/enacl.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef ENACL_H
#define ENACL_H
#include <erl_nif.h>
#define ATOM_OK "ok"
#define ATOM_ERROR "error"
#define ATOM_TRUE "true"
#define ATOM_FALSE "false"
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *);
ERL_NIF_TERM enacl_error_finalized(ErlNifEnv *);
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *);
#endif

86
c_src/enacl_ext.c Normal file
View File

@ -0,0 +1,86 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "enacl_ext.h"
static void uint64_pack(unsigned char *y, ErlNifUInt64 x) {
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
x >>= 8;
*y++ = x;
}
static ErlNifUInt64 uint64_unpack(const unsigned char *x) {
ErlNifUInt64 result;
result = x[7];
result <<= 8;
result |= x[6];
result <<= 8;
result |= x[5];
result <<= 8;
result |= x[4];
result <<= 8;
result |= x[3];
result <<= 8;
result |= x[2];
result <<= 8;
result |= x[1];
result <<= 8;
result |= x[0];
return result;
}
static int crypto_block(unsigned char *out, const unsigned char *in,
const unsigned char *k) {
ErlNifUInt64 v0 = uint64_unpack(in + 0);
ErlNifUInt64 v1 = uint64_unpack(in + 8);
ErlNifUInt64 k0 = uint64_unpack(k + 0);
ErlNifUInt64 k1 = uint64_unpack(k + 8);
ErlNifUInt64 k2 = uint64_unpack(k + 16);
ErlNifUInt64 k3 = uint64_unpack(k + 24);
ErlNifUInt64 sum = 0;
ErlNifUInt64 delta = 0x9e3779b97f4a7c15;
int i;
for (i = 0; i < 32; ++i) {
sum += delta;
v0 += ((v1 << 7) + k0) ^ (v1 + sum) ^ ((v1 >> 12) + k1);
v1 += ((v0 << 16) + k2) ^ (v0 + sum) ^ ((v0 >> 8) + k3);
}
uint64_pack(out + 0, v0);
uint64_pack(out + 8, v1);
return 0;
}
ERL_NIF_TERM enif_scramble_block_16(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary in, out, key;
if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &in)) ||
(!enif_inspect_binary(env, argv[1], &key)) || (in.size != 16) ||
(key.size != 32)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(in.size, &out)) {
return enacl_internal_error(env);
}
crypto_block(out.data, in.data, key.data);
return enif_make_binary(env, &out);
}

9
c_src/enacl_ext.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef ENACL_EXT_H
#define ENACL_EXT_H
#include <erl_nif.h>
ERL_NIF_TERM enif_scramble_block_16(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

File diff suppressed because it is too large Load Diff

301
c_src/generichash.c Normal file
View File

@ -0,0 +1,301 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "generichash.h"
typedef struct enacl_generichash_ctx {
ErlNifMutex *mtx;
crypto_generichash_state *ctx; // Underlying hash state from sodium
int alive; // Is the context still valid for updates/finalizes?
int outlen; // Final size of the hash
} enacl_generichash_ctx;
static ErlNifResourceType *enacl_generic_hash_ctx_rtype;
static void enacl_generic_hash_ctx_dtor(ErlNifEnv *env,
enacl_generichash_ctx *);
int enacl_init_generic_hash_ctx(ErlNifEnv *env) {
enacl_generic_hash_ctx_rtype =
enif_open_resource_type(env, NULL, "enacl_generichash_context",
(ErlNifResourceDtor *)enacl_generic_hash_ctx_dtor,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
if (enacl_generic_hash_ctx_rtype == NULL)
return 0;
return 1;
}
static void enacl_generic_hash_ctx_dtor(ErlNifEnv *env,
enacl_generichash_ctx *obj) {
if (!obj->alive) {
return;
}
if (obj->ctx)
sodium_free(obj->ctx);
if (obj->mtx != NULL)
enif_mutex_destroy(obj->mtx);
return;
}
/*
* Generic hash
*/
ERL_NIF_TERM enacl_crypto_generichash_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_BYTES);
}
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_BYTES_MIN);
}
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_BYTES_MAX);
}
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_KEYBYTES_MIN);
}
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_generichash_KEYBYTES_MAX);
}
ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary hash, message, key;
unsigned hash_size;
ERL_NIF_TERM ret;
// Validate the arguments
if (argc != 3)
goto bad_arg;
if (!enif_get_uint(env, argv[0], &hash_size))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &message))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &key))
goto bad_arg;
// Verify that hash size is
// crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX
if ((hash_size < crypto_generichash_BYTES_MIN) ||
(hash_size > crypto_generichash_BYTES_MAX)) {
goto bad_arg;
}
// validate key size
unsigned char *k = key.data;
if (0 == key.size) {
k = NULL;
} else if (key.size < crypto_generichash_KEYBYTES_MIN ||
key.size > crypto_generichash_KEYBYTES_MAX) {
goto bad_arg;
}
// allocate memory for hash
if (!enif_alloc_binary(hash_size, &hash)) {
goto err;
}
// calculate hash
if (0 != crypto_generichash(hash.data, hash.size, message.data, message.size,
k, key.size)) {
goto release;
}
ret = enif_make_binary(env, &hash);
goto done;
bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&hash);
err:
ret = enacl_internal_error(env);
done:
return ret;
}
ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key;
unsigned hash_size;
enacl_generichash_ctx *obj = NULL;
ERL_NIF_TERM ret;
// Validate the arguments
if (argc != 2)
goto bad_arg;
if (!enif_get_uint(env, argv[0], &hash_size))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &key))
goto bad_arg;
// Verify that hash size is valid
if ((hash_size < crypto_generichash_BYTES_MIN) ||
(hash_size > crypto_generichash_BYTES_MAX)) {
goto bad_arg;
}
// validate key size
unsigned char *k = key.data;
if (0 == key.size) {
k = NULL;
} else if (key.size < crypto_generichash_KEYBYTES_MIN ||
key.size > crypto_generichash_KEYBYTES_MAX) {
goto bad_arg;
}
// Create the resource
if ((obj = enif_alloc_resource(enacl_generic_hash_ctx_rtype,
sizeof(enacl_generichash_ctx))) == NULL) {
goto err;
}
// Allocate the state context via libsodium
// Note that this ensures a 64byte alignment for the resource
// And also protects the resource via guardpages
obj->mtx = NULL;
obj->ctx = NULL;
obj->alive = 0;
obj->outlen = 0;
obj->ctx = (crypto_generichash_state *)sodium_malloc(
crypto_generichash_statebytes());
if (obj->ctx == NULL) {
goto err;
}
obj->alive = 1;
obj->outlen = hash_size;
if ((obj->mtx = enif_mutex_create("enacl.generichash")) == NULL) {
ret = enacl_error_tuple(env, "mutex_create");
goto err;
}
// Call the library function
if (0 != crypto_generichash_init(obj->ctx, k, key.size, obj->outlen)) {
ret = enacl_error_tuple(env, "hash_init_error");
goto err;
}
ret = enif_make_resource(env, obj);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_internal_error(env);
if (obj != NULL) {
if (obj->alive) {
sodium_free(obj->ctx);
obj->alive = 0; // Maintain the invariant consistently
}
}
done:
if (obj != NULL) {
enif_release_resource(obj);
}
return ret;
}
ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary data;
enacl_generichash_ctx *obj = NULL;
// Validate the arguments
if (argc != 2)
goto bad_arg;
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_generic_hash_ctx_rtype,
(void **)&obj))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &data))
goto bad_arg;
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
goto err;
}
// Update hash state
if (0 != crypto_generichash_update(obj->ctx, data.data, data.size)) {
goto err;
}
ret = argv[0];
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_error_finalized(env);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary hash;
enacl_generichash_ctx *obj = NULL;
if (argc != 1)
goto bad_arg;
if (!enif_get_resource(env, argv[0], enacl_generic_hash_ctx_rtype,
(void **)&obj))
goto bad_arg;
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
ret = enacl_error_finalized(env);
goto done;
}
if (!enif_alloc_binary(obj->outlen, &hash)) {
goto err;
}
if (0 != crypto_generichash_final(obj->ctx, hash.data, hash.size)) {
goto release;
}
// Finalize the object such that it cannot be reused by accident
if (obj->ctx)
sodium_free(obj->ctx);
obj->alive = 0;
ret = enif_make_binary(env, &hash);
goto done;
bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&hash);
err:
ret = enacl_internal_error(env);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}

32
c_src/generichash.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef ENACL_GENERICHASH_H
#define ENACL_GENERICHASH_H
#include <erl_nif.h>
int enacl_init_generic_hash_ctx(ErlNifEnv *env);
ERL_NIF_TERM enacl_crypto_generichash_BYTES(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
#endif

62
c_src/hash.c Normal file
View File

@ -0,0 +1,62 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "hash.h"
ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_shorthash_BYTES);
}
ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_shorthash_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary a, m, k;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &k))) {
return enif_make_badarg(env);
}
if (k.size != crypto_shorthash_KEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_shorthash_BYTES, &a)) {
return enacl_internal_error(env);
}
crypto_shorthash(a.data, m.data, m.size, k.data);
return enif_make_binary(env, &a);
}
ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary input;
ErlNifBinary result;
ERL_NIF_TERM ret;
if ((argc != 1) || (!enif_inspect_iolist_as_binary(env, argv[0], &input)))
goto bad_arg;
if (!enif_alloc_binary(crypto_hash_BYTES, &result))
goto err;
crypto_hash(result.data, input.data, input.size);
ret = enif_make_binary(env, &result);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_internal_error(env);
done:
return ret;
}

17
c_src/hash.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef ENACL_HASH_H
#define ENACL_HASH_H
#include <erl_nif.h>
ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]);
#endif

59
c_src/kdf.c Normal file
View File

@ -0,0 +1,59 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "kdf.h"
ERL_NIF_TERM enacl_crypto_kdf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_kdf_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_kdf_CONTEXTBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_kdf_CONTEXTBYTES);
}
ERL_NIF_TERM enacl_crypto_kdf_derive_from_key(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary m, c, r;
ErlNifUInt64 id;
// Validate the arguments
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &c)) ||
(!enif_get_uint64(env, argv[2], &id))) {
return enif_make_badarg(env);
}
// Check Master Key length
if (m.size != crypto_kdf_KEYBYTES) {
return enif_make_badarg(env);
}
// Check Context Key length
if (c.size != crypto_kdf_CONTEXTBYTES) {
return enif_make_badarg(env);
}
// Allocate memory for return binary
if (!enif_alloc_binary(crypto_kdf_KEYBYTES, &r)) {
return enacl_internal_error(env);
}
if (crypto_kdf_derive_from_key(r.data, r.size,
id,
(const char *)c.data,
m.data) != 0) {
/* out of memory */
enif_release_binary(&r);
return enacl_internal_error(env);
}
return enif_make_binary(env, &r);
}

15
c_src/kdf.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef ENACL_KDF_H
#define ENACL_KDF_H
#include <erl_nif.h>
ERL_NIF_TERM enacl_crypto_kdf_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kdf_CONTEXTBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kdf_derive_from_key(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

151
c_src/kx.c Normal file
View File

@ -0,0 +1,151 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "kx.h"
/* Key exchange */
ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_kx_SECRETKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_kx_PUBLICKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_kx_SESSIONKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_kx_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk;
if (argc != 0) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_kx_PUBLICKEYBYTES, &pk)) {
return enacl_internal_error(env);
}
if (!enif_alloc_binary(crypto_kx_SECRETKEYBYTES, &sk)) {
enif_release_binary(&pk);
return enacl_internal_error(env);
}
crypto_kx_keypair(pk.data, sk.data);
return enif_make_tuple2(env, enif_make_binary(env, &pk),
enif_make_binary(env, &sk));
}
ERL_NIF_TERM
enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary rx, tx, server_pk, server_sk, client_pk;
if (argc != 3)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &server_pk))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &server_sk))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &client_pk))
goto bad_arg;
if (server_pk.size != crypto_kx_PUBLICKEYBYTES)
goto bad_arg;
if (server_sk.size != crypto_kx_SECRETKEYBYTES)
goto bad_arg;
if (client_pk.size != crypto_kx_PUBLICKEYBYTES)
goto bad_arg;
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) {
ret = enacl_internal_error(env);
goto done;
}
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) {
ret = enacl_internal_error(env);
goto release_rx;
}
if (0 != crypto_kx_server_session_keys(rx.data, tx.data, server_pk.data,
server_sk.data, client_pk.data)) {
// suspicious client public key
ret = enacl_error_tuple(env, "invalid_client_public_key");
goto release_tx_rx;
}
ret = enif_make_tuple2(env, enif_make_binary(env, &rx),
enif_make_binary(env, &tx));
goto done;
bad_arg:
return enif_make_badarg(env);
release_tx_rx:
enif_release_binary(&tx);
release_rx:
enif_release_binary(&rx);
done:
return ret;
}
ERL_NIF_TERM
enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary rx, tx, client_pk, client_sk, server_pk;
ERL_NIF_TERM ret;
if (argc != 3)
goto bad_arg;
if (!enif_inspect_binary(env, argv[0], &client_pk))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &client_sk))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &server_pk))
goto bad_arg;
if (client_pk.size != crypto_kx_PUBLICKEYBYTES)
goto bad_arg;
if (client_sk.size != crypto_kx_SECRETKEYBYTES)
goto bad_arg;
if (server_pk.size != crypto_kx_PUBLICKEYBYTES)
goto bad_arg;
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) {
ret = enacl_internal_error(env);
goto done;
}
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) {
ret = enacl_internal_error(env);
goto release_rx;
}
if (0 != crypto_kx_client_session_keys(rx.data, tx.data, client_pk.data,
client_sk.data, server_pk.data)) {
// suspicious server public key
ret = enacl_error_tuple(env, "invalid_server_public_key");
goto release_tx_rx;
}
ret = enif_make_tuple2(env, enif_make_binary(env, &rx),
enif_make_binary(env, &tx));
goto done;
bad_arg:
return enif_make_badarg(env);
release_tx_rx:
enif_release_binary(&tx);
release_rx:
enif_release_binary(&rx);
done:
return ret;
}

24
c_src/kx.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef ENACL_KX_H
#define ENACL_KX_H
#include <erl_nif.h>
ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kx_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

286
c_src/public.c Normal file
View File

@ -0,0 +1,286 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "public.h"
/* Public-key cryptography */
ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_NONCEBYTES);
}
ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_ZEROBYTES);
}
ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_BOXZEROBYTES);
}
ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_PUBLICKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_SECRETKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_BEFORENMBYTES);
}
ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_box_SEALBYTES);
}
ERL_NIF_TERM enacl_crypto_box_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk;
if (argc != 0) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_box_PUBLICKEYBYTES, &pk)) {
return enacl_error_tuple(env, "alloc_failed");
}
if (!enif_alloc_binary(crypto_box_SECRETKEYBYTES, &sk)) {
enif_release_binary(&pk);
return enacl_error_tuple(env, "alloc_failed");
}
crypto_box_keypair(pk.data, sk.data);
return enif_make_tuple2(env, enif_make_binary(env, &pk),
enif_make_binary(env, &sk));
}
ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary padded_msg, nonce, pk, sk, result;
ERL_NIF_TERM ret;
if (argc != 4)
goto bad_arg;
if (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &nonce))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &pk))
goto bad_arg;
if (!enif_inspect_binary(env, argv[3], &sk))
goto bad_arg;
if (nonce.size != crypto_box_NONCEBYTES)
goto bad_arg;
if (pk.size != crypto_box_PUBLICKEYBYTES)
goto bad_arg;
if (sk.size != crypto_box_SECRETKEYBYTES)
goto bad_arg;
if (padded_msg.size < crypto_box_ZEROBYTES)
goto bad_arg;
if (!enif_alloc_binary(padded_msg.size, &result)) {
goto err;
}
if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data,
pk.data, sk.data)) {
goto release;
}
ret = enif_make_sub_binary(env, enif_make_binary(env, &result),
crypto_box_BOXZEROBYTES,
padded_msg.size - crypto_box_BOXZEROBYTES);
goto done;
bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&result);
err:
ret = enacl_internal_error(env);
done:
return ret;
}
ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary padded_ciphertext, nonce, pk, sk, result;
if ((argc != 4) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &pk)) ||
(!enif_inspect_binary(env, argv[3], &sk))) {
return enif_make_badarg(env);
}
if ((nonce.size != crypto_box_NONCEBYTES) ||
(pk.size != crypto_box_PUBLICKEYBYTES) ||
(sk.size != crypto_box_SECRETKEYBYTES) ||
(padded_ciphertext.size < crypto_box_BOXZEROBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(padded_ciphertext.size, &result)) {
return enacl_internal_error(env);
}
if (0 != crypto_box_open(result.data, padded_ciphertext.data,
padded_ciphertext.size, nonce.data, pk.data,
sk.data)) {
enif_release_binary(&result);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_sub_binary(
env, enif_make_binary(env, &result), crypto_box_ZEROBYTES,
padded_ciphertext.size - crypto_box_ZEROBYTES);
return enif_make_tuple2(env, ret_ok, ret_bin);
}
/* Precomputed crypto boxes */
ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary k, pk, sk;
if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &pk)) ||
(!enif_inspect_binary(env, argv[1], &sk)) ||
(pk.size != crypto_box_PUBLICKEYBYTES) ||
(sk.size != crypto_box_SECRETKEYBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) {
goto err;
}
if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) {
// error
enif_release_binary(&k);
goto err;
}
return enif_make_binary(env, &k);
err:
return enacl_internal_error(env);
}
ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary result, m, nonce, k;
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &k)) ||
(m.size < crypto_box_ZEROBYTES) ||
(nonce.size != crypto_box_NONCEBYTES) ||
(k.size != crypto_box_BEFORENMBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size, &result)) {
return enacl_internal_error(env);
}
crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data);
return enif_make_sub_binary(env, enif_make_binary(env, &result),
crypto_box_BOXZEROBYTES,
m.size - crypto_box_BOXZEROBYTES);
}
ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary result, m, nonce, k;
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &k)) ||
(m.size < crypto_box_BOXZEROBYTES) ||
(nonce.size != crypto_box_NONCEBYTES) ||
(k.size != crypto_box_BEFORENMBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size, &result)) {
return enacl_internal_error(env);
}
if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data,
k.data)) {
enif_release_binary(&result);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin =
enif_make_sub_binary(env, enif_make_binary(env, &result),
crypto_box_ZEROBYTES, m.size - crypto_box_ZEROBYTES);
return enif_make_tuple2(env, ret_ok, ret_bin);
}
/* Sealed box functions */
ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, msg, ciphertext;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &msg)) ||
(!enif_inspect_binary(env, argv[1], &key))) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) {
return enacl_internal_error(env);
}
crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data);
return enif_make_binary(env, &ciphertext);
}
ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk, ciphertext, msg;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &ciphertext)) ||
(!enif_inspect_binary(env, argv[1], &pk)) ||
(!enif_inspect_binary(env, argv[2], &sk))) {
return enif_make_badarg(env);
}
if (ciphertext.size < crypto_box_SEALBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) {
return enacl_internal_error(env);
}
if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data,
sk.data) != 0) {
enif_release_binary(&msg);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &msg);
return enif_make_tuple2(env, ret_ok, ret_bin);
}

49
c_src/public.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef ENACL_PUBLIC_H
#define ENACL_PUBLIC_H
ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

180
c_src/pwhash.c Normal file
View File

@ -0,0 +1,180 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "pwhash.h"
static size_t enacl_pwhash_opslimit(ErlNifEnv *env, ERL_NIF_TERM arg) {
ERL_NIF_TERM a;
size_t r;
if (enif_is_atom(env, arg)) {
a = enif_make_atom(env, "interactive");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_OPSLIMIT_INTERACTIVE;
}
a = enif_make_atom(env, "moderate");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_OPSLIMIT_MODERATE;
}
a = enif_make_atom(env, "sensitive");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_OPSLIMIT_SENSITIVE;
}
} else if (enif_get_ulong(env, arg, &r)) {
return r;
}
return 0;
}
static size_t enacl_pwhash_memlimit(ErlNifEnv *env, ERL_NIF_TERM arg) {
ERL_NIF_TERM a;
size_t r;
if (enif_is_atom(env, arg)) {
a = enif_make_atom(env, "interactive");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_MEMLIMIT_INTERACTIVE;
}
a = enif_make_atom(env, "moderate");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_MEMLIMIT_MODERATE;
}
a = enif_make_atom(env, "sensitive");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_MEMLIMIT_SENSITIVE;
}
} else if (enif_get_ulong(env, arg, &r)) {
return r;
}
return 0;
}
ERL_NIF_TERM enacl_crypto_pwhash_SALTBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_pwhash_SALTBYTES);
}
static int enacl_pwhash_alg(ErlNifEnv *env, ERL_NIF_TERM arg) {
ERL_NIF_TERM a;
int r;
if (enif_is_atom(env, arg)) {
a = enif_make_atom(env, "default");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_ALG_DEFAULT;
}
a = enif_make_atom(env, "argon2i13");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_ALG_ARGON2I13;
}
a = enif_make_atom(env, "argon2id13");
if (enif_is_identical(a, arg)) {
return crypto_pwhash_ALG_ARGON2ID13;
}
} else if (enif_get_int(env, arg, &r)) {
return r;
}
return 0;
}
ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary h, p, s;
size_t o, m;
int alg;
// Validate the arguments
if ((argc != 5) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) ||
(!enif_inspect_binary(env, argv[1], &s)) ||
!(o = enacl_pwhash_opslimit(env, argv[2])) ||
!(m = enacl_pwhash_memlimit(env, argv[3])) ||
!(alg = enacl_pwhash_alg(env, argv[4]))) {
return enif_make_badarg(env);
}
// Check limits
if ((o < crypto_pwhash_OPSLIMIT_MIN) || (o > crypto_pwhash_OPSLIMIT_MAX) ||
(m < crypto_pwhash_MEMLIMIT_MIN) || (m > crypto_pwhash_MEMLIMIT_MAX)) {
return enif_make_badarg(env);
}
// Check Salt size
if (s.size != crypto_pwhash_SALTBYTES) {
return enif_make_badarg(env);
}
// Allocate memory for return binary
if (!enif_alloc_binary(crypto_box_SEEDBYTES, &h)) {
return enacl_internal_error(env);
}
if (crypto_pwhash(h.data, h.size, (char *)p.data, p.size, s.data, o, m,
alg) != 0) {
/* out of memory */
enif_release_binary(&h);
return enacl_internal_error(env);
}
return enif_make_binary(env, &h);
}
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary h, p;
size_t o, m;
// Validate the arguments
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) ||
!(o = enacl_pwhash_opslimit(env, argv[1])) ||
!(m = enacl_pwhash_memlimit(env, argv[2]))) {
return enif_make_badarg(env);
}
// Check limits
if ((o < crypto_pwhash_OPSLIMIT_MIN) || (o > crypto_pwhash_OPSLIMIT_MAX) ||
(m < crypto_pwhash_MEMLIMIT_MIN) || (m > crypto_pwhash_MEMLIMIT_MAX)) {
return enif_make_badarg(env);
}
// Allocate memory for return binary
if (!enif_alloc_binary(crypto_pwhash_STRBYTES, &h)) {
return enacl_internal_error(env);
}
if (crypto_pwhash_str((char *)h.data, (char *)p.data, p.size, o, m) != 0) {
/* out of memory */
enif_release_binary(&h);
return enacl_internal_error(env);
}
return enif_make_binary(env, &h);
}
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary h, p;
// Validate the arguments
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &h)) ||
(!enif_inspect_iolist_as_binary(env, argv[1], &p))) {
return enif_make_badarg(env);
}
ERL_NIF_TERM ret = enif_make_atom(env, ATOM_TRUE);
if (crypto_pwhash_str_verify((char *)h.data, (char *)p.data, p.size) != 0) {
/* wrong password */
ret = enif_make_atom(env, ATOM_FALSE);
}
return ret;
}

18
c_src/pwhash.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef ENACL_PWHASH_H
#define ENACL_PWHASH_H
#include <erl_nif.h>
ERL_NIF_TERM enacl_crypto_pwhash_SALTBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

49
c_src/randombytes.c Normal file
View File

@ -0,0 +1,49 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "randombytes.h"
ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
unsigned req_size;
ErlNifBinary result;
if ((argc != 1) || (!enif_get_uint(env, argv[0], &req_size))) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(req_size, &result)) {
return enacl_internal_error(env);
}
randombytes(result.data, result.size);
return enif_make_binary(env, &result);
}
ERL_NIF_TERM enif_randombytes_uint32(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifUInt64 result;
if (argc != 0) {
return enif_make_badarg(env);
}
result = randombytes_random();
return enif_make_uint64(env, result);
}
ERL_NIF_TERM enif_randombytes_uniform(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
unsigned upper_bound;
ErlNifUInt64 result;
if ((argc != 1) || (!enif_get_uint(env, argv[0], &upper_bound))) {
return enif_make_badarg(env);
}
result = randombytes_uniform(upper_bound);
return enif_make_uint64(env, result);
}

15
c_src/randombytes.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef ENACL_RANDOMBYTES_H
#define ENACL_RANDOMBYTES_H
#include <erl_nif.h>
ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enif_randombytes_uint32(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enif_randombytes_uniform(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

382
c_src/secret.c Normal file
View File

@ -0,0 +1,382 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "secret.h"
/* Secret key cryptography */
ERL_NIF_TERM
enacl_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_secretbox_NONCEBYTES);
}
ERL_NIF_TERM enacl_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_secretbox_KEYBYTES);
}
ERL_NIF_TERM
enacl_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_secretbox_ZEROBYTES);
}
ERL_NIF_TERM
enacl_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_secretbox_BOXZEROBYTES);
}
ERL_NIF_TERM
enacl_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_chacha20_KEYBYTES);
}
ERL_NIF_TERM
enacl_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_chacha20_NONCEBYTES);
}
ERL_NIF_TERM enacl_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_NONCEBYTES);
}
ERL_NIF_TERM enacl_crypto_auth_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_auth_BYTES);
}
ERL_NIF_TERM enacl_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_auth_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_onetimeauth_BYTES);
}
ERL_NIF_TERM
enacl_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_onetimeauth_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, padded_msg, padded_ciphertext;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES) ||
(padded_msg.size < crypto_secretbox_ZEROBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(padded_msg.size, &padded_ciphertext)) {
return enacl_internal_error(env);
}
crypto_secretbox(padded_ciphertext.data, padded_msg.data, padded_msg.size,
nonce.data, key.data);
return enif_make_sub_binary(env, enif_make_binary(env, &padded_ciphertext),
crypto_secretbox_BOXZEROBYTES,
padded_msg.size - crypto_secretbox_BOXZEROBYTES);
}
ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, padded_ciphertext, padded_msg;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES) ||
(padded_ciphertext.size < crypto_secretbox_BOXZEROBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(padded_ciphertext.size, &padded_msg)) {
return enacl_internal_error(env);
}
if (crypto_secretbox_open(padded_msg.data, padded_ciphertext.data,
padded_ciphertext.size, nonce.data,
key.data) != 0) {
enif_release_binary(&padded_msg);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_sub_binary(
env, enif_make_binary(env, &padded_msg), crypto_secretbox_ZEROBYTES,
padded_ciphertext.size - crypto_secretbox_ZEROBYTES);
return enif_make_tuple2(env, ret_ok, ret_bin);
}
ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, msg, cipherbox;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &msg)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(msg.size + crypto_secretbox_MACBYTES, &cipherbox)) {
return enacl_internal_error(env);
}
crypto_secretbox_easy(cipherbox.data, msg.data, msg.size,
nonce.data, key.data);
return enif_make_binary(env, &cipherbox);
}
ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, cipherbox, msg;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &cipherbox)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES) ||
(cipherbox.size < crypto_secretbox_MACBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(cipherbox.size - crypto_secretbox_MACBYTES, &msg)) {
return enacl_internal_error(env);
}
if (crypto_secretbox_open_easy(msg.data, cipherbox.data, cipherbox.size,
nonce.data, key.data) != 0) {
enif_release_binary(&msg);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &msg);
return enif_make_tuple2(env, ret_ok, ret_bin);
}
ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary c, n, k;
ErlNifUInt64 clen;
if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_stream_chacha20_KEYBYTES) ||
(n.size != crypto_stream_chacha20_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(clen, &c)) {
return enacl_internal_error(env);
}
crypto_stream_chacha20(c.data, c.size, n.data, k.data);
return enif_make_binary(env, &c);
}
ERL_NIF_TERM
enacl_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary c, m, n, k;
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_stream_chacha20_KEYBYTES) ||
(n.size != crypto_stream_chacha20_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size, &c)) {
return enacl_internal_error(env);
}
crypto_stream_chacha20_xor(c.data, m.data, m.size, n.data, k.data);
return enif_make_binary(env, &c);
}
ERL_NIF_TERM enacl_crypto_stream(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary c, n, k;
ErlNifUInt64 clen;
if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_stream_KEYBYTES) ||
(n.size != crypto_stream_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(clen, &c)) {
return enacl_internal_error(env);
}
crypto_stream(c.data, c.size, n.data, k.data);
return enif_make_binary(env, &c);
}
ERL_NIF_TERM enacl_crypto_stream_xor(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary c, m, n, k;
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_stream_KEYBYTES) ||
(n.size != crypto_stream_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size, &c)) {
return enacl_internal_error(env);
}
crypto_stream_xor(c.data, m.data, m.size, n.data, k.data);
return enif_make_binary(env, &c);
}
ERL_NIF_TERM enacl_crypto_auth(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary a, m, k;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &k))) {
return enif_make_badarg(env);
}
if (k.size != crypto_auth_KEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_auth_BYTES, &a)) {
return enacl_internal_error(env);
}
crypto_auth(a.data, m.data, m.size, k.data);
return enif_make_binary(env, &a);
}
ERL_NIF_TERM enacl_crypto_auth_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary a, m, k;
if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) ||
(!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_auth_KEYBYTES) || (a.size != crypto_auth_BYTES)) {
return enif_make_badarg(env);
}
if (0 == crypto_auth_verify(a.data, m.data, m.size, k.data)) {
return enif_make_atom(env, "true");
} else {
return enif_make_atom(env, "false");
}
}
ERL_NIF_TERM enacl_crypto_onetimeauth(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary a, m, k;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &k))) {
return enif_make_badarg(env);
}
if (k.size != crypto_onetimeauth_KEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_onetimeauth_BYTES, &a)) {
return enacl_internal_error(env);
}
crypto_onetimeauth(a.data, m.data, m.size, k.data);
return enif_make_binary(env, &a);
}
ERL_NIF_TERM enacl_crypto_onetimeauth_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary a, m, k;
if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) ||
(!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if ((k.size != crypto_onetimeauth_KEYBYTES) ||
(a.size != crypto_onetimeauth_BYTES)) {
return enif_make_badarg(env);
}
if (0 == crypto_onetimeauth_verify(a.data, m.data, m.size, k.data)) {
return enif_make_atom(env, "true");
} else {
return enif_make_atom(env, "false");
}
}

76
c_src/secret.h Normal file
View File

@ -0,0 +1,76 @@
#ifndef ENACL_SECRET_H
#define ENACL_SECRET_H
ERL_NIF_TERM enacl_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_auth_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_xor(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_auth(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_auth_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_onetimeauth(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_onetimeauth_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

462
c_src/secretstream.c Normal file
View File

@ -0,0 +1,462 @@
#include <erl_nif.h>
#include <sodium.h>
#include "enacl.h"
#include "secretstream.h"
typedef struct enacl_secretstream_ctx {
ErlNifMutex *mtx;
crypto_secretstream_xchacha20poly1305_state
*state; // The underlying secretstream state
int alive; // Is the context still valid for updates/finalization
} enacl_secretstream_ctx;
ErlNifResourceType *enacl_secretstream_ctx_rtype = NULL;
static void enacl_secretstream_ctx_dtor(ErlNifEnv *env,
enacl_secretstream_ctx *);
int enacl_init_secretstream_ctx(ErlNifEnv *env) {
enacl_secretstream_ctx_rtype =
enif_open_resource_type(env, NULL, "enacl_secretstream_context",
(ErlNifResourceDtor *)enacl_secretstream_ctx_dtor,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
if (enacl_secretstream_ctx_rtype == NULL)
return 0;
return 1;
}
static void enacl_secretstream_ctx_dtor(ErlNifEnv *env,
enacl_secretstream_ctx *obj) {
if (!obj->alive) {
return;
}
if (obj->state)
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
if (obj->mtx != NULL)
enif_mutex_destroy(obj->mtx);
return;
}
/*
* Secretstream
*/
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_ABYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(
env, crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env,
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_PUSH);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_REKEY);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_FINAL);
}
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_keygen(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifBinary key;
if (argc != 0) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_KEYBYTES,
&key)) {
return enacl_internal_error(env);
}
crypto_secretstream_xchacha20poly1305_keygen(key.data);
return enif_make_binary(env, &key);
}
/*
int crypto_secretstream_xchacha20poly1305_init_push
(crypto_secretstream_xchacha20poly1305_state *state,
unsigned char out[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary key, header;
enacl_secretstream_ctx *obj = NULL;
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &key))) {
goto bad_arg;
}
if (key.size != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
goto bad_arg;
}
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_HEADERBYTES,
&header)) {
ret = enacl_internal_error(env);
goto done;
}
if ((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
ret = enacl_internal_error(env);
goto release_header;
}
obj->alive = 0;
obj->state = enif_alloc(crypto_secretstream_xchacha20poly1305_statebytes());
if (obj->state == NULL) {
ret = enacl_internal_error(env);
goto release;
}
obj->alive = 1;
if ((obj->mtx = enif_mutex_create("enacl.secretstream")) == NULL) {
ret = enacl_internal_error(env);
goto free;
}
crypto_secretstream_xchacha20poly1305_init_push(obj->state, header.data,
key.data);
ret = enif_make_tuple2(env, enif_make_binary(env, &header),
enif_make_resource(env, obj));
goto release;
bad_arg:
return enif_make_badarg(env);
free:
if (obj->alive)
if (obj->state != NULL) {
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
release_header:
enif_release_binary(&header);
release:
// This also frees the mutex via the destructor
enif_release_resource(obj);
done:
return ret;
}
/*
crypto_secretstream_xchacha20poly1305_init_pull
(crypto_secretstream_xchacha20poly1305_state *state,
const unsigned char in[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary header, key;
enacl_secretstream_ctx *obj = NULL;
if (argc != 2) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[0], &header)) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[1], &key)) {
goto bad_arg;
}
if ((key.size != crypto_secretstream_xchacha20poly1305_KEYBYTES) ||
(header.size != crypto_secretstream_xchacha20poly1305_HEADERBYTES)) {
goto bad_arg;
}
if ((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
ret = enacl_internal_error(env);
goto done;
}
obj->alive = 0;
obj->state = enif_alloc(crypto_secretstream_xchacha20poly1305_statebytes());
if (obj->state == NULL) {
ret = enacl_internal_error(env);
goto release;
}
obj->alive = 1;
if ((obj->mtx = enif_mutex_create("enacl.secretstream")) == NULL) {
ret = enacl_internal_error(env);
goto free;
}
crypto_secretstream_xchacha20poly1305_init_pull(obj->state, header.data,
key.data);
ret = enif_make_resource(env, obj);
goto release;
bad_arg:
return enif_make_badarg(env);
free:
if (obj->alive)
if (obj->state != NULL) {
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
release:
// This also frees the mutex via the destructor
enif_release_resource(obj);
done:
return ret;
}
/*
void
crypto_secretstream_xchacha20poly1305_rekey
(crypto_secretstream_xchacha20poly1305_state *state)
*/
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_rekey(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
enacl_secretstream_ctx *obj = NULL;
if (argc != 1) {
goto bad_arg;
}
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
goto err;
}
crypto_secretstream_xchacha20poly1305_rekey(obj->state);
ret = enif_make_atom(env, ATOM_OK);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_error_finalized(env);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
/*
int
crypto_secretstream_xchacha20poly1305_push
(crypto_secretstream_xchacha20poly1305_state *state,
unsigned char *out, unsigned long long *outlen_p,
const unsigned char *m, unsigned long long mlen,
const unsigned char *ad, unsigned long long adlen, unsigned char tag)
*/
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_push(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary m, ad, out;
ErlNifUInt64 tag;
enacl_secretstream_ctx *obj = NULL;
if (argc != 4) {
goto bad_arg;
}
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[1], &m)) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[2], &ad)) {
goto bad_arg;
}
if (!enif_get_uint64(env, argv[3], &tag)) {
goto bad_arg;
}
if (!enif_alloc_binary(m.size + crypto_secretstream_xchacha20poly1305_ABYTES,
&out)) {
return enacl_internal_error(env);
}
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
goto err;
}
crypto_secretstream_xchacha20poly1305_push(obj->state, out.data, NULL, m.data,
m.size, ad.data, ad.size, tag);
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
if (obj->state) {
obj->alive = 0;
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
}
ret = enif_make_binary(env, &out);
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_error_finalized(env);
enif_release_binary(&out);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
/*
crypto_secretstream_xchacha20poly1305_pull
(crypto_secretstream_xchacha20poly1305_state *state,
unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
const unsigned char *in, unsigned long long inlen,
const unsigned char *ad, unsigned long long adlen)
*/
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_pull(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary m, in, ad;
unsigned char tag;
enacl_secretstream_ctx *obj = NULL;
if (argc != 3) {
goto bad_arg;
}
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[1], &in)) {
goto bad_arg;
}
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
goto bad_arg;
}
if (!enif_inspect_binary(env, argv[2], &ad)) {
goto bad_arg;
}
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
goto bad_arg;
}
if (!enif_alloc_binary(in.size - crypto_secretstream_xchacha20poly1305_ABYTES,
&m)) {
return enacl_internal_error(env);
}
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
goto err;
}
if (0 != crypto_secretstream_xchacha20poly1305_pull(obj->state, m.data, NULL,
&tag, in.data, in.size,
ad.data, ad.size)) {
ret = enacl_error_tuple(env, "failed_verification");
goto release;
}
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
if (obj->state) {
obj->alive = 0;
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
}
ret = enif_make_tuple2(env, enif_make_binary(env, &m),
enif_make_int64(env, tag));
goto done;
bad_arg:
return enif_make_badarg(env);
err:
ret = enacl_error_finalized(env);
release:
enif_release_binary(&m);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}

78
c_src/secretstream.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef ENACL_SECRETSTREAM_H
#define ENACL_SECRETSTREAM_H
#include <erl_nif.h>
int enacl_init_secretstream_ctx(ErlNifEnv *env);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_ABYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_keygen(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_rekey(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_push(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_pull(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
);
#endif

488
c_src/sign.c Normal file
View File

@ -0,0 +1,488 @@
#include <sodium.h>
#include <erl_nif.h>
#include "enacl.h"
#include "sign.h"
typedef struct enacl_sign_ctx {
ErlNifMutex *mtx;
crypto_sign_state *state; // The underlying signature state
int alive; // Is the context still valid for updates/finalization
} enacl_sign_ctx;
ErlNifResourceType *enacl_sign_ctx_rtype = NULL;
void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *);
int enacl_init_sign_ctx(ErlNifEnv *env) {
enacl_sign_ctx_rtype =
enif_open_resource_type(env, NULL, "enacl_sign_context",
(ErlNifResourceDtor *)enacl_sign_ctx_dtor,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
if (enacl_sign_ctx_rtype == NULL)
return 0;
return 1;
}
void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *obj) {
if (!obj->alive)
return;
if (obj->state) {
sodium_memzero(obj->state, crypto_sign_statebytes());
enif_free(obj->state);
}
if (obj->mtx != NULL)
enif_mutex_destroy(obj->mtx);
return;
}
/*
int crypto_sign_init(crypto_sign_state *state)
*/
ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
enacl_sign_ctx *obj = NULL;
if (argc != 0)
goto bad_arg;
if ((obj = enif_alloc_resource(enacl_sign_ctx_rtype,
sizeof(enacl_sign_ctx))) == NULL) {
ret = enacl_internal_error(env);
goto done;
}
obj->alive = 0;
obj->state = enif_alloc(crypto_sign_statebytes());
if (obj->state == NULL) {
ret = enacl_internal_error(env);
goto release;
}
obj->alive = 1;
if ((obj->mtx = enif_mutex_create("enacl.sign")) == NULL) {
goto free;
}
if (0 != crypto_sign_init(obj->state)) {
goto free;
}
// Create return values
ret = enif_make_resource(env, obj);
goto release;
bad_arg:
return enif_make_badarg(env);
free:
ret = enacl_internal_error(env);
if (obj->alive)
if (obj->state != NULL) {
sodium_memzero(obj->state, crypto_sign_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
release:
// This also frees the mutex via the destructor
enif_release_resource(obj);
done:
return ret;
}
/*
int crypto_sign_update(crypto_sign_state *state,
const unsigned char *m,
unsigned long long mlen);
*/
ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
enacl_sign_ctx *obj = NULL;
ErlNifBinary data;
// Validate the arguments
if (argc != 2)
goto bad_arg;
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &data))
goto bad_arg;
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
ret = enacl_error_finalized(env);
goto done;
}
if (0 != crypto_sign_update(obj->state, data.data, data.size)) {
ret = enacl_internal_error(env); // This should never be hit
goto done;
}
ret = argv[0];
goto done;
bad_arg:
return enif_make_badarg(env);
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM ret;
enacl_sign_ctx *obj = NULL;
ErlNifBinary sk, sig;
unsigned long long siglen;
if (argc != 2)
goto bad_arg;
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &sk))
goto bad_arg;
if (sk.size != crypto_sign_SECRETKEYBYTES)
goto bad_arg;
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
ret = enacl_error_finalized(env);
goto done;
}
if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
ret = enacl_internal_error(env);
goto done;
}
crypto_sign_final_create(obj->state, sig.data, &siglen, sk.data);
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM signature = enif_make_binary(env, &sig);
ret = enif_make_tuple2(env, ok, signature);
goto cleanup;
bad_arg:
return enif_make_badarg(env);
cleanup:
obj->alive = 0;
sodium_memzero(obj->state, crypto_sign_statebytes());
enif_free(obj->state);
obj->state = NULL;
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sig;
enacl_sign_ctx *obj = NULL;
ERL_NIF_TERM ret;
if (argc != 3)
goto bad_arg;
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
goto bad_arg;
if (!enif_inspect_binary(env, argv[1], &sig))
goto bad_arg;
if (!enif_inspect_binary(env, argv[2], &pk))
goto bad_arg;
if (pk.size != crypto_sign_PUBLICKEYBYTES)
goto bad_arg;
enif_mutex_lock(obj->mtx);
if (!obj->alive) {
ret = enacl_error_finalized(env);
goto done;
}
if (0 == crypto_sign_final_verify(obj->state, sig.data, pk.data)) {
ret = enif_make_atom(env, "true");
} else {
ret = enif_make_atom(env, "false");
}
// Mark as done
goto cleanup;
bad_arg:
return enif_make_badarg(env);
cleanup:
// Get rid of the context and mark it as dead
obj->alive = 0;
sodium_memzero(obj->state, crypto_sign_statebytes());
enif_free(obj->state);
obj->state = NULL;
done:
enif_mutex_unlock(obj->mtx);
return ret;
}
/* Ed 25519 */
ERL_NIF_TERM
enacl_crypto_sign_ed25519_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk;
if (argc != 0) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_sign_ed25519_PUBLICKEYBYTES, &pk)) {
return enacl_internal_error(env);
}
if (!enif_alloc_binary(crypto_sign_ed25519_SECRETKEYBYTES, &sk)) {
enif_release_binary(&pk);
return enacl_internal_error(env);
}
crypto_sign_ed25519_keypair(pk.data, sk.data);
return enif_make_tuple2(env, enif_make_binary(env, &pk),
enif_make_binary(env, &sk));
}
ERL_NIF_TERM
enacl_crypto_sign_ed25519_sk_to_pk(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk;
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &sk)) ||
(sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_sign_ed25519_PUBLICKEYBYTES, &pk)) {
return enacl_internal_error(env);
}
crypto_sign_ed25519_sk_to_pk(pk.data, sk.data);
return enif_make_binary(env, &pk);
}
ERL_NIF_TERM
enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary curve25519_pk, ed25519_pk;
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &ed25519_pk)) ||
(ed25519_pk.size != crypto_sign_ed25519_PUBLICKEYBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_pk)) {
return enacl_internal_error(env);
}
if (crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data) != 0) {
return enacl_internal_error(env);
}
return enif_make_binary(env, &curve25519_pk);
}
ERL_NIF_TERM
enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary curve25519_sk, ed25519_sk;
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &ed25519_sk)) ||
(ed25519_sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_sk)) {
return enacl_internal_error(env);
}
crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.data, ed25519_sk.data);
return enif_make_binary(env, &curve25519_sk);
}
ERL_NIF_TERM
enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_sign_ed25519_PUBLICKEYBYTES);
}
ERL_NIF_TERM
enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_sign_ed25519_SECRETKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_sign_PUBLICKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_sign_SECRETKEYBYTES);
}
ERL_NIF_TERM enacl_crypto_sign_SEEDBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_sign_SEEDBYTES);
}
ERL_NIF_TERM enacl_crypto_sign_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk;
if (argc != 0) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
return enacl_internal_error(env);
}
if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
enif_release_binary(&pk);
return enacl_internal_error(env);
}
crypto_sign_keypair(pk.data, sk.data);
return enif_make_tuple2(env, enif_make_binary(env, &pk),
enif_make_binary(env, &sk));
}
ERL_NIF_TERM enacl_crypto_sign_seed_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary pk, sk, seed;
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &seed))) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
return enacl_internal_error(env);
}
if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
enif_release_binary(&pk);
return enacl_internal_error(env);
}
crypto_sign_seed_keypair(pk.data, sk.data, seed.data);
return enif_make_tuple2(env, enif_make_binary(env, &pk),
enif_make_binary(env, &sk));
}
ERL_NIF_TERM enacl_crypto_sign(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary m, sk, sm;
unsigned long long smlen;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &sk))) {
return enif_make_badarg(env);
}
if (sk.size != crypto_sign_SECRETKEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size + crypto_sign_BYTES, &sm)) {
return enacl_internal_error(env);
}
crypto_sign(sm.data, &smlen, m.data, m.size, sk.data);
return enif_make_sub_binary(env, enif_make_binary(env, &sm), 0, smlen);
}
ERL_NIF_TERM enacl_crypto_sign_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary m, sm, pk;
unsigned long long mlen;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &sm)) ||
(!enif_inspect_binary(env, argv[1], &pk))) {
return enif_make_badarg(env);
}
if (pk.size != crypto_sign_PUBLICKEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(sm.size, &m)) {
return enacl_internal_error(env);
}
if (0 == crypto_sign_open(m.data, &mlen, sm.data, sm.size, pk.data)) {
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin =
enif_make_sub_binary(env, enif_make_binary(env, &m), 0, mlen);
return enif_make_tuple2(env, ret_ok, ret_bin);
} else {
enif_release_binary(&m);
return enacl_error_tuple(env, "failed_verification");
}
}
ERL_NIF_TERM enacl_crypto_sign_detached(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary m, sk, sig;
unsigned long long siglen;
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &sk))) {
return enif_make_badarg(env);
}
if (sk.size != crypto_sign_SECRETKEYBYTES) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
return enacl_internal_error(env);
}
crypto_sign_detached(sig.data, &siglen, m.data, m.size, sk.data);
return enif_make_binary(env, &sig);
}
ERL_NIF_TERM
enacl_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary m, sig, pk;
if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &sig)) ||
(!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
(!enif_inspect_binary(env, argv[2], &pk))) {
return enif_make_badarg(env);
}
if (sig.size != crypto_sign_BYTES) {
return enif_make_badarg(env);
}
if (pk.size != crypto_sign_PUBLICKEYBYTES) {
return enif_make_badarg(env);
}
if (0 == crypto_sign_verify_detached(sig.data, m.data, m.size, pk.data)) {
return enif_make_atom(env, ATOM_TRUE);
} else {
return enif_make_atom(env, ATOM_FALSE);
}
}

70
c_src/sign.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef ENACL_SIGN_H
#define ENACL_SIGN_H
#include <erl_nif.h>
int enacl_init_sign_ctx(ErlNifEnv *env);
ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_ed25519_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_ed25519_sk_to_pk(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_SEEDBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_seed_keypair(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_sign_detached(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enacl_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

View File

@ -1,6 +1,6 @@
-module(enacl_eqc).
-include_lib("eqc/include/eqc.hrl").
-compile(export_all).
-compile([export_all, nowarn_export_all]).
-ifndef(mini).
-compile({parse_transform, eqc_parallelize}).
@ -83,8 +83,8 @@ v_binary(_, _) -> false.
%% Typical generators based on the binaries
nonce() -> g_binary(enacl:box_nonce_size()).
nonce_valid(N) -> v_binary(enacl:box_nonce_size(), N).
nonce() -> g_binary(enacl:box_NONCEBYTES()).
nonce_valid(N) -> v_binary(enacl:box_NONCEBYTES(), N).
%% Generator of natural numbers
g_nat() ->
@ -111,10 +111,10 @@ keypair_bad() ->
#{ public := PK, secret := SK} = enacl:box_keypair(),
case X of
pk ->
PKBytes = enacl:box_public_key_bytes(),
PKBytes = enacl:box_PUBLICKEYBYTES(),
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
sk ->
SKBytes = enacl:box_secret_key_bytes(),
SKBytes = enacl:box_SECRETKEYBYTES(),
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
end
end).
@ -122,6 +122,35 @@ keypair_bad() ->
keypair() ->
?FAULT(keypair_bad(), keypair_good()).
kx_keypair_good() ->
#{ public := PK, secret := SK} = enacl:kx_keypair(),
{PK, SK}.
kx_keypair_bad() ->
?LET(X, elements([pk, sk]),
begin
#{ public := PK, secret := SK} = enacl:box_keypair(),
case X of
pk ->
PKBytes = enacl:kx_public_key_size(),
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
sk ->
SKBytes = enacl:kx_secret_key_size(),
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
end
end).
g_generichash_data() ->
binary().
g_generichash_key() ->
?LET({Min, Max}, {return(enacl_nif:crypto_generichash_KEYBYTES_MIN()), return(enacl_nif:crypto_generichash_KEYBYTES_MAX())},
largebinary({limit, Min, Max})).
g_generichash_size() ->
?LET({Min, Max}, {return(enacl_nif:crypto_generichash_BYTES_MIN()), return(enacl_nif:crypto_generichash_BYTES_MAX())},
choose(Min, Max)).
%% CRYPTO BOX
%% ---------------------------
%% * box/4
@ -130,8 +159,8 @@ keypair() ->
%% * box_afternm/3
%% * box_open_afternm/3
keypair_valid(PK, SK) when is_binary(PK), is_binary(SK) ->
PKBytes = enacl:box_public_key_bytes(),
SKBytes = enacl:box_secret_key_bytes(),
PKBytes = enacl:box_PUBLICKEYBYTES(),
SKBytes = enacl:box_SECRETKEYBYTES(),
byte_size(PK) == PKBytes andalso byte_size(SK) == SKBytes;
keypair_valid(_PK, _SK) -> false.
@ -235,11 +264,11 @@ beforenm_key() ->
oneof([
elements([a,b,c]),
real(),
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_beforenm_bytes())
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_BEFORENMBYTES())
])
end).
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_beforenm_bytes();
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_BEFORENMBYTES();
v_key(_) -> false.
prop_beforenm_correct() ->
@ -295,11 +324,11 @@ sign_keypair_bad() ->
KP = enacl:sign_keypair(),
case X of
pk ->
Sz = enacl:sign_keypair_public_size(),
Sz = enacl:sign_PUBLICBYTES(),
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
KP#{ public := Wrong });
sk ->
Sz = enacl:sign_keypair_secret_size(),
Sz = enacl:sign_SECRETBYTES(),
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
KP#{ secret := Wrong })
end
@ -313,12 +342,12 @@ sign_keypair() ->
sign_keypair_public_valid(#{ public := Public })
when is_binary(Public) ->
byte_size(Public) == enacl:sign_keypair_public_size();
byte_size(Public) == enacl:sign_PUBLICBYTES();
sign_keypair_public_valid(_) -> false.
sign_keypair_secret_valid(#{ secret := Secret })
when is_binary(Secret) ->
byte_size(Secret) == enacl:sign_keypair_secret_size();
byte_size(Secret) == enacl:sign_SECRETBYTES();
sign_keypair_secret_valid(_) -> false.
sign_keypair_valid(KP) ->
@ -379,18 +408,18 @@ signed_message_good_d(M) ->
end)}]).
signed_message_bad() ->
Sz = enacl:sign_keypair_public_size(),
Sz = enacl:sign_PUBLICBYTES(),
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
signed_message_bad_d() ->
Sz = enacl:sign_keypair_public_size(),
Sz = enacl:sign_PUBLICBYTES(),
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
signed_message(M) ->
?FAULT(signed_message_bad(), signed_message_good(M)).
signed_message_d(M) ->
?FAULT(signed_message_bad(), signed_message_good(M)).
?FAULT(signed_message_bad_d(), signed_message_good_d(M)).
signed_message_valid({valid, _}, _) -> true;
signed_message_valid({invalid, _}, _) -> true;
@ -403,9 +432,9 @@ prop_sign_detached_open() ->
true ->
case SignMsg of
{valid, Sig} ->
equals({ok, Msg}, enacl:sign_verify_detached(Sig, Msg, PK));
equals(true, enacl:sign_verify_detached(Sig, Msg, PK));
{invalid, Sig} ->
equals({error, failed_verification}, enacl:sign_verify_detached(Sig, Msg, PK))
equals(false, enacl:sign_verify_detached(Sig, Msg, PK))
end;
false ->
badargs(fun() -> enacl:sign_verify_detached(SignMsg, Msg, PK) end)
@ -467,19 +496,19 @@ prop_seal_box_correct() ->
%% * secretbox/3
%% * secretbo_open/3
secret_key_good() ->
Sz = enacl:secretbox_key_size(),
Sz = enacl:secretbox_KEYBYTES(),
binary(Sz).
secret_key_bad() ->
oneof([return(a),
nat(),
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_key_size())]).
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_KEYBYTES())]).
secret_key() ->
?FAULT(secret_key_bad(), secret_key_good()).
secret_key_valid(SK) when is_binary(SK) ->
Sz = enacl:secretbox_key_size(),
Sz = enacl:secretbox_KEYBYTES(),
byte_size(SK) == Sz;
secret_key_valid(_SK) -> false.
@ -521,24 +550,87 @@ prop_secretbox_failure_integrity() ->
equals(Err, {error, failed_verification})
end).
secretbox_easy(Msg, Nonce, Key) ->
try enacl:secretbox_easy(Msg, Nonce, Key)
catch error:badarg -> badarg
end.
secretbox_open_easy(Msg, Nonce, Key) ->
try enacl:secretbox_open_easy(Msg, Nonce, Key)
catch error:badarg -> badarg
end.
prop_secretbox_easy_correct() ->
?FORALL({Msg, Nonce, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, secret_key())},
begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of
true ->
CipherText = enacl:secretbox_easy(Msg, Nonce, Key),
{ok, DecodedMsg} = enacl:secretbox_open_easy(CipherText, Nonce, Key),
equals(iolist_to_binary(Msg), DecodedMsg);
false ->
case secretbox_easy(Msg, Nonce, Key) of
badarg -> true;
Res ->
failure(secretbox_open_easy(Res, Nonce, Key))
end
end
end).
prop_secretbox_easy_failure_integrity() ->
?FORALL({Msg, Nonce, Key}, {g_iodata(), nonce(), secret_key()},
begin
CipherText = enacl:secretbox_easy(Msg, Nonce, Key),
Err = enacl:secretbox_open_easy([<<"x">>, CipherText], Nonce, Key),
equals(Err, {error, failed_verification})
end).
%% AEAD ChaCha20Poly1305
%% ------------------------------------------------------------
%% * aead_chacha20poly1305_encrypt/4,
%% * aead_chacha20poly1305_decrypt/4,
prop_aead_chacha20poly1305() ->
prop_aead_chacha20poly1305_ietf() ->
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), largeint()},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
EncryptMsg = enacl:aead_chacha20poly1305_encrypt(Key, Nonce, AD, Msg),
equals(enacl:aead_chacha20poly1305_decrypt(Key, Nonce, AD, EncryptMsg), Msg)
EncryptMsg = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
equals(enacl:aead_chacha20poly1305_ietf_decrypt(EncryptMsg, AD, Nonce, Key), Msg)
end).
prop_aead_chacha20poly1305_fail() ->
prop_aead_chacha20poly1305_ietf_fail() ->
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), largeint()},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
EncryptMsg = enacl:aead_chacha20poly1305_encrypt(Key, Nonce, AD, Msg),
case enacl:aead_chacha20poly1305_decrypt(Key, Nonce, AD, <<0:8, EncryptMsg/binary>>) of
EncryptMsg = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
case enacl:aead_chacha20poly1305_ietf_decrypt(<<0:8, EncryptMsg/binary>>, AD, Nonce, Key) of
{error, _} -> true;
_ -> false
end
end).
%% * aead_xchacha20poly1305_encrypt/4,
%% * aead_xchacha20poly1305_decrypt/4,
prop_aead_xchacha20poly1305_ietf() ->
NPubBytes = enacl:aead_xchacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
EncryptMsg = enacl:aead_xchacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
equals(enacl:aead_xchacha20poly1305_ietf_decrypt(EncryptMsg, AD, Nonce, Key), Msg)
end).
prop_aead_xchacha20poly1305_ietf_fail() ->
NPubBytes = enacl:aead_xchacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
EncryptMsg = enacl:aead_xchacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
case enacl:aead_xchacha20poly1305_ietf_decrypt(<<0:8, EncryptMsg/binary>>, AD, Nonce, Key) of
{error, _} -> true;
_ -> false
end
@ -564,23 +656,26 @@ xor_bytes(<<A, As/binary>>, <<B, Bs/binary>>) ->
[A bxor B | xor_bytes(As, Bs)];
xor_bytes(<<>>, <<>>) -> [].
%% prop_stream_xor_correct() ->
%% ?FORALL({Msg, Nonce, Key},
%% {?FAULT_RATE(1, 40, g_iodata()),
%% ?FAULT_RATE(1, 40, nonce()),
%% ?FAULT_RATE(1, 40, secret_key())},
%% case v_iodata(Msg) andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of
%% true ->
%% Stream = enacl:stream(iolist_size(Msg), Nonce, Key),
%% CipherText = enacl:stream_xor(Msg, Nonce, Key),
%% StreamXor = enacl:stream_xor(CipherText, Nonce, Key),
%% conjunction([
%% {'xor', equals(iolist_to_binary(Msg), StreamXor)},
%% {stream, equals(iolist_to_binary(xor_bytes(Stream, iolist_to_binary(Msg))), CipherText)}
%% ]);
%% false ->
%% badargs(fun() -> enacl:stream_xor(Msg, Nonce, Key) end)
%% end).
positive() ->
?LET(N, nat(), N+1).
chacha20_nonce() ->
Sz = enacl:stream_chacha20_NONCEBYTES(),
binary(Sz).
chacha20_key() ->
Sz = enacl:stream_chacha20_KEYBYTES(),
binary(Sz).
prop_stream_chacha20_correct() ->
?FORALL(Len, positive(),
?FORALL({Msg, Nonce, Key}, {binary(Len), chacha20_nonce(), chacha20_key()},
begin
CT = enacl:stream_chacha20_xor(Msg, Nonce, Key),
Stream = enacl:stream_chacha20(Len, Nonce, Key),
CT2 = list_to_binary(xor_bytes(Stream, Msg)),
equals(CT, CT2)
end)).
%% CRYPTO AUTH
%% ------------------------------------------------------------
@ -599,19 +694,19 @@ prop_auth_correct() ->
end).
authenticator_bad() ->
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_size())]).
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_BYTES())]).
authenticator_good(Msg, Key) when is_binary(Key) ->
Sz = enacl:secretbox_key_size(),
Sz = enacl:secretbox_KEYBYTES(),
case v_iodata(Msg) andalso byte_size(Key) == Sz of
true ->
frequency([{1, ?LAZY({invalid, binary(enacl:auth_size())})},
frequency([{1, ?LAZY({invalid, binary(enacl:auth_BYTES())})},
{3, return({valid, enacl:auth(Msg, Key)})}]);
false ->
binary(enacl:auth_size())
binary(enacl:auth_BYTES())
end;
authenticator_good(_Msg, _Key) ->
binary(enacl:auth_size()).
binary(enacl:auth_BYTES()).
authenticator(Msg, Key) ->
?FAULT(authenticator_bad(), authenticator_good(Msg, Key)).
@ -654,19 +749,19 @@ prop_onetimeauth_correct() ->
end).
ot_authenticator_bad() ->
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_size())]).
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_BYTES())]).
ot_authenticator_good(Msg, Key) when is_binary(Key) ->
Sz = enacl:secretbox_key_size(),
Sz = enacl:secretbox_KEYBYTES(),
case v_iodata(Msg) andalso byte_size(Key) == Sz of
true ->
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_size())})},
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_BYTES())})},
{3, return({valid, enacl:onetime_auth(Msg, Key)})}]);
false ->
binary(enacl:onetime_auth_size())
binary(enacl:onetime_auth_BYTES())
end;
ot_authenticator_good(_Msg, _Key) ->
binary(enacl:auth_size()).
binary(enacl:auth_BYTES()).
ot_authenticator(Msg, Key) ->
?FAULT(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
@ -704,6 +799,13 @@ pwhash(Passwd, Salt) ->
error:badarg -> badarg
end.
pwhash(Password, Salt, Ops, Mem, Alg) ->
try
enacl:pwhsah(Password, Salt, Ops, Mem, Alg)
catch
error:badarg -> badarg
end.
pwhash_str(Passwd) ->
try
enacl:pwhash_str(Passwd)
@ -718,13 +820,29 @@ pwhash_str_verify(PasswdHash, Passwd) ->
error:badarg -> badarg
end.
prop_pwhash() ->
?FORALL({Password, Salt, OLimit, MLimit, Alg},
{binary(16),
binary(16),
elements([interactive, moderate]), %% These could add senstitive, but are too runtime-expensive
elements([interactive, moderate]), %% And that is for a reason.
elements([default, 'argon2id13'])}, %% Argon2I13 uses different limits, so it is kept out as
%% this would otherwise fail
begin
Bin1 = enacl:pwhash(Password, Salt, OLimit, MLimit, Alg),
Bin2 = enacl:pwhash(Password, Salt, OLimit, MLimit, Alg),
equals(Bin1, Bin2)
end).
prop_pwhash_str_verify() ->
?FORALL({Passwd},
{?FAULT_RATE(1, 40, g_iodata())},
?FORALL({Passwd, OLimit, MLimit},
{?FAULT_RATE(1, 40, g_iodata()),
elements([interactive, moderate]),
elements([interactive, moderate])},
begin
case v_iodata(Passwd) of
true ->
{ok, Ascii} = enacl:pwhash_str(Passwd),
Ascii = enacl:pwhash_str(Passwd, OLimit, MLimit),
S = enacl:pwhash_str_verify(Ascii, Passwd),
equals(S, true);
false ->
@ -758,6 +876,41 @@ prop_crypto_hash_neq() ->
enacl:hash(X) /= enacl:hash(Y)
).
prop_crypto_shorthash_eq() ->
?FORALL(X, g_iodata(),
case v_iodata(X) of
true -> equals(enacl:hash(X), enacl:hash(X));
false ->
try
enacl:hash(X),
false
catch
error:badarg -> true
end
end
).
prop_crypto_generichash_eq() ->
?FORALL({Sz, X, Key}, {g_generichash_size(), g_generichash_data(), g_generichash_key()},
equals(enacl:generichash(Sz, X, Key), enacl:generichash(Sz, X, Key))).
generichash_loop(S, []) -> S;
generichash_loop(S, [M|Ms]) ->
S2 = enacl:generichash_update(S, M),
generichash_loop(S2, Ms).
prop_crypto_generichash_multi_part_eq() ->
?FORALL({Sz, Xs, Key}, {g_generichash_size(), list(g_generichash_data()), g_generichash_key()},
begin
S1 = generichash_loop(enacl:generichash_init(Sz, Key), Xs),
S2 = generichash_loop(enacl:generichash_init(Sz, Key), Xs),
equals(enacl:generichash_final(S1), enacl:generichash_final(S2))
end).
prop_crypto_shorthash_neq() ->
?FORALL({X, Y}, diff_pair(),
enacl:hash(X) /= enacl:hash(Y)
).
%% STRING COMPARISON
%% -------------------------
%% * verify_16/2,
@ -817,7 +970,8 @@ prop_randombytes() ->
?FORALL(X, g_nat(),
case is_nat(X) of
true ->
is_binary(enacl:randombytes(X));
R = enacl:randombytes(X),
is_binary(R) andalso (byte_size(R) == X);
false ->
try
enacl:randombytes(X),
@ -828,8 +982,84 @@ prop_randombytes() ->
end
end).
prop_randombytes_uint32() ->
?FORALL(_, return(x),
begin
V = enacl:randombytes_uint32(),
is_integer(V)
end).
%% KX
%% ---------------------------
prop_kx() ->
?FORALL({{CPK, CSK}, {SPK, SSK}}, {kx_keypair_good(), kx_keypair_good()},
begin
#{ client_tx := CTX, client_rx := CRX} = enacl:kx_client_session_keys(CPK, CSK, SPK),
#{ server_tx := STX, server_rx := SRX} = enacl:kx_server_session_keys(SPK, SSK, CPK),
%% This keypair must be shared in both directions
conjunction([{ctx_srx, equals(CTX, SRX)}, {stx_crx, equals(STX, CRX)}])
end).
%% SCRAMBLING
prop_scramble_block() ->
?FORALL({Block, Key}, {binary(16), eqc_gen:largebinary(32)},
is_binary(enacl_ext:scramble_block_16(Block, Key))).
%% Scala multiplication
prop_scalarmult() ->
Bytes = 32,
?FORALL({S1, S2, Basepoint}, {binary(Bytes), binary(Bytes), binary(Bytes)},
equals(enacl:curve25519_scalarmult(S1,
enacl:curve25519_scalarmult(S2, Basepoint)),
enacl:curve25519_scalarmult(S2,
enacl:curve25519_scalarmult(S1, Basepoint)))
).
%% Secretstream
secretstream_key() ->
?LET(K, enacl:secretstream_xchacha20poly1305_keygen(), K).
secretstream_msg() ->
?LET({Tag, AD, Msg}, {oneof([message,rekey,push]), binary(), binary()},
{Tag, AD, Msg}).
secretstream_msgs() ->
?LET({Ms, {_, AD, Msg}}, {list(secretstream_msg()), secretstream_msg()},
Ms ++ [{final, AD, Msg}]).
push_messages(_State, []) ->
[];
push_messages(State, [{Tag, AD, Msg}|Next]) ->
Block = enacl:secretstream_xchacha20poly1305_push(State, Msg, AD, Tag),
[Block|push_messages(State, Next)].
pull_messages(_State, [], []) ->
true;
pull_messages(State, [B|Bs], [{_Tag, AD, _Msg}=Expect|Next]) ->
{Msgx, Tagx} = enacl:secretstream_xchacha20poly1305_pull(State, B, AD),
case equals(Expect, {Tagx, AD, Msgx}) of
true ->
pull_messages(State, Bs, Next);
R ->
R
end.
prop_secretstream() ->
?FORALL({Key, Msgs}, {secretstream_key(), secretstream_msgs()},
begin
%% Encrypt
{Header, State} = enacl:secretstream_xchacha20poly1305_init_push(Key),
Blocks = push_messages(State, Msgs),
%% Decrypt & Verify
DState = enacl:secretstream_xchacha20poly1305_init_pull(Header, Key),
pull_messages(DState, Blocks, Msgs)
end).
%% HELPERS
%% INTERNAL FUNCTIONS
%% ------------------------------------------------------------
badargs(Thunk) ->
try
Thunk(),

View File

@ -1,7 +1,8 @@
-module(enacl_ext_eqc).
-include_lib("eqc/include/eqc.hrl").
-compile(export_all).
-compile({parse_transform, eqc_parallelize}).
-compile([export_all, nowarn_export_all]).
public_keypair() ->
?LET(#{ public := PK, secret := SK}, enacl_ext:curve25519_keypair(),

View File

@ -1,9 +1,39 @@
{erl_opts, [debug_info]}.
{pre_hooks, [{"freebsd", compile, "gmake -C c_src"},
{"freebsd", clean, "gmake -C c_src clean"},
{"netbsd", compile, "gmake -C c_src"},
{"netbsd", clean, "gmake -C c_src clean"},
{"(linux|darwin|solaris)", compile, "make -C c_src"},
{"(linux|darwin|solaris)", clean, "make -C c_src clean"}
{plugins, [pc]}.
{project_plugins, [rebar3_hex]}.
{provider_hooks, [
{pre, [
{compile, {pc, compile}},
{clean, {pc, clean}}
]}
]}.
{port_specs, [
{"priv/enacl_nif.so", [
"c_src/*.c"
]}
]}.
{port_env, [
{"darwin", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes"},
{"darwin", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"},
{"darwin", "LDFLAGS", "$LDFLAGS -flat_namespace -undefined suppress -lsodium"},
{"linux", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes"},
{"linux", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"},
{"linux", "LDFLAGS", "$LDFLAGS -lsodium"},
{"freebsd", "CFLAGS", "$CFLAGS -fPIC -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -I /usr/local/include"},
{"freebsd", "CXXFLAGS", "$CXXFLAGS -fPIC -O3 -finline-functions -Wall"},
{"freebsd", "LDFLAGS", "$LDFLAGS -fPIC -L /usr/local/lib -lsodium"},
{"solaris", "CFLAGS", "$CFLAGS -fPIC -m64 -I/opt/local/include -O2 -std=c99 -finline-functions -Wall -Wmissing-prototypes"},
{"solaris", "CXXFLAGS", "$CXXFLAGS -fPIC -O2 -finline-function -Wall"},
{"solaris", "LDFLAGS", "$LDFLAGS -m64 -fPIC -L /opt/local/lib -lsodium"},
{"win32", "CFLAGS", "$CFLAGS /LD /O2 /DNDEBUG"},
{"win32", "LDFLAGS", "$LDFLAGS libsodium.dll.a"}
]}.

12
shell.nix Normal file
View File

@ -0,0 +1,12 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.hello
# keep this line if you use bash
pkgs.bashInteractive
pkgs.erlang
pkgs.libsodium
];
}

View File

@ -1,6 +1,6 @@
{application,enacl,
[{description,"Erlang libsodium (NaCl) bindings"},
{vsn,"0.17.1"},
{vsn,"1.2.1"},
{registered,[]},
{applications,[kernel,stdlib]},
{env,[]},

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,10 @@
crypto_sign_PUBLICKEYBYTES/0,
crypto_sign_SECRETKEYBYTES/0,
crypto_sign_SEEDBYTES/0,
crypto_sign_keypair/0,
crypto_sign_seed_keypair/1,
crypto_sign/2,
crypto_sign_open/2,
@ -34,6 +36,11 @@
crypto_sign_detached/2,
crypto_sign_verify_detached/3,
crypto_sign_init/0,
crypto_sign_update/2,
crypto_sign_final_create/2,
crypto_sign_final_verify/3,
crypto_box_seal/2,
crypto_box_seal_open/3,
crypto_box_SEALBYTES/0
@ -50,6 +57,10 @@
crypto_secretbox_b/3,
crypto_secretbox_open/3,
crypto_secretbox_open_b/3,
crypto_secretbox_easy/3,
crypto_secretbox_easy_b/3,
crypto_secretbox_open_easy/3,
crypto_secretbox_open_easy_b/3,
crypto_stream_chacha20_KEYBYTES/0,
crypto_stream_chacha20_NONCEBYTES/0,
@ -67,12 +78,19 @@
crypto_stream_xor/3,
crypto_stream_xor_b/3,
crypto_aead_chacha20poly1305_encrypt/4,
crypto_aead_chacha20poly1305_decrypt/4,
crypto_aead_chacha20poly1305_KEYBYTES/0,
crypto_aead_chacha20poly1305_NPUBBYTES/0,
crypto_aead_chacha20poly1305_ABYTES/0,
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX/0,
crypto_aead_chacha20poly1305_ietf_encrypt/4,
crypto_aead_chacha20poly1305_ietf_decrypt/4,
crypto_aead_chacha20poly1305_ietf_KEYBYTES/0,
crypto_aead_chacha20poly1305_ietf_NPUBBYTES/0,
crypto_aead_chacha20poly1305_ietf_ABYTES/0,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX/0,
crypto_aead_xchacha20poly1305_ietf_encrypt/4,
crypto_aead_xchacha20poly1305_ietf_decrypt/4,
crypto_aead_xchacha20poly1305_ietf_KEYBYTES/0,
crypto_aead_xchacha20poly1305_ietf_NPUBBYTES/0,
crypto_aead_xchacha20poly1305_ietf_ABYTES/0,
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX/0,
crypto_auth_BYTES/0,
crypto_auth_KEYBYTES/0,
@ -105,6 +123,7 @@
%% Ed 25519
-export([
crypto_sign_ed25519_keypair/0,
crypto_sign_ed25519_sk_to_pk/1,
crypto_sign_ed25519_public_to_curve25519/1,
crypto_sign_ed25519_secret_to_curve25519/1,
crypto_sign_ed25519_PUBLICKEYBYTES/0,
@ -132,11 +151,19 @@
%% Password Hashing - Argon2 Algorithm
-export([
crypto_pwhash/2,
crypto_pwhash_str/1,
crypto_pwhash_SALTBYTES/0,
crypto_pwhash/5,
crypto_pwhash_str/3,
crypto_pwhash_str_verify/2
]).
%% Key Derivation
-export([
crypto_kdf_KEYBYTES/0,
crypto_kdf_CONTEXTBYTES/0,
crypto_kdf_derive_from_key/3
]).
%% Generic hash
-export([
crypto_generichash_BYTES/0,
@ -147,13 +174,33 @@
crypto_generichash_KEYBYTES_MAX/0,
crypto_generichash/3,
crypto_generichash_init/2,
crypto_generichash_update/3,
crypto_generichash_final/2
crypto_generichash_update/2,
crypto_generichash_final/1
]).
%% Secretstream
-export([
crypto_secretstream_xchacha20poly1305_ABYTES/0,
crypto_secretstream_xchacha20poly1305_HEADERBYTES/0,
crypto_secretstream_xchacha20poly1305_KEYBYTES/0,
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX/0,
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE/0,
crypto_secretstream_xchacha20poly1305_TAG_PUSH/0,
crypto_secretstream_xchacha20poly1305_TAG_REKEY/0,
crypto_secretstream_xchacha20poly1305_TAG_FINAL/0,
crypto_secretstream_xchacha20poly1305_keygen/0,
crypto_secretstream_xchacha20poly1305_init_push/1,
crypto_secretstream_xchacha20poly1305_push/4,
crypto_secretstream_xchacha20poly1305_init_pull/2,
crypto_secretstream_xchacha20poly1305_pull/3,
crypto_secretstream_xchacha20poly1305_rekey/1
]).
%% Access to the RNG
-export([
randombytes/1
randombytes/1,
randombytes_uint32/0,
randombytes_uniform/1
]).
%% Undocumented features :>
@ -185,13 +232,33 @@ crypto_generichash_KEYBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_generichash(_HashSize, _Message, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_init(_HashSize, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_update(_HashSize, _HashState, _Message) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_final(_HashSize, _HashState) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_update(_HashState, _Message) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_final(_HashState) -> erlang:nif_error(nif_not_loaded).
crypto_pwhash(_Password, _Salt) -> erlang:nif_error(nif_not_loaded).
crypto_pwhash_str(_Password) -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_HEADERBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_TAG_PUSH() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_TAG_REKEY() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_TAG_FINAL() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_keygen() -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_init_push(_Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_push(_Ref, _Message, _AD, _Tag) -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_init_pull(_Header, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_pull(_Ref, _CipherText, _AD) -> erlang:nif_error(nif_not_loaded).
crypto_secretstream_xchacha20poly1305_rekey(_Ref) -> erlang:nif_error(nif_not_loaded).
crypto_pwhash_SALTBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_pwhash(_Password, _Salt, _Ops, _Mem, _Alg) -> erlang:nif_error(nif_not_loaded).
crypto_pwhash_str(_Password, _Ops, _Mem) -> erlang:nif_error(nif_not_loaded).
crypto_pwhash_str_verify(_HashedPassword, _Password) -> erlang:nif_error(nif_not_loaded).
crypto_kdf_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_kdf_CONTEXTBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_kdf_derive_from_key(_MasterKey, _Context, _Id) -> erlang:nif_error(nif_not_loaded).
crypto_box_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_box_ZEROBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_box_BOXZEROBYTES() -> erlang:nif_error(nif_not_loaded).
@ -211,8 +278,10 @@ crypto_box_open_afternm_b(_CipherText, _Nonce, _K) -> erlang:nif_error(nif_not_l
crypto_sign_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_sign_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_sign_SEEDBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_sign_keypair() -> erlang:nif_error(nif_not_loaded).
crypto_sign_seed_keypair(_S) -> erlang:nif_error(nif_not_loaded).
crypto_sign(_M, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_open(_SignedMessage, _PK) -> erlang:nif_error(nif_not_loaded).
@ -220,6 +289,11 @@ crypto_sign_detached(_M, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_verify_detached(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_init() -> erlang:nif_error(nif_not_loaded).
crypto_sign_update(_S, _M) -> erlang:nif_error(nif_not_loaded).
crypto_sign_final_create(_S, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_final_verify(_State, _Sig, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal(_Msg, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal_open(_CipherText, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_SEALBYTES() -> erlang:nif_error(nif_not_loaded).
@ -233,6 +307,10 @@ crypto_secretbox(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
@ -248,12 +326,19 @@ crypto_stream_b(_Bytes, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_xor(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_xor_b(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_encrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_decrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_NPUBBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_encrypt(_Message, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_decrypt(_CipherText, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_NPUBBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_ABYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_encrypt(_Message, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_decrypt(_CipherText, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_NPUBBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_ABYTES() -> erlang:nif_error(nif_not_loaded).
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_auth_BYTES() -> erlang:nif_error(nif_not_loaded).
crypto_auth_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
@ -277,6 +362,7 @@ crypto_curve25519_scalarmult(_Secret, _BasePoint) -> erlang:nif_error(nif_not_lo
crypto_curve25519_scalarmult_base(_Secret) -> erlang:nif_error(nif_not_loaded).
crypto_sign_ed25519_keypair() -> erlang:nif_error(nif_not_loaded).
crypto_sign_ed25519_sk_to_pk(_SecretKey) -> erlang:nif_error(nif_not_loaded).
crypto_sign_ed25519_public_to_curve25519(_PublicKey) -> erlang:nif_error(nif_not_loaded).
crypto_sign_ed25519_secret_to_curve25519(_SecretKey) -> erlang:nif_error(nif_not_loaded).
crypto_sign_ed25519_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
@ -296,5 +382,7 @@ crypto_kx_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_kx_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded).
randombytes(_RequestedSize) -> erlang:nif_error(nif_not_loaded).
randombytes_uint32() -> erlang:nif_error(nif_not_loaded).
randombytes_uniform(_UpperBound) -> erlang:nif_error(nif_not_loaded).
scramble_block_16(_Block, _Key) -> erlang:nif_error(nif_not_loaded).

196
test/enacl_SUITE.erl Normal file
View File

@ -0,0 +1,196 @@
-module(enacl_SUITE).
-include_lib("common_test/include/ct.hrl").
-compile([export_all, nowarn_export_all]).
suite() ->
[{timetrap, {seconds, 30}}].
init_per_group(_Group, Config) ->
Config.
end_per_group(_Group, _Config) ->
ok.
init_per_suite(Config) ->
application:ensure_all_started(enacl),
Config.
end_per_suite(_Config) ->
application:stop(enacl),
ok.
init_per_testcase(x, Config) ->
{ok, _} = dbg:tracer(),
dbg:p(all, c),
dbg:tpl(graphql_execute, lookup_field, '_', cx),
Config;
init_per_testcase(_Case, Config) ->
Config.
end_per_testcase(x, _Config) ->
dbg:stop_clear(),
ok;
end_per_testcase(_Case, _Config) ->
ok.
groups() ->
Neg = {negative, [shuffle, parallel],
[generichash_basic_neg]},
Pos = {positive, [shuffle, parallel],
[
aead_chacha20poly1305_ietf,
aead_xchacha20poly1305,
generichash_basic_pos,
generichash_chunked,
kx,
pwhash,
secretstream,
sign,
verify_detached
]},
[Neg, Pos].
all() ->
[{group, negative},
{group, positive}].
%% -- BASIC --------------------------------------
generichash_basic_neg(_Config) ->
%% Negative generichash invocations
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
"All those... moments... will be lost... in time, like... tears... in rain">>,
Key = <<"Hash Key 123456789">>,
{'EXIT', {badarg, _}} = (catch enacl:generichash(9, Msg, Key)),
{'EXIT', {badarg, _}} = (catch enacl:generichash(65, Msg, Key)),
{'EXIT', {badarg, _}} = (catch enacl:generichash(32, Msg, <<"Small">>)),
ok.
generichash_basic_pos(_Config) ->
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
"All those... moments... will be lost... in time, like... tears... in rain">>,
Key = <<"Hash Key 123456789">>,
<<189,104,45,187,170,229,212,4,121,43,137,74,241,173,181,77,
67,211,133,70,196,6,128,97>> = enacl:generichash(24, Msg, Key),
ok.
generichash_chunked(_Config) ->
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
"All those... moments... will be lost... in time, like... tears... in rain">>,
Key = <<"Hash Key 123456789">>,
State = enacl:generichash_init(24, Key),
State = generichash_chunked(State, Msg, 10000),
Expected = <<46,49,32,18,13,186,182,105,106,122,253,139,89,176,169,141,
73,93,99,6,41,216,110,41>>,
Expected = enacl:generichash_final(State),
try enacl:generichash_final(State) of
_ -> ct:fail(must_finalize)
catch
error:enacl_finalized ->
ok
end,
try enacl:generichash_update(State, <<"x">>) of
_ -> ct:fail(must_finalize)
catch
error:enacl_finalized ->
ok
end,
ok.
generichash_chunked(State, _Msg, 0) -> State;
generichash_chunked(State, Msg, N) ->
State2 = enacl:generichash_update(State, Msg),
generichash_chunked(State2, Msg, N-1).
aead_xchacha20poly1305(_Config) ->
NonceLen = enacl:aead_xchacha20poly1305_ietf_NPUBBYTES(),
KLen = enacl:aead_xchacha20poly1305_ietf_KEYBYTES(),
Key = binary:copy(<<"K">>, KLen),
Msg = <<"test">>,
AD = <<1,2,3,4,5,6>>,
Nonce = binary:copy(<<"N">>, NonceLen),
CipherText = enacl:aead_xchacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
Msg = enacl:aead_xchacha20poly1305_ietf_decrypt(CipherText, AD, Nonce, Key),
ok.
aead_chacha20poly1305_ietf(_Config) ->
NonceLen = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
KLen = enacl:aead_chacha20poly1305_ietf_KEYBYTES(),
Key = binary:copy(<<"K">>, KLen),
Msg = <<"test">>,
AD = <<1,2,3,4,5,6>>,
Nonce = binary:copy(<<"N">>, NonceLen),
CipherText = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
Msg = enacl:aead_chacha20poly1305_ietf_decrypt(CipherText, AD, Nonce, Key),
ok.
pwhash(_Config) ->
PW = <<"XYZZY">>,
Salt = <<"1234567890abcdef">>,
Hash1 = <<164,75,127,151,168,101,55,77,48,77,240,204,64,20,43,23,88,
18,133,11,53,151,2,113,232,95,84,165,50,7,60,20>>,
Hash1 = enacl:pwhash(PW, Salt),
Str1 = enacl:pwhash_str(PW),
true = enacl:pwhash_str_verify(Str1, PW),
false = enacl:pwhash_str_verify(Str1, <<PW/binary, 1>>),
16 = enacl:pwhash_SALTBYTES(),
ok.
sign(_Config) ->
#{public := PK, secret := SK} = enacl:sign_keypair(),
Msg = <<"Test">>,
State = enacl:sign_init(),
Create = sign_chunked(State, Msg, 10000),
{ok, Signature} = enacl:sign_final_create(Create, SK),
StateVerify = enacl:sign_init(),
Verify = sign_chunked(StateVerify, Msg, 10000),
true = enacl:sign_final_verify(Verify, Signature, PK),
ok.
sign_chunked(S, _M, 0) -> S;
sign_chunked(S, M, N) ->
S2 = enacl:sign_update(S, M),
sign_chunked(S2, M, N-1).
kx(_Config) ->
#{ public := CPK, secret := CSK} = enacl:kx_keypair(),
#{ public := SPK, secret := SSK} = enacl:kx_keypair(),
#{ client_tx := CTX, client_rx := CRX} = enacl:kx_client_session_keys(CPK, CSK, SPK),
#{ server_tx := STX, server_rx := SRX} = enacl:kx_server_session_keys(SPK, SSK, CPK),
%% Verify we got a shared keypair
CTX = SRX,
STX = CRX,
ok.
secretstream(_Config) ->
Part1 = <<"Arbitrary data to encrypt">>,
Part2 = <<"split into">>,
Part3 = <<"three messages">>,
Key = enacl:secretstream_xchacha20poly1305_keygen(),
%% Encrypt
{Header, State} = enacl:secretstream_xchacha20poly1305_init_push(Key),
Block1 = enacl:secretstream_xchacha20poly1305_push(State, Part1, <<"AD1">>, message),
Block2 = enacl:secretstream_xchacha20poly1305_push(State, Part2, <<>>, message),
Block3 = enacl:secretstream_xchacha20poly1305_push(State, Part3, <<"AD3">>, final),
%% Decrypt
DState = enacl:secretstream_xchacha20poly1305_init_pull(Header, Key),
{Part1, message} = enacl:secretstream_xchacha20poly1305_pull(DState, Block1, <<"AD1">>),
{Part2, message} = enacl:secretstream_xchacha20poly1305_pull(DState, Block2, <<>>),
{Part3, final} = enacl:secretstream_xchacha20poly1305_pull(DState, Block3, <<"AD3">>),
ok.
verify_detached(_Config) ->
#{ public := PK, secret := SK} = enacl:sign_keypair(),
M = <<"Arbitrary data to encrypt">>,
Sig = enacl:sign_detached(M, SK),
true = enacl:sign_verify_detached(Sig, M, PK),
ok.