Compare commits

..

No commits in common. "master" and "0.16.0" have entirely different histories.

52 changed files with 1823 additions and 5838 deletions

View File

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

View File

@ -1,37 +0,0 @@
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]
}

View File

@ -1,34 +0,0 @@
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

View File

@ -1,21 +0,0 @@
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"]
}
}

View File

@ -1,40 +0,0 @@
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,6 +1,5 @@
.rebar
.rebar3
.envrc
ebin
*.beam
*.o
@ -13,8 +12,3 @@ doc/*.png
doc/*.css
_build
/.eqc-info
priv/enacl_nif.dll
priv/enacl_nif.exp
priv/enacl_nif.lib
c_src/*.d

View File

@ -1,16 +0,0 @@
{
"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
}

View File

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

View File

@ -1,322 +0,0 @@
# Changelog
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).
## [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 [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 [0.17.0]
- Expose the AEAD ChaCha20 Poly1305 (IETF) functionality (Hans
Svensson / Quviq).
- Expose Curve25519 Scalar Multiplication over a base point in the
curve (Hans Svensson / Quviq)
- Support the pwhash_* primitives (relying on Argon2) for password
hashing (daveed-al / Venkatakumar Srinivasan)
- Support for EQC Mini runs (Irina Guberman). The generator doesn't
inject faults, but it does verify the positive path. This is useful
to verify the enacl library on embedded platforms and so on.
- Support generichash functions (Venkatakumar Srinivasan / Xaptum)
### Fixed [0.17.0]
- The type specification of generichash/2 and generichash/3 was
corrected (Technion)
### 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
dirty scheduler interface is on and enabled by default (YAZ!)
- Some `size_t` entries in the C layer are now `uint` (Zane Beckwith).
The change only affects messages of exorbitant sizes, which we think
should be guarded against anyway, and it fixes some obvious
compilation problems on 32 bit architectures, and to boot matches
better against the Erlang NIF interface. We might change this later,
but hopefully this is a change for the better.
## [0.16.0]
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 [0.16.0]
- Add kx_* functions (Alexander Malaev)
- chacha stream functions added, siphash-2-4 added, unsafe_memzero/1
added (no attribution)
### Fixed [0.16.0]
- Do not use the dirty-scheduler test macro as it is gone.
## [0.15.0]
### 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 [0.15.0]
- Many dirty-scheduler tunings have been performed to make sure we
won't block a scheduler ever.
- New benchmarks: `bench/timing.erl` together with DTrace scripts
`bench/*.d`
- Interface simplification toward the NIF api. Only execute
instructions directly on the scheduler if the operation *really*
benefits from doing so.
No functional change, but the above characteristic change may mean the
library now behaves differently from what it did before. It should be
a better citizen to other libraries and other parts of the system.
## [0.14.0]
### 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 [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 [0.13.0]
- Quell warnings from the C code
### 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 [0.12.1]
- Provide the `priv` directory for being able to properly build
without manual intervention.
## [0.12.0]
### 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).
- Introduce Curve25519 manipulations into the extension interface.
- Write (rudimentary) QuickCheck tests for the new interface, to
verify its correctness.
## [0.11.0]
### 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 [0.11.0]
- Fix type for `enacl:box_open/4`. The specification was wrong which
results in errors in other applications using enacl.
## [0.10.2]
Maintenance release. Fix some usability problems with the library.
### 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)
- Fix a wrong call in the timing code. Luckily, this error has not
affected anything as it has only replaced a verification call with
one that does not verify. In practice, the timing is roughly the
same for both, save for a small constant factor (Thanks to the
dialyzer)
- Improve documentation around installation/building the software.
Hopefully it is now more prominent (Thanks to David N. Welton)
## [0.10.1]
### 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
`largebinary`-support in EQC tests.
- The release also adds an (experimental) scrambling function for
hiding the internal structure of counters. This is based on an
enlarged TEA-cipher by Wheeler and Needham. It is neccessary for
correct operation of the CurveCP implementation, which is why it is
included in this library.
## [0.10.0]
Ultra-late beta; tuning for the last couple of functions which could
be nice to have.
### 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`
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
gives no added security benefit. Key generation in NaCl relies on
`/dev/urandom`. Go relies on `/dev/urandom`. It is about time Erlang
does as well.
## [0.9.0]
Ultra-late beta. Code probably works, but it requires some real-world
use before it is deemed entirely stable.
Initial release.

View File

@ -3,15 +3,9 @@ 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

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014-2018 Jesper Louis Andersen
Copyright (c) 2014 Jesper Louis Andersen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,29 +1,8 @@
REBAR=rebar3
RUN_EQC=erl -pa _build/default/lib/enacl/ebin -noshell -s enacl_eqc -s init stop
.PHONY: compile
compile:
$(REBAR) compile
.PHONY: tests
tests:
$(REBAR) ct
eqc_compile: compile
erlc -o _build/default/lib/enacl/ebin eqc_test/enacl_eqc.erl
eqc_mini_compile: compile
erlc -Dmini -o _build/default/lib/enacl/ebin eqc_test/enacl_eqc.erl
eqc_run: eqc_compile
$(RUN_EQC)
eqc_mini_run: eqc_mini_compile
$(RUN_EQC)
.PHONE: console
console: compile
$(REBAR) shell
$(REBAR) compile | sed -e 's|_build/default/lib/enacl/||g'
.PHONY: clean
clean:

198
README.md
View File

@ -6,40 +6,34 @@ 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.
## INSTALL/Requirements
Several Erlang ports of NaCl/libsodium exists, but this one is a
rewrite with the following foci:
* 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.
*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
libsodium.
## INSTALL/Requirements:
* 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
libsodium.
To build the software execute:
make
make
or
rebar compile
rebar compile
To build and run licensed eqc test execute:
make eqc_run
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 large set of additional functionality from libsodium.
* Implements a small 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,
@ -58,18 +52,17 @@ In addition, I would like to thank Steve Vinoski, Rickard Green, and
Sverker Eriksson for providing the Dirty Scheduler API in the first
place.
## Usage
# USING:
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 [NaCl website](https://nacl.cr.yp.to)
In general, consult the NaCl documentation at
https://nacl.cr.yp.to
but also note that our interface has full Edoc documentation,
generated by executing
rebar3 doc
rebar doc
## Hints
In general, the primitives provided by NaCl are intermediate-level
@ -126,11 +119,135 @@ 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
### v0.16.0
## Overview
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.
Features:
* Add kx_* functions (Alexander Malaev)
* chacha stream functions added, siphash-2-4 added, unsafe_memzero/1
added (no attribution)
Bug fixes:
* Do not use the dirty-scheduler test macro as it is gone.
### v0.15.0
Bug fixes:
* 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.
Features:
* Many dirty-scheduler tunings have been performed to make sure we
won't block a scheduler ever.
* New benchmarks: `bench/timing.erl` together with DTrace scripts
`bench/*.d`
* Interface simplification toward the NIF api. Only execute
instructions directly on the scheduler if the operation *really*
benefits from doing so.
No functional change, but the above characteristic change may mean the
library now behaves differently from what it did before. It should be
a better citizen to other libraries and other parts of the system.
### v0.14.0
* Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr)
* Add support for libsodiums `crypto_sign_detached` (Joel Stanley,
Parnell Springmeyer)
* 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.
### v0.13.0
* Quell warnings from the C code
* Add Ed 25519 utility API (Alexander Færøy)
* Add FreeBSD support for the NIF compilation (Ricardo Lanziano)
### v0.12.1
* Provide the `priv` directory for being able to properly build
without manual intervention.
### v0.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).
* Introduce Curve25519 manipulations into the extension interface.
* Write (rudimentary) QuickCheck tests for the new interface, to
verify its correctness.
### v0.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.
* Fix type for `enacl:box_open/4`. The specification was wrong which
results in errors in other applications using enacl.
### v0.10.2
Maintenance release. Fix some usability problems with the library.
* 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)
* Fix a wrong call in the timing code. Luckily, this error has not
affected anything as it has only replaced a verification call with
one that does not verify. In practice, the timing is roughly the
same for both, save for a small constant factor (Thanks to the
dialyzer)
* Improve documentation around installation/building the software.
Hopefully it is now more prominent (Thanks to David N. Welton)
### v0.10.1
This small patch-release provides tests for the `randombytes/1`
function call, and optimizes EQC tests to make it easier to implement
`largebinary`-support in EQC tests. The release also adds an
(experimental) scrambling function for hiding the internal structure
of counters. This is based on an enlarged TEA-cipher by Wheeler and
Needham. It is neccessary for correct operation of the CurveCP
implementation, which is why it is included in this library.
### v0.10.0
Ultra-late beta; tuning for the last couple of functions which could
be nice to have. 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`
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
gives no added security benefit. Key generation in NaCl relies on
`/dev/urandom`. Go relies on `/dev/urandom`. It is about time Erlang
does as well.
### v0.9.0
Ultra-late beta. Code probably works, but it requires some real-world
use before it is deemed entirely stable.
Initial release.
# Overview
The NaCl cryptographic library provides a number of different
cryptographic primitives. In the following, we split up the different
@ -192,7 +309,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
@ -244,7 +361,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
@ -271,8 +388,11 @@ 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 [NaCl](http://nacl.cr.yp.to)
just the 3 main authors. Please see the page
http://nacl.cr.yp.to
for the full list of authors.

View File

@ -20,7 +20,7 @@ test() ->
randombytes() ->
randombytes(100*1000).
randombytes(0) -> ok;
randombytes(N) ->
enacl:randombytes(1024),
@ -29,7 +29,7 @@ randombytes(N) ->
hash() ->
B = binary:copy(<<0>>, 4096),
hash(B, 10*1000).
hash(_B, 0) -> ok;
hash(B, N) ->
enacl:hash(B),
@ -37,7 +37,7 @@ hash(B, N) ->
box_keypair() ->
box_keypair(10*1000).
box_keypair(0) -> ok;
box_keypair(N) ->
enacl:box_keypair(),
@ -47,9 +47,9 @@ box() ->
#{ public := PK1} = enacl:box_keypair(),
#{ secret := SK2} = enacl:box_keypair(),
B = binary:copy(<<0>>, 1),
Nonce = binary:copy(<<0>>, enacl:box_NONCEBYTES()()),
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
box(B, Nonce, PK1, SK2, 10*1000).
box(_B, _Nonce, _PK1, _SK2, 0) -> ok;
box(B, Nonce, PK1, SK2, N) ->
enacl:box(B, Nonce, PK1, SK2),
@ -62,15 +62,15 @@ 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_NONCEBYTES()()),
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
box_afternm(B, Nonce, R, 10*1000),
ok.
box_beforenm(_PK, _SK, 0) -> ok;
box_beforenm(PK, SK, N) ->
enacl:box_beforenm(PK, SK),
box_beforenm(PK, SK, N-1).
box_afternm(_Msg, _Nonce, _Key, 0) -> ok;
box_afternm(Msg, Nonce, Key, N) ->
enacl:box_afternm(Msg, Nonce, Key),
@ -78,7 +78,7 @@ box_afternm(Msg, Nonce, Key, N) ->
sign_keypair() ->
sign_keypair(10*1000).
sign_keypair(0) -> ok;
sign_keypair(N) ->
enacl:sign_keypair(),
@ -91,7 +91,7 @@ sign() ->
Msg = binary:copy(<<0>>, 1024),
#{ secret := SK } = enacl:sign_keypair(),
sign(Msg, SK, 10*1000).
sign(_Msg, _SK, 0) -> ok;
sign(Msg, SK, N) ->
enacl:sign(Msg, SK),
@ -100,10 +100,10 @@ sign(Msg, SK, N) ->
secretbox() ->
Msg = binary:copy(<<0>>, 8192),
Nonce = binary:copy(<<0>>, enacl:secretbox_NONCEBYTES()()),
Key = binary:copy(<<0>>, enacl:secretbox_KEYBYTES()),
Nonce = binary:copy(<<0>>, enacl:secretbox_nonce_size()),
Key = binary:copy(<<0>>, enacl:secretbox_key_size()),
secretbox(Msg, Nonce, Key, 10*1000).
secretbox(_Msg, _Nonce, _Key, 0) -> ok;
secretbox(Msg, Nonce, Key, N) ->
enacl:secretbox(Msg, Nonce, Key),
@ -111,8 +111,8 @@ secretbox(Msg, Nonce, Key, N) ->
stream() ->
stream(16384, binary:copy(<<0>>, enacl:stream_NONCEBYTES()), binary:copy(<<0>>, enacl:stream_KEYBYTES()), 10*1000).
stream(16384, binary:copy(<<0>>, enacl:stream_nonce_size()), binary:copy(<<0>>, enacl:stream_key_size()), 10*1000).
stream(_L, _Nonce, _K, 0) -> ok;
stream(L, Nonce, K, N) ->
enacl:stream(L, Nonce, K),
@ -120,31 +120,31 @@ stream(L, Nonce, K, N) ->
auth() ->
Msg = binary:copy(<<0>>, 4096),
Key = binary:copy(<<0>>, enacl:auth_KEYBYTES()),
Key = binary:copy(<<0>>, enacl:auth_key_size()),
auth(Msg, Key, 10*1000).
auth(_Msg, _Key, 0) -> ok;
auth(Msg, Key, N) ->
enacl:auth(Msg, Key),
auth(Msg, Key, N-1).
onetime_auth() ->
Msg = binary:copy(<<0>>, 16384),
Key = binary:copy(<<0>>, enacl:onetime_auth_KEYBYTES()),
Key = binary:copy(<<0>>, enacl:onetime_auth_key_size()),
onetime_auth(Msg, Key, 10*1000).
onetime_auth(_Msg, _Key, 0) -> ok;
onetime_auth(Msg, Key, N) ->
enacl:onetime_auth(Msg, Key),
onetime_auth(Msg, Key, N-1).
scalarmult() ->
Secret = binary:copy(<<0>>, 32),
BasePoint = binary:copy(<<1>>, 32),
scalarmult(Secret, BasePoint, 10*1000).
scalarmult(_S, _B, 0) -> ok;
scalarmult(S, B, N) ->
enacl:curve25519_scalarmult(S, B),
scalarmult(S, B, N-1).

75
c_src/Makefile Normal file
View File

@ -0,0 +1,75 @@
# 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.
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)

View File

@ -1,242 +0,0 @@
#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;
}

View File

@ -1,46 +0,0 @@
#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

View File

@ -1,16 +0,0 @@
#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"));
}

View File

@ -1,15 +0,0 @@
#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

View File

@ -1,86 +0,0 @@
#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);
}

View File

@ -1,9 +0,0 @@
#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

View File

@ -1,301 +0,0 @@
#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;
}

View File

@ -1,32 +0,0 @@
#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

View File

@ -1,62 +0,0 @@
#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;
}

View File

@ -1,17 +0,0 @@
#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

View File

@ -1,59 +0,0 @@
#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);
}

View File

@ -1,15 +0,0 @@
#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

View File

@ -1,151 +0,0 @@
#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;
}

View File

@ -1,24 +0,0 @@
#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

View File

@ -1,286 +0,0 @@
#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);
}

View File

@ -1,49 +0,0 @@
#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

View File

@ -1,180 +0,0 @@
#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;
}

View File

@ -1,18 +0,0 @@
#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

View File

@ -1,49 +0,0 @@
#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);
}

View File

@ -1,15 +0,0 @@
#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

View File

@ -1,382 +0,0 @@
#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");
}
}

View File

@ -1,76 +0,0 @@
#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

View File

@ -1,462 +0,0 @@
#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;
}

View File

@ -1,78 +0,0 @@
#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

View File

@ -1,488 +0,0 @@
#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);
}
}

View File

@ -1,70 +0,0 @@
#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,3 @@
eqc_compile:
$(MAKE) -C .. eqc_compile
console:
erl -pa ../ebin ../deps/*/ebin

View File

@ -1,22 +1,8 @@
-module(enacl_eqc).
-include_lib("eqc/include/eqc.hrl").
-compile([export_all, nowarn_export_all]).
-compile(export_all).
-ifndef(mini).
-compile({parse_transform, eqc_parallelize}).
-define(FAULT(Arg1, Arg2), fault(Arg1, Arg2)).
-define(FAULT_RATE(Arg1, Arg2, Arg3), fault_rate(Arg1, Arg2, Arg3)).
-else.
-define(FAULT(Arg1, Arg2), noop_fault(Arg1, Arg2)).
-define(FAULT_RATE(Arg1, Arg2, Arg3), noop_fault_rate(Arg1, Arg2, Arg3)).
-endif.
start()->
eqc:module(?MODULE).
noop_fault(_Bad, Good) -> Good.
noop_fault_rate(_1, _2, Gen) -> Gen.
non_byte_int() ->
oneof([
@ -28,7 +14,7 @@ g_iolist() ->
?SIZED(Sz, g_iolist(Sz)).
g_iolist(0) ->
?FAULT(
fault(
oneof([
elements([a,b,c]),
real(),
@ -36,7 +22,7 @@ g_iolist(0) ->
]),
return([]));
g_iolist(N) ->
?FAULT(
fault(
oneof([
elements([a,b,c]),
real(),
@ -48,7 +34,7 @@ g_iolist(N) ->
])).
g_iodata() ->
?FAULT(
fault(
oneof([elements([a,b,c]), real()]),
oneof([binary(), g_iolist(), eqc_gen:largebinary(64*1024)])).
@ -64,7 +50,7 @@ v_iodata(Structure) -> v_iolist(Structure).
%% Generator for binaries of a given size with different properties and fault injection:
g_binary(Sz) ->
?FAULT(g_binary_bad(Sz), g_binary_good(Sz)).
fault(g_binary_bad(Sz), g_binary_good(Sz)).
g_binary_good(Sz) when Sz =< 32 -> binary(Sz);
g_binary_good(Sz) -> eqc_gen:largebinary(Sz).
@ -83,12 +69,12 @@ v_binary(_, _) -> false.
%% Typical generators based on the binaries
nonce() -> g_binary(enacl:box_NONCEBYTES()).
nonce_valid(N) -> v_binary(enacl:box_NONCEBYTES(), N).
nonce() -> g_binary(enacl:box_nonce_size()).
nonce_valid(N) -> v_binary(enacl:box_nonce_size(), N).
%% Generator of natural numbers
g_nat() ->
?FAULT(g_nat_bad(), nat()).
fault(g_nat_bad(), nat()).
g_nat_bad() ->
oneof([
@ -111,56 +97,23 @@ keypair_bad() ->
#{ public := PK, secret := SK} = enacl:box_keypair(),
case X of
pk ->
PKBytes = enacl:box_PUBLICKEYBYTES(),
PKBytes = enacl:box_public_key_bytes(),
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
sk ->
SKBytes = enacl:box_SECRETKEYBYTES(),
SKBytes = enacl:box_secret_key_bytes(),
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
end
end).
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)).
fault(keypair_bad(), keypair_good()).
%% CRYPTO BOX
%% ---------------------------
%% * box/4
%% * box_open/4
%% * box_beforenm/2
%% * box_afternm/3
%% * box_open_afternm/3
keypair_valid(PK, SK) when is_binary(PK), is_binary(SK) ->
PKBytes = enacl:box_PUBLICKEYBYTES(),
SKBytes = enacl:box_SECRETKEYBYTES(),
PKBytes = enacl:box_public_key_bytes(),
SKBytes = enacl:box_secret_key_bytes(),
byte_size(PK) == PKBytes andalso byte_size(SK) == SKBytes;
keypair_valid(_PK, _SK) -> false.
@ -205,10 +158,10 @@ failure(X) -> {failure, X}.
prop_box_correct() ->
?FORALL({Msg, Nonce, {PK1, SK1}, {PK2, SK2}},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, keypair()),
?FAULT_RATE(1, 40, keypair())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, nonce()),
fault_rate(1, 40, keypair()),
fault_rate(1, 40, keypair())},
begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of
true ->
@ -229,10 +182,10 @@ prop_box_correct() ->
prop_box_failure_integrity() ->
?FORALL({Msg, Nonce, {PK1, SK1}, {PK2, SK2}},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, keypair()),
?FAULT_RATE(1, 40, keypair())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, nonce()),
fault_rate(1, 40, keypair()),
fault_rate(1, 40, keypair())},
begin
case v_iodata(Msg)
andalso nonce_valid(Nonce)
@ -252,11 +205,45 @@ prop_box_failure_integrity() ->
end
end
end).
prop_seal_box_failure_integrity() ->
?FORALL({Msg, {PK1, SK1}}, {fault_rate(1,40,g_iodata()), fault_rate(1,40,keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
CT = enacl:box_seal(Msg, PK1),
Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1),
equals(Err, {error, failed_verification});
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res ->
failure(box_seal_open(Res, PK1, SK1))
end
end
end).
prop_seal_box_correct() ->
?FORALL({Msg, {PK1, SK1}},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
SealedCipherText = enacl:box_seal(Msg, PK1),
{ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1),
equals(iolist_to_binary(Msg), DecodedMsg);
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res -> failure(box_seal_open(Res, PK1, SK1))
end
end
end).
%% PRECOMPUTATIONS
beforenm_key() ->
?LET([{PK1, SK1}, {PK2, SK2}], [?FAULT_RATE(1, 40, keypair()), ?FAULT_RATE(1, 40, keypair())],
?LET([{PK1, SK1}, {PK2, SK2}], [fault_rate(1, 40, keypair()), fault_rate(1, 40, keypair())],
case keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of
true ->
enacl:box_beforenm(PK1, SK2);
@ -264,15 +251,15 @@ beforenm_key() ->
oneof([
elements([a,b,c]),
real(),
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_BEFORENMBYTES())
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_beforenm_bytes())
])
end).
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_BEFORENMBYTES();
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_beforenm_bytes();
v_key(_) -> false.
prop_beforenm_correct() ->
?FORALL([{PK1, SK1}, {PK2, SK2}], [?FAULT_RATE(1, 40, keypair()), ?FAULT_RATE(1, 40, keypair())],
?FORALL([{PK1, SK1}, {PK2, SK2}], [fault_rate(1, 40, keypair()), fault_rate(1, 40, keypair())],
case keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of
true ->
equals(enacl:box_beforenm(PK1, SK2), enacl:box_beforenm(PK2, SK1));
@ -285,9 +272,9 @@ prop_beforenm_correct() ->
prop_afternm_correct() ->
?FORALL([Msg, Nonce, Key],
[?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, beforenm_key())],
[fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, nonce()),
fault_rate(1, 40, beforenm_key())],
begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso v_key(Key) of
true ->
@ -324,11 +311,11 @@ sign_keypair_bad() ->
KP = enacl:sign_keypair(),
case X of
pk ->
Sz = enacl:sign_PUBLICBYTES(),
Sz = enacl:sign_keypair_public_size(),
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
KP#{ public := Wrong });
sk ->
Sz = enacl:sign_SECRETBYTES(),
Sz = enacl:sign_keypair_secret_size(),
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
KP#{ secret := Wrong })
end
@ -338,16 +325,16 @@ sign_keypair_good() ->
return(enacl:sign_keypair()).
sign_keypair() ->
?FAULT(sign_keypair_bad(), sign_keypair_good()).
fault(sign_keypair_bad(), sign_keypair_good()).
sign_keypair_public_valid(#{ public := Public })
when is_binary(Public) ->
byte_size(Public) == enacl:sign_PUBLICBYTES();
byte_size(Public) == enacl:sign_keypair_public_size();
sign_keypair_public_valid(_) -> false.
sign_keypair_secret_valid(#{ secret := Secret })
when is_binary(Secret) ->
byte_size(Secret) == enacl:sign_SECRETBYTES();
byte_size(Secret) == enacl:sign_keypair_secret_size();
sign_keypair_secret_valid(_) -> false.
sign_keypair_valid(KP) ->
@ -355,8 +342,8 @@ sign_keypair_valid(KP) ->
prop_sign_detached() ->
?FORALL({Msg, KeyPair},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, sign_keypair())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, sign_keypair())},
begin
case v_iodata(Msg) andalso sign_keypair_secret_valid(KeyPair) of
true ->
@ -371,8 +358,8 @@ prop_sign_detached() ->
prop_sign() ->
?FORALL({Msg, KeyPair},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, sign_keypair())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, sign_keypair())},
begin
case v_iodata(Msg) andalso sign_keypair_secret_valid(KeyPair) of
true ->
@ -408,18 +395,18 @@ signed_message_good_d(M) ->
end)}]).
signed_message_bad() ->
Sz = enacl:sign_PUBLICBYTES(),
Sz = enacl:sign_keypair_public_size(),
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
signed_message_bad_d() ->
Sz = enacl:sign_PUBLICBYTES(),
Sz = enacl:sign_keypair_public_size(),
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
signed_message(M) ->
?FAULT(signed_message_bad(), signed_message_good(M)).
fault(signed_message_bad(), signed_message_good(M)).
signed_message_d(M) ->
?FAULT(signed_message_bad_d(), signed_message_good_d(M)).
fault(signed_message_bad(), signed_message_good(M)).
signed_message_valid({valid, _}, _) -> true;
signed_message_valid({invalid, _}, _) -> true;
@ -432,9 +419,9 @@ prop_sign_detached_open() ->
true ->
case SignMsg of
{valid, Sig} ->
equals(true, enacl:sign_verify_detached(Sig, Msg, PK));
equals({ok, Msg}, enacl:sign_verify_detached(Sig, Msg, PK));
{invalid, Sig} ->
equals(false, enacl:sign_verify_detached(Sig, Msg, PK))
equals({error, failed_verification}, enacl:sign_verify_detached(Sig, Msg, PK))
end;
false ->
badargs(fun() -> enacl:sign_verify_detached(SignMsg, Msg, PK) end)
@ -455,78 +442,64 @@ prop_sign_open() ->
badargs(fun() -> enacl:sign_open(SignMsg, PK) end)
end)).
prop_seal_box_failure_integrity() ->
?FORALL({Msg, {PK1, SK1}}, {?FAULT_RATE(1,40,g_iodata()), ?FAULT_RATE(1,40,keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
CT = enacl:box_seal(Msg, PK1),
Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1),
equals(Err, {error, failed_verification});
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res ->
failure(box_seal_open(Res, PK1, SK1))
end
end
end).
prop_seal_box_correct() ->
?FORALL({Msg, {PK1, SK1}},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
SealedCipherText = enacl:box_seal(Msg, PK1),
{ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1),
equals(iolist_to_binary(Msg), DecodedMsg);
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res -> failure(box_seal_open(Res, PK1, SK1))
end
end
end).
%% CRYPTO SECRET BOX
%% ------------------------------------------------------------
%% * secretbox/3
%% * secretbo_open/3
%% -------------------------------
%% Note: key sizes are the same in a lot of situations, so we can use the same generator
%% for keys in many locations.
key_sz(Sz) ->
equals(enacl:secretbox_key_size(), Sz).
prop_key_sizes() ->
conjunction([{secret, key_sz(enacl:secretbox_key_size())},
{stream, key_sz(enacl:stream_key_size())},
{auth, key_sz(enacl:auth_key_size())},
{onetimeauth, key_sz(enacl:onetime_auth_key_size())}]).
nonce_sz(Sz) ->
equals(enacl:secretbox_nonce_size(), Sz).
prop_nonce_sizes() ->
conjunction([{secret, nonce_sz(enacl:secretbox_nonce_size())},
{stream, nonce_sz(enacl:stream_nonce_size())}]).
secret_key_good() ->
Sz = enacl:secretbox_KEYBYTES(),
Sz = enacl:secretbox_key_size(),
binary(Sz).
secret_key_bad() ->
oneof([return(a),
nat(),
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_KEYBYTES())]).
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_key_size())]).
secret_key() ->
?FAULT(secret_key_bad(), secret_key_good()).
fault(secret_key_bad(), secret_key_good()).
secret_key_valid(SK) when is_binary(SK) ->
Sz = enacl:secretbox_KEYBYTES(),
Sz = enacl:secretbox_key_size(),
byte_size(SK) == Sz;
secret_key_valid(_SK) -> false.
secretbox(Msg, Nonce, Key) ->
try enacl:secretbox(Msg, Nonce, Key)
catch error:badarg -> badarg
try
enacl:secretbox(Msg, Nonce, Key)
catch
error:badarg -> badarg
end.
secretbox_open(Msg, Nonce, Key) ->
try enacl:secretbox_open(Msg, Nonce, Key)
catch error:badarg -> badarg
try
enacl:secretbox_open(Msg, Nonce, Key)
catch
error:badarg -> badarg
end.
prop_secretbox_correct() ->
?FORALL({Msg, Nonce, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, secret_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 ->
@ -550,100 +523,12 @@ 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_ietf() ->
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
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_ietf_fail() ->
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
?FORALL({Key, Msg, AD, Nonce},
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
begin
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
end).
%% CRYPTO STREAM
%% ------------------------------------------------------------
%% * stream/3
prop_stream_correct() ->
?FORALL({Len, Nonce, Key},
{int(),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, secret_key())},
fault_rate(1, 40, nonce()),
fault_rate(1, 40, secret_key())},
case Len >= 0 andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of
true ->
CipherStream = enacl:stream(Len, Nonce, Key),
@ -656,35 +541,29 @@ xor_bytes(<<A, As/binary>>, <<B, Bs/binary>>) ->
[A bxor B | xor_bytes(As, Bs)];
xor_bytes(<<>>, <<>>) -> [].
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)).
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).
%% CRYPTO AUTH
%% ------------------------------------------------------------
%% * auth/2
%% * auth_verify/3
prop_auth_correct() ->
?FORALL({Msg, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, secret_key())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, secret_key())},
case v_iodata(Msg) andalso secret_key_valid(Key) of
true ->
Authenticator = enacl:auth(Msg, Key),
@ -694,22 +573,22 @@ prop_auth_correct() ->
end).
authenticator_bad() ->
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_BYTES())]).
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_size())]).
authenticator_good(Msg, Key) when is_binary(Key) ->
Sz = enacl:secretbox_KEYBYTES(),
Sz = enacl:secretbox_key_size(),
case v_iodata(Msg) andalso byte_size(Key) == Sz of
true ->
frequency([{1, ?LAZY({invalid, binary(enacl:auth_BYTES())})},
frequency([{1, ?LAZY({invalid, binary(enacl:auth_size())})},
{3, return({valid, enacl:auth(Msg, Key)})}]);
false ->
binary(enacl:auth_BYTES())
binary(enacl:auth_size())
end;
authenticator_good(_Msg, _Key) ->
binary(enacl:auth_BYTES()).
binary(enacl:auth_size()).
authenticator(Msg, Key) ->
?FAULT(authenticator_bad(), authenticator_good(Msg, Key)).
fault(authenticator_bad(), authenticator_good(Msg, Key)).
authenticator_valid({valid, _}) -> true;
authenticator_valid({invalid, _}) -> true;
@ -717,8 +596,8 @@ authenticator_valid(_) -> false.
prop_auth_verify_correct() ->
?FORALL({Msg, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, secret_key())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, secret_key())},
?FORALL(Authenticator, authenticator(Msg, Key),
case v_iodata(Msg) andalso secret_key_valid(Key) andalso authenticator_valid(Authenticator) of
true ->
@ -733,13 +612,10 @@ prop_auth_verify_correct() ->
end)).
%% CRYPTO ONETIME AUTH
%% ------------------------------------------------------------
%% * onetime_auth/2
%% * onetime_auth_verify/3
prop_onetimeauth_correct() ->
?FORALL({Msg, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, secret_key())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, secret_key())},
case v_iodata(Msg) andalso secret_key_valid(Key) of
true ->
Authenticator = enacl:onetime_auth(Msg, Key),
@ -749,22 +625,22 @@ prop_onetimeauth_correct() ->
end).
ot_authenticator_bad() ->
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_BYTES())]).
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_size())]).
ot_authenticator_good(Msg, Key) when is_binary(Key) ->
Sz = enacl:secretbox_KEYBYTES(),
Sz = enacl:secretbox_key_size(),
case v_iodata(Msg) andalso byte_size(Key) == Sz of
true ->
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_BYTES())})},
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_size())})},
{3, return({valid, enacl:onetime_auth(Msg, Key)})}]);
false ->
binary(enacl:onetime_auth_BYTES())
binary(enacl:onetime_auth_size())
end;
ot_authenticator_good(_Msg, _Key) ->
binary(enacl:auth_BYTES()).
binary(enacl:auth_size()).
ot_authenticator(Msg, Key) ->
?FAULT(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
fault(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
ot_authenticator_valid({valid, _}) -> true;
ot_authenticator_valid({invalid, _}) -> true;
@ -772,8 +648,8 @@ ot_authenticator_valid(_) -> false.
prop_onetime_auth_verify_correct() ->
?FORALL({Msg, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, secret_key())},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, secret_key())},
?FORALL(Authenticator, ot_authenticator(Msg, Key),
case v_iodata(Msg) andalso secret_key_valid(Key) andalso ot_authenticator_valid(Authenticator) of
true ->
@ -787,71 +663,7 @@ prop_onetime_auth_verify_correct() ->
badargs(fun() -> enacl:onetime_auth_verify(Authenticator, Msg, Key) end)
end)).
%% PWHASH
%% -------------------------------
%% * pwhash/2
%% * pwhash_str/1
%% * pwhash_str_verify/2
pwhash(Passwd, Salt) ->
try
enacl:pwhash(Passwd, Salt)
catch
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)
catch
error:badarg -> badarg
end.
pwhash_str_verify(PasswdHash, Passwd) ->
try
enacl:pwhash_str_verify(PasswdHash, Passwd)
catch
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, OLimit, MLimit},
{?FAULT_RATE(1, 40, g_iodata()),
elements([interactive, moderate]),
elements([interactive, moderate])},
begin
case v_iodata(Passwd) of
true ->
Ascii = enacl:pwhash_str(Passwd, OLimit, MLimit),
S = enacl:pwhash_str_verify(Ascii, Passwd),
equals(S, true);
false ->
badargs(fun() -> enacl:pwhash_str(Passwd) end),
badargs(fun() -> enacl:pwhash_str_verify("", Passwd) end)
end
end).
%% SUBTLE HASHING
%% HASHING
%% ---------------------------
diff_pair() ->
?SUCHTHAT({X, Y}, {g_iodata(), g_iodata()},
@ -876,45 +688,9 @@ 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,
%% * verify_32/2
verify_pair_bad(Sz) ->
?LET(X, elements([fst, snd]),
case X of
@ -930,7 +706,7 @@ verify_pair_good(Sz) ->
?SUCHTHAT({X, Y}, {binary(Sz), binary(Sz)}, X /= Y)]).
verify_pair(Sz) ->
?FAULT(verify_pair_bad(Sz), verify_pair_good(Sz)).
fault(verify_pair_bad(Sz), verify_pair_good(Sz)).
verify_pair_valid(Sz, X, Y) ->
byte_size(X) == Sz andalso byte_size(Y) == Sz.
@ -964,14 +740,11 @@ prop_verify_32() ->
end).
%% RANDOMBYTES
%% ------------------------------------------------------------
%% * randombytes/1
prop_randombytes() ->
?FORALL(X, g_nat(),
case is_nat(X) of
true ->
R = enacl:randombytes(X),
is_binary(R) andalso (byte_size(R) == X);
is_binary(enacl:randombytes(X));
false ->
try
enacl:randombytes(X),
@ -982,84 +755,12 @@ 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,8 +1,7 @@
-module(enacl_ext_eqc).
-include_lib("eqc/include/eqc.hrl").
-compile({parse_transform, eqc_parallelize}).
-compile([export_all, nowarn_export_all]).
-compile(export_all).
public_keypair() ->
?LET(#{ public := PK, secret := SK}, enacl_ext:curve25519_keypair(),
@ -23,7 +22,3 @@ prop_shared_secret() ->
equals(Alice, Bob)
end).
prop_scramble_block() ->
?FORALL({Block, Key}, {binary(16), eqc_gen:largebinary(32)},
is_binary(enacl_ext:scramble_block_16(Block, Key))).

View File

@ -1,39 +1,9 @@
{erl_opts, [debug_info]}.
{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"}
{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"}
]}.

View File

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

View File

@ -1,9 +1,8 @@
{application,enacl,
[{description,"Erlang libsodium (NaCl) bindings"},
{vsn,"1.2.1"},
{registered,[]},
{applications,[kernel,stdlib]},
{env,[]},
{maintainers,["Jesper Louis Andersen"]},
{licenses,["MIT","ISC"]},
{links,[{"Github","https://github.com/jlouis/enacl"}]}]}.
{application, enacl,
[
{description, "Erlang NaCl bindings"},
{vsn, "0.16.0"},
{registered, []},
{applications, [kernel, stdlib]},
{env, []}
]}.

File diff suppressed because it is too large Load Diff

View File

@ -40,19 +40,19 @@ scramble_block_16(Block, Key) ->
%% @end
-spec curve25519_keypair() -> #{ atom() => binary() }.
curve25519_keypair() ->
<<B0:8/integer, B1:30/binary, B2:8/integer>> = enacl:randombytes(32),
SK = <<(B0 band 248), B1/binary, (64 bor (B2 band 127))>>,
PK = curve25519_public_key(SK),
#{ public => PK, secret => SK }.
<<B0:8/integer, B1:30/binary, B2:8/integer>> = enacl:randombytes(32),
SK = <<(B0 band 248), B1/binary, (64 bor (B2 band 127))>>,
PK = curve25519_public_key(SK),
#{ public => PK, secret => SK }.
%% @doc curve25519_public_key/1 creates a public key from a given SecretKey.
%% @end
-spec curve25519_public_key(SecretKey :: binary()) -> binary().
curve25519_public_key(SecretKey) ->
enacl:curve25519_scalarmult(SecretKey, <<9, 0:248>>).
enacl:curve25519_scalarmult(SecretKey, <<9, 0:248>>).
%% @doc curve25519_shared/2 creates a new shared secret from a given SecretKey and PublicKey.
%% @end.
-spec curve25519_shared(SecretKey :: binary(), PublicKey :: binary()) -> binary().
curve25519_shared(SecretKey, PublicKey) ->
enacl:curve25519_scalarmult(SecretKey, PublicKey).
enacl:curve25519_scalarmult(SecretKey, PublicKey).

View File

@ -25,10 +25,8 @@
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,
@ -36,11 +34,6 @@
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
@ -57,10 +50,6 @@
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,
@ -78,20 +67,6 @@
crypto_stream_xor/3,
crypto_stream_xor_b/3,
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,
@ -116,14 +91,12 @@
%% Curve25519
-export([
crypto_curve25519_scalarmult/2,
crypto_curve25519_scalarmult_base/1
crypto_curve25519_scalarmult/2
]).
%% 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,
@ -149,58 +122,9 @@
sodium_memzero/1
]).
%% Password Hashing - Argon2 Algorithm
-export([
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,
crypto_generichash_BYTES_MIN/0,
crypto_generichash_BYTES_MAX/0,
crypto_generichash_KEYBYTES/0,
crypto_generichash_KEYBYTES_MIN/0,
crypto_generichash_KEYBYTES_MAX/0,
crypto_generichash/3,
crypto_generichash_init/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_uint32/0,
randombytes_uniform/1
randombytes/1
]).
%% Undocumented features :>
@ -219,45 +143,8 @@ init() ->
code:which(?MODULE))), "priv");
D -> D
end,
SoName = filename:join(Dir, atom_to_list(?MODULE)),
erlang:load_nif(SoName, 0).
crypto_generichash_BYTES() -> erlang:nif_error(nif_not_loaded).
crypto_generichash_BYTES_MIN() -> erlang:nif_error(nif_not_loaded).
crypto_generichash_BYTES_MAX() -> erlang:nif_error(nif_not_loaded).
crypto_generichash_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_generichash_KEYBYTES_MIN() -> erlang:nif_error(nif_not_loaded).
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(_HashState, _Message) -> erlang:nif_error(nif_not_loaded).
crypto_generichash_final(_HashState) -> 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).
SoName = filename:join(Dir, atom_to_list(?MODULE)),
erlang:load_nif(SoName, 0).
crypto_box_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_box_ZEROBYTES() -> erlang:nif_error(nif_not_loaded).
@ -278,10 +165,8 @@ 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).
@ -289,11 +174,6 @@ 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).
@ -307,10 +187,6 @@ 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).
@ -326,20 +202,6 @@ 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_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).
crypto_auth(_Msg, _Key) -> erlang:nif_error(nif_not_loaded).
@ -359,10 +221,8 @@ crypto_onetimeauth_verify(_Authenticator, _Msg, _Key) -> erlang:nif_error(nif_no
crypto_onetimeauth_verify_b(_Authenticator, _Msg, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_curve25519_scalarmult(_Secret, _BasePoint) -> erlang:nif_error(nif_not_loaded).
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).
@ -382,7 +242,5 @@ 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).

View File

@ -1,196 +0,0 @@
-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.