commit
793ddb502f
3
.github/workflows/Makefile
vendored
Normal file
3
.github/workflows/Makefile
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
all:
|
||||||
|
cue export --out yaml > ci.yaml
|
||||||
|
|
37
.github/workflows/actions.cue
vendored
Normal file
37
.github/workflows/actions.cue
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
#Name: string
|
||||||
|
#Branches: branches: [...string]
|
||||||
|
#Tags: tags: [...string]
|
||||||
|
|
||||||
|
#On: {
|
||||||
|
push?: #Branches
|
||||||
|
pull_request?: #Branches
|
||||||
|
page_build?: #Branches
|
||||||
|
}
|
||||||
|
|
||||||
|
#Action: "actions/checkout@v2" | "erlef/setup-beam@v1"
|
||||||
|
#Uses: {
|
||||||
|
uses: #Action
|
||||||
|
with?: {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#Run: {
|
||||||
|
name: string
|
||||||
|
run: string
|
||||||
|
}
|
||||||
|
#Steps: #Uses | #Run
|
||||||
|
|
||||||
|
#OS_Version: *"ubuntu-latest" | "macos-latest" | "windows_latest"
|
||||||
|
|
||||||
|
#Jobs: ci: {
|
||||||
|
name: string
|
||||||
|
"runs-on": string
|
||||||
|
strategy:
|
||||||
|
matrix: {
|
||||||
|
otp_vsn: [...string]
|
||||||
|
os: [...#OS_Version]
|
||||||
|
}
|
||||||
|
steps: [...#Steps]
|
||||||
|
}
|
34
.github/workflows/ci.yaml
vendored
Normal file
34
.github/workflows/ci.yaml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: build
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
name: Run checks and tests over ${{matrix.otp_vsn}} and ${{matrix.os}}
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
otp_vsn:
|
||||||
|
- "22.3"
|
||||||
|
- "23.3"
|
||||||
|
- "24.0"
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: erlef/setup-beam@v1
|
||||||
|
with:
|
||||||
|
otp-version: ${{matrix.otp_vsn}}
|
||||||
|
rebar3-version: 3.16.1
|
||||||
|
- name: Update apt-get database
|
||||||
|
run: sudo apt-get update
|
||||||
|
- name: Install libsodium
|
||||||
|
run: sudo apt-get install -y libsodium-dev
|
||||||
|
- name: Compile source code
|
||||||
|
run: make compile
|
||||||
|
- name: Run the tests
|
||||||
|
run: make tests
|
21
.github/workflows/setup.cue
vendored
Normal file
21
.github/workflows/setup.cue
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
name: #Name & "build"
|
||||||
|
on: #On & {
|
||||||
|
push: branches: [
|
||||||
|
_branch,
|
||||||
|
]
|
||||||
|
pull_request: branches: [
|
||||||
|
_branch,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
jobs: #Jobs
|
||||||
|
jobs: ci: {
|
||||||
|
name: "Run checks and tests over ${{matrix.otp_vsn}} and ${{matrix.os}}"
|
||||||
|
"runs-on": "${{matrix.os}}"
|
||||||
|
strategy: matrix: {
|
||||||
|
otp_vsn: _versions.otp
|
||||||
|
os: ["ubuntu-latest"]
|
||||||
|
}
|
||||||
|
}
|
40
.github/workflows/steps.cue
vendored
Normal file
40
.github/workflows/steps.cue
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
// Versions for simplicity
|
||||||
|
_versions: {
|
||||||
|
// The versions here have an underlying Debian/Ubuntu which support enough of
|
||||||
|
// libsodium to handle what enacl provides. Older versions will fail to compile
|
||||||
|
otp: ["22.3", "23.3", "24.0"]
|
||||||
|
rebar3: "3.16.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_branch: "master"
|
||||||
|
|
||||||
|
jobs: ci: steps:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
uses: "actions/checkout@v2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uses: "erlef/setup-beam@v1"
|
||||||
|
with: {
|
||||||
|
"otp-version": "${{matrix.otp_vsn}}"
|
||||||
|
"rebar3-version": _versions.rebar3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update apt-get database"
|
||||||
|
run: "sudo apt-get update"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Install libsodium"
|
||||||
|
run: "sudo apt-get install -y libsodium-dev"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Compile source code"
|
||||||
|
run: "make compile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Run the tests"
|
||||||
|
run: "make tests"
|
||||||
|
}]
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ _build
|
|||||||
priv/enacl_nif.dll
|
priv/enacl_nif.dll
|
||||||
priv/enacl_nif.exp
|
priv/enacl_nif.exp
|
||||||
priv/enacl_nif.lib
|
priv/enacl_nif.lib
|
||||||
c_src/enacl_nif.d
|
c_src/*.d
|
||||||
|
|
||||||
|
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/nix/store/fb30zc52va0g99q8qgv7kx4ngq163pii-gcc-wrapper-9.3.0/bin/gcc",
|
||||||
|
"cStandard": "c11",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "clang-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.errorSquiggles": "Disabled"
|
||||||
|
}
|
180
CHANGELOG.md
180
CHANGELOG.md
@ -5,23 +5,139 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
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).
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [1.2.1]
|
||||||
|
|
||||||
|
### Fixed [1.2.1]
|
||||||
|
|
||||||
|
- Export types from the `enacl` module so it can be referenced in other parts of your system (serokell.io)
|
||||||
|
|
||||||
|
## [1.2.0]
|
||||||
|
|
||||||
|
### Fixed [1.2.0]
|
||||||
|
|
||||||
|
- `sign_verify_detached/3` The code now verifies the size of signatures in detached mode. Before
|
||||||
|
this change, you could supply a larger binary and the code would only use the first `SIGNBYTES`
|
||||||
|
of the binary, assuming the signature were in there. Now, it fails with a badarg if the signature
|
||||||
|
doesn't match expectation in size.
|
||||||
|
|
||||||
|
## [1.1.1]
|
||||||
|
|
||||||
|
### Added [1.1.1]
|
||||||
|
|
||||||
|
- Introduce the ability to reload the enacl module (Bryan Paxton, @starbelly)
|
||||||
|
|
||||||
|
## [1.1.0]
|
||||||
|
|
||||||
|
### Added [1.1.0]
|
||||||
|
|
||||||
|
- Secretstream support was added to the API (Alexander Malaev)
|
||||||
|
- Add KDF functions (Nicolas Goy, @kuon)
|
||||||
|
- Add pwhash/5 specifying what algorithm to use for older compatibility (Nicolas Goy, @kuon)
|
||||||
|
|
||||||
|
### Changed [1.1.0]
|
||||||
|
|
||||||
|
- Remove rebar3_hex as a direct dependency (Bryan Paxton, @starbelly)
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
|
||||||
|
### Compatibility [1.0.0]
|
||||||
|
|
||||||
|
- Some functions have been streamlined to badarg in certain cases where it made more
|
||||||
|
sense to do so than returning back an error to the caller.
|
||||||
|
- Functions generally don't return error values for internal errors. They now raise
|
||||||
|
exceptions when this happens. If you can't allocate a binary, there is usually not
|
||||||
|
much the programmer can do with that information, sans crashing.
|
||||||
|
- If you used `aead_chacha20poly1305_*` functions, please read through the changelog
|
||||||
|
carefully as we have made changes to these functions. TL;DR: look for
|
||||||
|
`aead_chacha20poly1305_ietf_*` but note it is *not* just a simple substitution
|
||||||
|
into your code.
|
||||||
|
- The `kx` constants have been renamed to follow libsodium one-to-one.
|
||||||
|
- All calls with `verify` now returns booleans. See `sign_verify_detached`, which
|
||||||
|
were changed by this.
|
||||||
|
- Many constants were changed to their underlying libsodium names.
|
||||||
|
|
||||||
|
### Removed [1.0.0]
|
||||||
|
|
||||||
|
- The functions of the form `aead_chacha20poly1305_*` were removed. They implement
|
||||||
|
the IETF variant, and the argument order for them were wrong. Also, they used
|
||||||
|
severely limited nonce values, which is somewhat dangerous. The `..._NONCEBYTES`
|
||||||
|
name was changed to the consistent `..._NPUBBYTES`.
|
||||||
|
|
||||||
|
### Added [1.0.0]
|
||||||
|
|
||||||
|
- Added `aead_chacha20poly1305_ietf_*` variants.
|
||||||
|
- Implement multipart signature support, by Garry Hill.
|
||||||
|
- Implement enacl:crypto_sign_seed_keypair/1, by Ole Andre Birkedal.
|
||||||
|
- Implement enacl:crypto_sign_ed25519_sk_to_pk/1, by an anonymous contribution.
|
||||||
|
- Added AEAD XChaCha20-Poly1305 support, thanks to Github/ECrownofFire.
|
||||||
|
- The Password Hash Generation functions now support memory and operations limits,
|
||||||
|
thanks to Github/ECrownofFire.
|
||||||
|
- Implement enacl:randombytes_uint32/0. Returns a random 32bit unsigned
|
||||||
|
integer, by means of the underlying random source.
|
||||||
|
- Implement enacl:randombytes_uniform/1. Takes up to a 32bit unsigned
|
||||||
|
integer and produces a uniform integer in the range [0..N). Note
|
||||||
|
that the implementation avoids the typical non-uniformness which
|
||||||
|
would be present on a modulus operation on the nearest power-of-two
|
||||||
|
integer.
|
||||||
|
- Added Win32 build support (Tino Breddin)
|
||||||
|
- Added a nix shell for easier development
|
||||||
|
|
||||||
|
### Changed [1.0.0]
|
||||||
|
|
||||||
|
- Started a split the C code over multiple files for easier maintenance.
|
||||||
|
- Rewrote the generichash routines to be more consistent. We are now more-or-less
|
||||||
|
following the style of the Erlang/OTP `crypto` library. While here, make sure
|
||||||
|
we clean up correctly and that we don't accidentally mis-ref-count data. The
|
||||||
|
code is a bit more goto heavy, but this style is surprisingly common in C code.
|
||||||
|
- Use sodium's dynamic memory allocators. These guarantee 64bit alignment, and also
|
||||||
|
provide guard pages around the allocation, somewhat protecting it. It adds some
|
||||||
|
page table pressure compared to the current code, but is easier to maintain and
|
||||||
|
much cleaner code.
|
||||||
|
- The code now rejects updates to generichash states which were already finalized.
|
||||||
|
- We now track the desired outlen of a generichash operation in the opaque NIF
|
||||||
|
resource rather than on the Erlang side. This avoids some checks in the code,
|
||||||
|
and streamlines a good deal of the interface.
|
||||||
|
- Split AEAD routines off from the main enacl_nif.c file
|
||||||
|
- Renamed many routines from enif_* to enacl_*. This better reflects where they live
|
||||||
|
in the code base, and avoids pollution of the enif_* "namespace".
|
||||||
|
- Split Sign Public Key routines from the rest. Modernize the handling of contexts.
|
||||||
|
- The multi-part generic hash routines now follow the structure of the crypto
|
||||||
|
modules multi-part constructions in API and style.
|
||||||
|
- The AEAD constructions have been streamlined so they follow the rules of libsodium
|
||||||
|
closer than before. In particular, some dead code has been removed as a result.
|
||||||
|
- Constants are now named by their libsodium counterpart. This should make it easier
|
||||||
|
to find the correct names given the libsodium documentation.
|
||||||
|
- Generichash now checks if a `_final` call has already happened and rejects further
|
||||||
|
hashing on the object. The rejection is an error: if you ever do this, your code
|
||||||
|
is definitely wrong and there is no recovery possible.
|
||||||
|
|
||||||
|
### Fixed [1.0.0]
|
||||||
|
|
||||||
|
- Fix a resource leak in generichash/sign init/update/final.
|
||||||
|
- Clang static analysis warnings (Thomas Arts).
|
||||||
|
- Replace a constant 31 with a computation from libsodium (Thomas Arts, from a security review).
|
||||||
|
- Some subtle memory leaks in the error path for kx operations were plugged.
|
||||||
|
- The multi-part generichash interface is now properly process/thread safe.
|
||||||
|
- The sign interface is now properly process/thread safe.
|
||||||
|
|
||||||
## [0.17.2]
|
## [0.17.2]
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.17.2]
|
||||||
|
|
||||||
- Work around `rebar3 hex` publishing .so files
|
- Work around `rebar3 hex` publishing .so files
|
||||||
|
|
||||||
## [0.17.1]
|
## [0.17.1]
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.17.1]
|
||||||
|
|
||||||
- Provide a fix for the `pwhash_str/x` functions. The C strings were
|
- Provide a fix for the `pwhash_str/x` functions. The C strings were
|
||||||
not properly handled wrt. NULL-termination and what the libsodium
|
not properly handled wrt. NULL-termination and what the libsodium
|
||||||
library expects.
|
library expects.
|
||||||
|
|
||||||
## [0.17.0]
|
## [0.17.0]
|
||||||
|
|
||||||
### Added
|
### Added [0.17.0]
|
||||||
|
|
||||||
- Expose the AEAD ChaCha20 Poly1305 (IETF) functionality (Hans
|
- Expose the AEAD ChaCha20 Poly1305 (IETF) functionality (Hans
|
||||||
Svensson / Quviq).
|
Svensson / Quviq).
|
||||||
- Expose Curve25519 Scalar Multiplication over a base point in the
|
- Expose Curve25519 Scalar Multiplication over a base point in the
|
||||||
@ -33,11 +149,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||||||
to verify the enacl library on embedded platforms and so on.
|
to verify the enacl library on embedded platforms and so on.
|
||||||
- Support generichash functions (Venkatakumar Srinivasan / Xaptum)
|
- Support generichash functions (Venkatakumar Srinivasan / Xaptum)
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.17.0]
|
||||||
|
|
||||||
- The type specification of generichash/2 and generichash/3 was
|
- The type specification of generichash/2 and generichash/3 was
|
||||||
corrected (Technion)
|
corrected (Technion)
|
||||||
|
|
||||||
### Changed
|
### Changed [0.17.0]
|
||||||
|
|
||||||
- Removed the experimental feature flag `ERL_NIF_DIRTY_JOB_CPU_BOUND`.
|
- Removed the experimental feature flag `ERL_NIF_DIRTY_JOB_CPU_BOUND`.
|
||||||
This breaks compatibility with older Erlang releases of dirty
|
This breaks compatibility with older Erlang releases of dirty
|
||||||
schedulers, but prepares us correctly for the new releases where the
|
schedulers, but prepares us correctly for the new releases where the
|
||||||
@ -55,24 +173,26 @@ Bump libsodium requirement to version 1.0.12. This gives us access to
|
|||||||
a number of functions which are added recently and thus gives us
|
a number of functions which are added recently and thus gives us
|
||||||
access to implement these from libsodium.
|
access to implement these from libsodium.
|
||||||
|
|
||||||
### Added
|
### Added [0.16.0]
|
||||||
|
|
||||||
- Add kx_* functions (Alexander Malaev)
|
- Add kx_* functions (Alexander Malaev)
|
||||||
- chacha stream functions added, siphash-2-4 added, unsafe_memzero/1
|
- chacha stream functions added, siphash-2-4 added, unsafe_memzero/1
|
||||||
added (no attribution)
|
added (no attribution)
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.16.0]
|
||||||
|
|
||||||
- Do not use the dirty-scheduler test macro as it is gone.
|
- Do not use the dirty-scheduler test macro as it is gone.
|
||||||
|
|
||||||
## [0.15.0]
|
## [0.15.0]
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.15.0]
|
||||||
|
|
||||||
- Using `enacl:sign_verify_detacted` on large iolists would fail to do
|
- 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
|
the correct thing due to a typo. This has been corrected. Also the
|
||||||
EQC tests have been extended to include large binary support to
|
EQC tests have been extended to include large binary support to
|
||||||
capture these kinds of errors in the future.
|
capture these kinds of errors in the future.
|
||||||
|
|
||||||
### Changed
|
### Changed [0.15.0]
|
||||||
|
|
||||||
- Many dirty-scheduler tunings have been performed to make sure we
|
- Many dirty-scheduler tunings have been performed to make sure we
|
||||||
won't block a scheduler ever.
|
won't block a scheduler ever.
|
||||||
@ -88,33 +208,40 @@ a better citizen to other libraries and other parts of the system.
|
|||||||
|
|
||||||
## [0.14.0]
|
## [0.14.0]
|
||||||
|
|
||||||
### Added
|
### Added [0.14.0]
|
||||||
|
|
||||||
- Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr)
|
- Add support for libsodiums `box_seal` functions (Amir Ghassemi Nasr)
|
||||||
- Add support for libsodiums `crypto_sign_detached` (Joel Stanley,
|
- Add support for libsodiums `crypto_sign_detached` (Joel Stanley,
|
||||||
Parnell Springmeyer)
|
Parnell Springmeyer)
|
||||||
### Changed
|
|
||||||
|
### Changed [0.14.0]
|
||||||
|
|
||||||
- Switch the tag names to the form `0.14.0` rather than `v0.14.0`. For
|
- 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
|
this release both tags are present, but from the next release on, it
|
||||||
won't be the case.
|
won't be the case.
|
||||||
|
|
||||||
## [0.13.0]
|
## [0.13.0]
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.13.0]
|
||||||
|
|
||||||
- Quell warnings from the C code
|
- Quell warnings from the C code
|
||||||
|
|
||||||
### Added
|
### Added [0.13.0]
|
||||||
|
|
||||||
- Add Ed 25519 utility API (Alexander Færøy)
|
- Add Ed 25519 utility API (Alexander Færøy)
|
||||||
- Add FreeBSD support for the NIF compilation (Ricardo Lanziano)
|
- Add FreeBSD support for the NIF compilation (Ricardo Lanziano)
|
||||||
|
|
||||||
## [0.12.1]
|
## [0.12.1]
|
||||||
|
|
||||||
### Changed
|
### Changed [0.12.1]
|
||||||
|
|
||||||
- Provide the `priv` directory for being able to properly build
|
- Provide the `priv` directory for being able to properly build
|
||||||
without manual intervention.
|
without manual intervention.
|
||||||
|
|
||||||
## [0.12.0]
|
## [0.12.0]
|
||||||
|
|
||||||
### Added
|
### Added [0.12.0]
|
||||||
|
|
||||||
- Introduce an extension interface for various necessary extensions to
|
- Introduce an extension interface for various necessary extensions to
|
||||||
the eNaCl system for handling the Tor network, thanks to Alexander
|
the eNaCl system for handling the Tor network, thanks to Alexander
|
||||||
Færøy (ahf).
|
Færøy (ahf).
|
||||||
@ -124,12 +251,15 @@ a better citizen to other libraries and other parts of the system.
|
|||||||
|
|
||||||
## [0.11.0]
|
## [0.11.0]
|
||||||
|
|
||||||
### Added
|
### Added [0.11.0]
|
||||||
|
|
||||||
- Introduce NIF layer beforenm/afternm calls.
|
- Introduce NIF layer beforenm/afternm calls.
|
||||||
- Introduce the API for precomputed keys (beforenm/afternm calls).
|
- Introduce the API for precomputed keys (beforenm/afternm calls).
|
||||||
- Use test cases which tries to inject `iodata()` rather than binaries
|
- Use test cases which tries to inject `iodata()` rather than binaries
|
||||||
in all places where `iodata()` tend to be accepted.
|
in all places where `iodata()` tend to be accepted.
|
||||||
### Fixed
|
|
||||||
|
### Fixed [0.11.0]
|
||||||
|
|
||||||
- Fix type for `enacl:box_open/4`. The specification was wrong which
|
- Fix type for `enacl:box_open/4`. The specification was wrong which
|
||||||
results in errors in other applications using enacl.
|
results in errors in other applications using enacl.
|
||||||
|
|
||||||
@ -137,7 +267,8 @@ a better citizen to other libraries and other parts of the system.
|
|||||||
|
|
||||||
Maintenance release. Fix some usability problems with the library.
|
Maintenance release. Fix some usability problems with the library.
|
||||||
|
|
||||||
### Fixed
|
### Fixed [0.10.2]
|
||||||
|
|
||||||
- Do not compile the C NIF code if there are no dirty scheduler
|
- Do not compile the C NIF code if there are no dirty scheduler
|
||||||
support in the Erlang system (Thanks to David N. Welton)
|
support in the Erlang system (Thanks to David N. Welton)
|
||||||
- Fix dialyzer warnings (Thanks Anthony Ramine)
|
- Fix dialyzer warnings (Thanks Anthony Ramine)
|
||||||
@ -151,7 +282,7 @@ Maintenance release. Fix some usability problems with the library.
|
|||||||
|
|
||||||
## [0.10.1]
|
## [0.10.1]
|
||||||
|
|
||||||
### Added
|
### Added [0.10.1]
|
||||||
|
|
||||||
- This small patch-release provides tests for the `randombytes/1`
|
- This small patch-release provides tests for the `randombytes/1`
|
||||||
function call, and optimizes EQC tests to make it easier to implement
|
function call, and optimizes EQC tests to make it easier to implement
|
||||||
@ -167,15 +298,15 @@ included in this library.
|
|||||||
Ultra-late beta; tuning for the last couple of functions which could
|
Ultra-late beta; tuning for the last couple of functions which could
|
||||||
be nice to have.
|
be nice to have.
|
||||||
|
|
||||||
### Added
|
### Added [0.10.0]
|
||||||
|
|
||||||
Added the function `randombytes/1` to obtain randombytes from the
|
Added the function `randombytes/1` to obtain randombytes from the
|
||||||
operating system. The system uses the "best" applicable (P)RNG on the
|
operating system. The system uses the "best" applicable (P)RNG on the
|
||||||
target system:
|
target system:
|
||||||
|
|
||||||
* Windows: `RtlGenRandom()`
|
- Windows: `RtlGenRandom()`
|
||||||
* OpenBSD, Bitrig: `arc4random()`
|
- OpenBSD, Bitrig: `arc4random()`
|
||||||
* Unix in general: `/dev/urandom`
|
- Unix in general: `/dev/urandom`
|
||||||
|
|
||||||
Do note that on Linux and FreeBSD at the *least*, this is the best
|
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
|
thing you can do. Relying on `/dev/random` is almost always wrong and
|
||||||
@ -189,4 +320,3 @@ Ultra-late beta. Code probably works, but it requires some real-world
|
|||||||
use before it is deemed entirely stable.
|
use before it is deemed entirely stable.
|
||||||
|
|
||||||
Initial release.
|
Initial release.
|
||||||
|
|
||||||
|
@ -3,9 +3,15 @@ List of people who have contributed to the eNaCl source code:
|
|||||||
Alexander Færøy
|
Alexander Færøy
|
||||||
Alexander Malaev
|
Alexander Malaev
|
||||||
Amir Ghassemi Nasr
|
Amir Ghassemi Nasr
|
||||||
|
Bryan Paxton
|
||||||
|
GitHub/ECrownofFire
|
||||||
Geller Bedoya
|
Geller Bedoya
|
||||||
Jesper Louis Andersen
|
Jesper Louis Andersen
|
||||||
Joel Stanley
|
Joel Stanley
|
||||||
Konrad Zemek
|
Konrad Zemek
|
||||||
|
Nicolas Goy
|
||||||
Parnell Springmeyer
|
Parnell Springmeyer
|
||||||
Ricardo Lanziano
|
Ricardo Lanziano
|
||||||
|
Tino Breddin
|
||||||
|
Venkatakumar Srinivasan
|
||||||
|
|
||||||
|
4
Makefile
4
Makefile
@ -5,6 +5,10 @@ RUN_EQC=erl -pa _build/default/lib/enacl/ebin -noshell -s enacl_eqc -s init stop
|
|||||||
compile:
|
compile:
|
||||||
$(REBAR) compile
|
$(REBAR) compile
|
||||||
|
|
||||||
|
.PHONY: tests
|
||||||
|
tests:
|
||||||
|
$(REBAR) ct
|
||||||
|
|
||||||
eqc_compile: compile
|
eqc_compile: compile
|
||||||
erlc -o _build/default/lib/enacl/ebin eqc_test/enacl_eqc.erl
|
erlc -o _build/default/lib/enacl/ebin eqc_test/enacl_eqc.erl
|
||||||
|
|
||||||
|
73
README.md
73
README.md
@ -6,42 +6,40 @@ 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 library. The enacl project is somewhat misnamed, as it uses
|
||||||
libsodium as the underlying driver.
|
libsodium as the underlying driver.
|
||||||
|
|
||||||
Several Erlang ports of NaCl/libsodium exists, but this one is a
|
## INSTALL/Requirements
|
||||||
rewrite with the following foci:
|
|
||||||
|
|
||||||
## INSTALL/Requirements:
|
* New-ish Erlang installation. Tested back to version 22.3, but version 21 *may*
|
||||||
|
work as well.
|
||||||
|
* *Requires* the libsodium library, and has been tested with version
|
||||||
|
1.0.18. Lower versions might work, or they might fail to compile,
|
||||||
|
due to missing functionality. In particular, this means your libsodium installation
|
||||||
|
must be fairly recent as well.
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
* 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:
|
To build the software execute:
|
||||||
|
|
||||||
make
|
make
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
rebar compile
|
rebar compile
|
||||||
|
|
||||||
To build and run licensed eqc test execute:
|
To build and run licensed eqc test execute:
|
||||||
|
|
||||||
make eqc_run
|
make eqc_run
|
||||||
|
|
||||||
To build and run eqc-mini version of test execute:
|
To build and run eqc-mini version of test execute:
|
||||||
|
|
||||||
make eqc_mini_run
|
make eqc_mini_run
|
||||||
|
|
||||||
## Features:
|
## Features
|
||||||
|
|
||||||
* Complete NaCl library, implementing all default functionality.
|
* Complete NaCl library, implementing all default functionality.
|
||||||
* Implements a small set of additional functionality from libsodium.
|
* Implements a large set of additional functionality from libsodium.
|
||||||
Most notably access to a proper CSPRNG random source
|
Most notably access to a proper CSPRNG random source
|
||||||
* Tests created by aggressive use of Erlang QuickCheck.
|
* Tests created by aggressive use of Erlang QuickCheck.
|
||||||
* NaCl is a very fast cryptographic library. That is,
|
* NaCl is a very fast cryptographic library. That is,
|
||||||
@ -60,22 +58,18 @@ In addition, I would like to thank Steve Vinoski, Rickard Green, and
|
|||||||
Sverker Eriksson for providing the Dirty Scheduler API in the first
|
Sverker Eriksson for providing the Dirty Scheduler API in the first
|
||||||
place.
|
place.
|
||||||
|
|
||||||
# USING:
|
## Usage
|
||||||
|
|
||||||
In general, consult the libsodium documentation at
|
In general, consult the libsodium documentation at [Libsodium documentation](https://download.libsodium.org/doc/)
|
||||||
|
|
||||||
https://download.libsodium.org/doc/
|
|
||||||
|
|
||||||
The original NaCl documentation is nowadays largely superceded by the
|
The original NaCl documentation is nowadays largely superceded by the
|
||||||
libsodium documentation, but it is still worth a visit
|
libsodium documentation, but it is still worth a visit [NaCl website](https://nacl.cr.yp.to)
|
||||||
|
|
||||||
https://nacl.cr.yp.to
|
|
||||||
|
|
||||||
but also note that our interface has full Edoc documentation,
|
but also note that our interface has full Edoc documentation,
|
||||||
generated by executing
|
generated by executing
|
||||||
|
|
||||||
rebar3 doc
|
rebar3 doc
|
||||||
|
|
||||||
## Hints
|
## Hints
|
||||||
|
|
||||||
In general, the primitives provided by NaCl are intermediate-level
|
In general, the primitives provided by NaCl are intermediate-level
|
||||||
@ -132,11 +126,11 @@ However, their correct use is still needed in order to be secure:
|
|||||||
a foreign system as an oracle in order to learn the structure of a
|
a foreign system as an oracle in order to learn the structure of a
|
||||||
string, breaking the cryptograhic system in the process.
|
string, breaking the cryptograhic system in the process.
|
||||||
|
|
||||||
# Versions
|
## Versions
|
||||||
|
|
||||||
See CHANGELOG.md
|
See CHANGELOG.md
|
||||||
|
|
||||||
# Overview
|
## Overview
|
||||||
|
|
||||||
The NaCl cryptographic library provides a number of different
|
The NaCl cryptographic library provides a number of different
|
||||||
cryptographic primitives. In the following, we split up the different
|
cryptographic primitives. In the following, we split up the different
|
||||||
@ -198,7 +192,7 @@ This implements cryptography where there is a shared secret key between parties.
|
|||||||
* *String comparison:* Implements guaranteed constant-time string
|
* *String comparison:* Implements guaranteed constant-time string
|
||||||
comparisons to protect against timing attacks.
|
comparisons to protect against timing attacks.
|
||||||
|
|
||||||
# Rationale
|
## Rationale
|
||||||
|
|
||||||
Doing crypto right in Erlang is not that easy. For one, the crypto
|
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
|
system has to be rather fast, which rules out Erlang as the main
|
||||||
@ -250,7 +244,7 @@ perhaps being able to switch faster. There are plans to rerun these
|
|||||||
tests on OSX and Illumos as well, in order to investigate the numbers
|
tests on OSX and Illumos as well, in order to investigate the numbers
|
||||||
on more platforms.
|
on more platforms.
|
||||||
|
|
||||||
# Testing
|
## Testing
|
||||||
|
|
||||||
Every primitive has been stress-tested through the use of Erlang
|
Every primitive has been stress-tested through the use of Erlang
|
||||||
QuickCheck with both *positive* and *negative* testing. This has been
|
QuickCheck with both *positive* and *negative* testing. This has been
|
||||||
@ -277,11 +271,8 @@ sure we have no memory leaks as they will show themselves under the
|
|||||||
extensive QuickCheck test cases we run. It has been verified there are
|
extensive QuickCheck test cases we run. It has been verified there are
|
||||||
no leaks in the code.
|
no leaks in the code.
|
||||||
|
|
||||||
# Notes
|
## Notes
|
||||||
|
|
||||||
[0] Other people have worked on bits and pieces of NaCl. These are
|
[0] Other people have worked on bits and pieces of NaCl. These are
|
||||||
just the 3 main authors. Please see the page
|
just the 3 main authors. Please see the page [NaCl](http://nacl.cr.yp.to)
|
||||||
|
|
||||||
http://nacl.cr.yp.to
|
|
||||||
|
|
||||||
for the full list of authors.
|
for the full list of authors.
|
||||||
|
@ -20,7 +20,7 @@ test() ->
|
|||||||
|
|
||||||
randombytes() ->
|
randombytes() ->
|
||||||
randombytes(100*1000).
|
randombytes(100*1000).
|
||||||
|
|
||||||
randombytes(0) -> ok;
|
randombytes(0) -> ok;
|
||||||
randombytes(N) ->
|
randombytes(N) ->
|
||||||
enacl:randombytes(1024),
|
enacl:randombytes(1024),
|
||||||
@ -29,7 +29,7 @@ randombytes(N) ->
|
|||||||
hash() ->
|
hash() ->
|
||||||
B = binary:copy(<<0>>, 4096),
|
B = binary:copy(<<0>>, 4096),
|
||||||
hash(B, 10*1000).
|
hash(B, 10*1000).
|
||||||
|
|
||||||
hash(_B, 0) -> ok;
|
hash(_B, 0) -> ok;
|
||||||
hash(B, N) ->
|
hash(B, N) ->
|
||||||
enacl:hash(B),
|
enacl:hash(B),
|
||||||
@ -37,7 +37,7 @@ hash(B, N) ->
|
|||||||
|
|
||||||
box_keypair() ->
|
box_keypair() ->
|
||||||
box_keypair(10*1000).
|
box_keypair(10*1000).
|
||||||
|
|
||||||
box_keypair(0) -> ok;
|
box_keypair(0) -> ok;
|
||||||
box_keypair(N) ->
|
box_keypair(N) ->
|
||||||
enacl:box_keypair(),
|
enacl:box_keypair(),
|
||||||
@ -47,9 +47,9 @@ box() ->
|
|||||||
#{ public := PK1} = enacl:box_keypair(),
|
#{ public := PK1} = enacl:box_keypair(),
|
||||||
#{ secret := SK2} = enacl:box_keypair(),
|
#{ secret := SK2} = enacl:box_keypair(),
|
||||||
B = binary:copy(<<0>>, 1),
|
B = binary:copy(<<0>>, 1),
|
||||||
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
|
Nonce = binary:copy(<<0>>, enacl:box_NONCEBYTES()()),
|
||||||
box(B, Nonce, PK1, SK2, 10*1000).
|
box(B, Nonce, PK1, SK2, 10*1000).
|
||||||
|
|
||||||
box(_B, _Nonce, _PK1, _SK2, 0) -> ok;
|
box(_B, _Nonce, _PK1, _SK2, 0) -> ok;
|
||||||
box(B, Nonce, PK1, SK2, N) ->
|
box(B, Nonce, PK1, SK2, N) ->
|
||||||
enacl:box(B, Nonce, PK1, SK2),
|
enacl:box(B, Nonce, PK1, SK2),
|
||||||
@ -62,15 +62,15 @@ box_before_after() ->
|
|||||||
box_beforenm(PK1, SK2, 10*1000),
|
box_beforenm(PK1, SK2, 10*1000),
|
||||||
R = enacl:box_beforenm(PK1, SK2),
|
R = enacl:box_beforenm(PK1, SK2),
|
||||||
B = binary:copy(<<0>>, 8192),
|
B = binary:copy(<<0>>, 8192),
|
||||||
Nonce = binary:copy(<<0>>, enacl:box_nonce_size()),
|
Nonce = binary:copy(<<0>>, enacl:box_NONCEBYTES()()),
|
||||||
box_afternm(B, Nonce, R, 10*1000),
|
box_afternm(B, Nonce, R, 10*1000),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
box_beforenm(_PK, _SK, 0) -> ok;
|
box_beforenm(_PK, _SK, 0) -> ok;
|
||||||
box_beforenm(PK, SK, N) ->
|
box_beforenm(PK, SK, N) ->
|
||||||
enacl:box_beforenm(PK, SK),
|
enacl:box_beforenm(PK, SK),
|
||||||
box_beforenm(PK, SK, N-1).
|
box_beforenm(PK, SK, N-1).
|
||||||
|
|
||||||
box_afternm(_Msg, _Nonce, _Key, 0) -> ok;
|
box_afternm(_Msg, _Nonce, _Key, 0) -> ok;
|
||||||
box_afternm(Msg, Nonce, Key, N) ->
|
box_afternm(Msg, Nonce, Key, N) ->
|
||||||
enacl:box_afternm(Msg, Nonce, Key),
|
enacl:box_afternm(Msg, Nonce, Key),
|
||||||
@ -78,7 +78,7 @@ box_afternm(Msg, Nonce, Key, N) ->
|
|||||||
|
|
||||||
sign_keypair() ->
|
sign_keypair() ->
|
||||||
sign_keypair(10*1000).
|
sign_keypair(10*1000).
|
||||||
|
|
||||||
sign_keypair(0) -> ok;
|
sign_keypair(0) -> ok;
|
||||||
sign_keypair(N) ->
|
sign_keypair(N) ->
|
||||||
enacl:sign_keypair(),
|
enacl:sign_keypair(),
|
||||||
@ -91,7 +91,7 @@ sign() ->
|
|||||||
Msg = binary:copy(<<0>>, 1024),
|
Msg = binary:copy(<<0>>, 1024),
|
||||||
#{ secret := SK } = enacl:sign_keypair(),
|
#{ secret := SK } = enacl:sign_keypair(),
|
||||||
sign(Msg, SK, 10*1000).
|
sign(Msg, SK, 10*1000).
|
||||||
|
|
||||||
sign(_Msg, _SK, 0) -> ok;
|
sign(_Msg, _SK, 0) -> ok;
|
||||||
sign(Msg, SK, N) ->
|
sign(Msg, SK, N) ->
|
||||||
enacl:sign(Msg, SK),
|
enacl:sign(Msg, SK),
|
||||||
@ -100,10 +100,10 @@ sign(Msg, SK, N) ->
|
|||||||
|
|
||||||
secretbox() ->
|
secretbox() ->
|
||||||
Msg = binary:copy(<<0>>, 8192),
|
Msg = binary:copy(<<0>>, 8192),
|
||||||
Nonce = binary:copy(<<0>>, enacl:secretbox_nonce_size()),
|
Nonce = binary:copy(<<0>>, enacl:secretbox_NONCEBYTES()()),
|
||||||
Key = binary:copy(<<0>>, enacl:secretbox_key_size()),
|
Key = binary:copy(<<0>>, enacl:secretbox_KEYBYTES()),
|
||||||
secretbox(Msg, Nonce, Key, 10*1000).
|
secretbox(Msg, Nonce, Key, 10*1000).
|
||||||
|
|
||||||
secretbox(_Msg, _Nonce, _Key, 0) -> ok;
|
secretbox(_Msg, _Nonce, _Key, 0) -> ok;
|
||||||
secretbox(Msg, Nonce, Key, N) ->
|
secretbox(Msg, Nonce, Key, N) ->
|
||||||
enacl:secretbox(Msg, Nonce, Key),
|
enacl:secretbox(Msg, Nonce, Key),
|
||||||
@ -111,8 +111,8 @@ secretbox(Msg, Nonce, Key, N) ->
|
|||||||
|
|
||||||
|
|
||||||
stream() ->
|
stream() ->
|
||||||
stream(16384, binary:copy(<<0>>, enacl:stream_nonce_size()), binary:copy(<<0>>, enacl:stream_key_size()), 10*1000).
|
stream(16384, binary:copy(<<0>>, enacl:stream_NONCEBYTES()), binary:copy(<<0>>, enacl:stream_KEYBYTES()), 10*1000).
|
||||||
|
|
||||||
stream(_L, _Nonce, _K, 0) -> ok;
|
stream(_L, _Nonce, _K, 0) -> ok;
|
||||||
stream(L, Nonce, K, N) ->
|
stream(L, Nonce, K, N) ->
|
||||||
enacl:stream(L, Nonce, K),
|
enacl:stream(L, Nonce, K),
|
||||||
@ -120,31 +120,31 @@ stream(L, Nonce, K, N) ->
|
|||||||
|
|
||||||
auth() ->
|
auth() ->
|
||||||
Msg = binary:copy(<<0>>, 4096),
|
Msg = binary:copy(<<0>>, 4096),
|
||||||
Key = binary:copy(<<0>>, enacl:auth_key_size()),
|
Key = binary:copy(<<0>>, enacl:auth_KEYBYTES()),
|
||||||
auth(Msg, Key, 10*1000).
|
auth(Msg, Key, 10*1000).
|
||||||
|
|
||||||
auth(_Msg, _Key, 0) -> ok;
|
auth(_Msg, _Key, 0) -> ok;
|
||||||
auth(Msg, Key, N) ->
|
auth(Msg, Key, N) ->
|
||||||
enacl:auth(Msg, Key),
|
enacl:auth(Msg, Key),
|
||||||
auth(Msg, Key, N-1).
|
auth(Msg, Key, N-1).
|
||||||
|
|
||||||
onetime_auth() ->
|
onetime_auth() ->
|
||||||
Msg = binary:copy(<<0>>, 16384),
|
Msg = binary:copy(<<0>>, 16384),
|
||||||
Key = binary:copy(<<0>>, enacl:onetime_auth_key_size()),
|
Key = binary:copy(<<0>>, enacl:onetime_auth_KEYBYTES()),
|
||||||
onetime_auth(Msg, Key, 10*1000).
|
onetime_auth(Msg, Key, 10*1000).
|
||||||
|
|
||||||
onetime_auth(_Msg, _Key, 0) -> ok;
|
onetime_auth(_Msg, _Key, 0) -> ok;
|
||||||
onetime_auth(Msg, Key, N) ->
|
onetime_auth(Msg, Key, N) ->
|
||||||
enacl:onetime_auth(Msg, Key),
|
enacl:onetime_auth(Msg, Key),
|
||||||
onetime_auth(Msg, Key, N-1).
|
onetime_auth(Msg, Key, N-1).
|
||||||
|
|
||||||
scalarmult() ->
|
scalarmult() ->
|
||||||
Secret = binary:copy(<<0>>, 32),
|
Secret = binary:copy(<<0>>, 32),
|
||||||
BasePoint = binary:copy(<<1>>, 32),
|
BasePoint = binary:copy(<<1>>, 32),
|
||||||
scalarmult(Secret, BasePoint, 10*1000).
|
scalarmult(Secret, BasePoint, 10*1000).
|
||||||
|
|
||||||
scalarmult(_S, _B, 0) -> ok;
|
scalarmult(_S, _B, 0) -> ok;
|
||||||
scalarmult(S, B, N) ->
|
scalarmult(S, B, N) ->
|
||||||
enacl:curve25519_scalarmult(S, B),
|
enacl:curve25519_scalarmult(S, B),
|
||||||
scalarmult(S, B, N-1).
|
scalarmult(S, B, N-1).
|
||||||
|
|
||||||
|
242
c_src/aead.c
Normal file
242
c_src/aead.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "aead.h"
|
||||||
|
#include "enacl.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AEAD ChaCha20 Poly1305
|
||||||
|
*/
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_KEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_ABYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX(
|
||||||
|
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env,
|
||||||
|
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary key, nonce, ad, message, ciphertext;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &message))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &ad))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &nonce))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[3], &key))
|
||||||
|
goto bad_arg;
|
||||||
|
if (key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(message.size +
|
||||||
|
crypto_aead_chacha20poly1305_ietf_ABYTES,
|
||||||
|
&ciphertext)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.data, NULL, message.data,
|
||||||
|
message.size, ad.data, ad.size,
|
||||||
|
NULL, nonce.data, key.data);
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &ciphertext);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary key, nonce, ad, message, ciphertext;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &ciphertext))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &ad))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &nonce))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[3], &key))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (ciphertext.size < crypto_aead_chacha20poly1305_ietf_ABYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(ciphertext.size -
|
||||||
|
crypto_aead_chacha20poly1305_ietf_ABYTES,
|
||||||
|
&message)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||||
|
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
|
||||||
|
ad.size, nonce.data, key.data) != 0) {
|
||||||
|
ret = enacl_error_tuple(env, "failed_verification");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &message);
|
||||||
|
goto done;
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release:
|
||||||
|
enif_release_binary(&message);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AEAD XChaCha20 Poly1305
|
||||||
|
*/
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_ABYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX(
|
||||||
|
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env,
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary key, nonce, ad, message, ciphertext;
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &message))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &ad))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &nonce))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[3], &key))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(message.size +
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_ABYTES,
|
||||||
|
&ciphertext)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||||
|
ciphertext.data, NULL, message.data, message.size, ad.data, ad.size, NULL,
|
||||||
|
nonce.data, key.data);
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &ciphertext);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary key, nonce, ad, message, ciphertext;
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &ciphertext))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &ad))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &nonce))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[3], &key))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (ciphertext.size < crypto_aead_xchacha20poly1305_ietf_ABYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(ciphertext.size -
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_ABYTES,
|
||||||
|
&message)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||||
|
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
|
||||||
|
ad.size, nonce.data, key.data) != 0) {
|
||||||
|
ret = enacl_error_tuple(env, "failed_verification");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &message);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release:
|
||||||
|
enif_release_binary(&message);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
46
c_src/aead.h
Normal file
46
c_src/aead.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef ENACL_AEAD_H
|
||||||
|
#define ENACL_AEAD_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
/* AEAD ChaCha20 Poly1305 */
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX(
|
||||||
|
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_chacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
/* AEAD XChaCha20 Poly1305 */
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_ABYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX(
|
||||||
|
ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_encrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_aead_xchacha20poly1305_ietf_decrypt(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
16
c_src/enacl.c
Normal file
16
c_src/enacl.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *env, char *error_atom) {
|
||||||
|
return enif_make_tuple2(env, enif_make_atom(env, "error"),
|
||||||
|
enif_make_atom(env, error_atom));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *env) {
|
||||||
|
return enif_raise_exception(env, enif_make_atom(env, "enacl_internal_error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_error_finalized(ErlNifEnv *env) {
|
||||||
|
return enif_raise_exception(env, enif_make_atom(env, "enacl_finalized"));
|
||||||
|
}
|
15
c_src/enacl.h
Normal file
15
c_src/enacl.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef ENACL_H
|
||||||
|
#define ENACL_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#define ATOM_OK "ok"
|
||||||
|
#define ATOM_ERROR "error"
|
||||||
|
#define ATOM_TRUE "true"
|
||||||
|
#define ATOM_FALSE "false"
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *);
|
||||||
|
ERL_NIF_TERM enacl_error_finalized(ErlNifEnv *);
|
||||||
|
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *);
|
||||||
|
|
||||||
|
#endif
|
86
c_src/enacl_ext.c
Normal file
86
c_src/enacl_ext.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "enacl_ext.h"
|
||||||
|
|
||||||
|
static void uint64_pack(unsigned char *y, ErlNifUInt64 x) {
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
x >>= 8;
|
||||||
|
*y++ = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErlNifUInt64 uint64_unpack(const unsigned char *x) {
|
||||||
|
ErlNifUInt64 result;
|
||||||
|
|
||||||
|
result = x[7];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[6];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[5];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[4];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[3];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[2];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[1];
|
||||||
|
result <<= 8;
|
||||||
|
result |= x[0];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crypto_block(unsigned char *out, const unsigned char *in,
|
||||||
|
const unsigned char *k) {
|
||||||
|
ErlNifUInt64 v0 = uint64_unpack(in + 0);
|
||||||
|
ErlNifUInt64 v1 = uint64_unpack(in + 8);
|
||||||
|
ErlNifUInt64 k0 = uint64_unpack(k + 0);
|
||||||
|
ErlNifUInt64 k1 = uint64_unpack(k + 8);
|
||||||
|
ErlNifUInt64 k2 = uint64_unpack(k + 16);
|
||||||
|
ErlNifUInt64 k3 = uint64_unpack(k + 24);
|
||||||
|
ErlNifUInt64 sum = 0;
|
||||||
|
ErlNifUInt64 delta = 0x9e3779b97f4a7c15;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
sum += delta;
|
||||||
|
v0 += ((v1 << 7) + k0) ^ (v1 + sum) ^ ((v1 >> 12) + k1);
|
||||||
|
v1 += ((v0 << 16) + k2) ^ (v0 + sum) ^ ((v0 >> 8) + k3);
|
||||||
|
}
|
||||||
|
uint64_pack(out + 0, v0);
|
||||||
|
uint64_pack(out + 8, v1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_scramble_block_16(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary in, out, key;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &in)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &key)) || (in.size != 16) ||
|
||||||
|
(key.size != 32)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(in.size, &out)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_block(out.data, in.data, key.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &out);
|
||||||
|
}
|
9
c_src/enacl_ext.h
Normal file
9
c_src/enacl_ext.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef ENACL_EXT_H
|
||||||
|
#define ENACL_EXT_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_scramble_block_16(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
2065
c_src/enacl_nif.c
2065
c_src/enacl_nif.c
File diff suppressed because it is too large
Load Diff
302
c_src/generichash.c
Normal file
302
c_src/generichash.c
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
#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;
|
||||||
|
unsigned int data_size;
|
||||||
|
enacl_generichash_ctx *obj = NULL;
|
||||||
|
|
||||||
|
// Validate the arguments
|
||||||
|
if (argc != 2)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_get_resource(env, argv[0],
|
||||||
|
(ErlNifResourceType *)enacl_generic_hash_ctx_rtype,
|
||||||
|
(void **)&obj))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &data))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
enif_mutex_lock(obj->mtx);
|
||||||
|
if (!obj->alive) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update hash state
|
||||||
|
if (0 != crypto_generichash_update(obj->ctx, data.data, data.size)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = argv[0];
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_error_finalized(env);
|
||||||
|
done:
|
||||||
|
enif_mutex_unlock(obj->mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary hash;
|
||||||
|
enacl_generichash_ctx *obj = NULL;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_get_resource(env, argv[0], enacl_generic_hash_ctx_rtype,
|
||||||
|
(void **)&obj))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
enif_mutex_lock(obj->mtx);
|
||||||
|
if (!obj->alive) {
|
||||||
|
ret = enacl_error_finalized(env);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(obj->outlen, &hash)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_generichash_final(obj->ctx, hash.data, hash.size)) {
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize the object such that it cannot be reused by accident
|
||||||
|
if (obj->ctx)
|
||||||
|
sodium_free(obj->ctx);
|
||||||
|
obj->alive = 0;
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &hash);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release:
|
||||||
|
enif_release_binary(&hash);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
done:
|
||||||
|
enif_mutex_unlock(obj->mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
32
c_src/generichash.h
Normal file
32
c_src/generichash.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef ENACL_GENERICHASH_H
|
||||||
|
#define ENACL_GENERICHASH_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
int enacl_init_generic_hash_ctx(ErlNifEnv *env);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_BYTES(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
|
||||||
|
#endif
|
62
c_src/hash.c
Normal file
62
c_src/hash.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_shorthash_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_shorthash_KEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary a, m, k;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &k))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k.size != crypto_shorthash_KEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_shorthash_BYTES, &a)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_shorthash(a.data, m.data, m.size, k.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &a);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary input;
|
||||||
|
ErlNifBinary result;
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
|
||||||
|
if ((argc != 1) || (!enif_inspect_iolist_as_binary(env, argv[0], &input)))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_hash_BYTES, &result))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
crypto_hash(result.data, input.data, input.size);
|
||||||
|
ret = enif_make_binary(env, &result);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
17
c_src/hash.h
Normal file
17
c_src/hash.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef ENACL_HASH_H
|
||||||
|
#define ENACL_HASH_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]);
|
||||||
|
#endif
|
59
c_src/kdf.c
Normal file
59
c_src/kdf.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "kdf.h"
|
||||||
|
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_kdf_KEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_CONTEXTBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_kdf_CONTEXTBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_derive_from_key(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary m, c, r;
|
||||||
|
uint64_t id;
|
||||||
|
|
||||||
|
// Validate the arguments
|
||||||
|
if ((argc != 3) ||
|
||||||
|
(!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &c)) ||
|
||||||
|
(!enif_get_uint64(env, argv[2], &id))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Master Key length
|
||||||
|
if (m.size != crypto_kdf_KEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Context Key length
|
||||||
|
if (c.size != crypto_kdf_CONTEXTBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate memory for return binary
|
||||||
|
if (!enif_alloc_binary(crypto_kdf_KEYBYTES, &r)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_kdf_derive_from_key(r.data, r.size,
|
||||||
|
id,
|
||||||
|
(const char *)c.data,
|
||||||
|
m.data) != 0) {
|
||||||
|
/* out of memory */
|
||||||
|
enif_release_binary(&r);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enif_make_binary(env, &r);
|
||||||
|
}
|
||||||
|
|
15
c_src/kdf.h
Normal file
15
c_src/kdf.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef ENACL_KDF_H
|
||||||
|
#define ENACL_KDF_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_KEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_CONTEXTBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kdf_derive_from_key(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
151
c_src/kx.c
Normal file
151
c_src/kx.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "kx.h"
|
||||||
|
|
||||||
|
/* Key exchange */
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_kx_SECRETKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_kx_PUBLICKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_kx_SESSIONKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary pk, sk;
|
||||||
|
|
||||||
|
if (argc != 0) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_PUBLICKEYBYTES, &pk)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_SECRETKEYBYTES, &sk)) {
|
||||||
|
enif_release_binary(&pk);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_kx_keypair(pk.data, sk.data);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, enif_make_binary(env, &pk),
|
||||||
|
enif_make_binary(env, &sk));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary rx, tx, server_pk, server_sk, client_pk;
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &server_pk))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &server_sk))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &client_pk))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (server_pk.size != crypto_kx_PUBLICKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (server_sk.size != crypto_kx_SECRETKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (client_pk.size != crypto_kx_PUBLICKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) {
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) {
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
goto release_rx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_kx_server_session_keys(rx.data, tx.data, server_pk.data,
|
||||||
|
server_sk.data, client_pk.data)) {
|
||||||
|
// suspicious client public key
|
||||||
|
ret = enacl_error_tuple(env, "invalid_client_public_key");
|
||||||
|
goto release_tx_rx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_tuple2(env, enif_make_binary(env, &rx),
|
||||||
|
enif_make_binary(env, &tx));
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release_tx_rx:
|
||||||
|
enif_release_binary(&tx);
|
||||||
|
release_rx:
|
||||||
|
enif_release_binary(&rx);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary rx, tx, client_pk, client_sk, server_pk;
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[0], &client_pk))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &client_sk))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &server_pk))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (client_pk.size != crypto_kx_PUBLICKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (client_sk.size != crypto_kx_SECRETKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (server_pk.size != crypto_kx_PUBLICKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) {
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) {
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
goto release_rx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_kx_client_session_keys(rx.data, tx.data, client_pk.data,
|
||||||
|
client_sk.data, server_pk.data)) {
|
||||||
|
// suspicious server public key
|
||||||
|
ret = enacl_error_tuple(env, "invalid_server_public_key");
|
||||||
|
goto release_tx_rx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_tuple2(env, enif_make_binary(env, &rx),
|
||||||
|
enif_make_binary(env, &tx));
|
||||||
|
goto done;
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release_tx_rx:
|
||||||
|
enif_release_binary(&tx);
|
||||||
|
release_rx:
|
||||||
|
enif_release_binary(&rx);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
24
c_src/kx.h
Normal file
24
c_src/kx.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef ENACL_KX_H
|
||||||
|
#define ENACL_KX_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
286
c_src/public.c
Normal file
286
c_src/public.c
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "public.h"
|
||||||
|
|
||||||
|
/* Public-key cryptography */
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_NONCEBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_ZEROBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_BOXZEROBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_PUBLICKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_SECRETKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_BEFORENMBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_box_SEALBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary pk, sk;
|
||||||
|
|
||||||
|
if (argc != 0) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_box_PUBLICKEYBYTES, &pk)) {
|
||||||
|
return enacl_error_tuple(env, "alloc_failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_box_SECRETKEYBYTES, &sk)) {
|
||||||
|
enif_release_binary(&pk);
|
||||||
|
return enacl_error_tuple(env, "alloc_failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_box_keypair(pk.data, sk.data);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, enif_make_binary(env, &pk),
|
||||||
|
enif_make_binary(env, &sk));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary padded_msg, nonce, pk, sk, result;
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &nonce))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &pk))
|
||||||
|
goto bad_arg;
|
||||||
|
if (!enif_inspect_binary(env, argv[3], &sk))
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (nonce.size != crypto_box_NONCEBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (pk.size != crypto_box_PUBLICKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (sk.size != crypto_box_SECRETKEYBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
if (padded_msg.size < crypto_box_ZEROBYTES)
|
||||||
|
goto bad_arg;
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(padded_msg.size, &result)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data,
|
||||||
|
pk.data, sk.data)) {
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_sub_binary(env, enif_make_binary(env, &result),
|
||||||
|
crypto_box_BOXZEROBYTES,
|
||||||
|
padded_msg.size - crypto_box_BOXZEROBYTES);
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
release:
|
||||||
|
enif_release_binary(&result);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary padded_ciphertext, nonce, pk, sk, result;
|
||||||
|
|
||||||
|
if ((argc != 4) ||
|
||||||
|
(!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &nonce)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[2], &pk)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[3], &sk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nonce.size != crypto_box_NONCEBYTES) ||
|
||||||
|
(pk.size != crypto_box_PUBLICKEYBYTES) ||
|
||||||
|
(sk.size != crypto_box_SECRETKEYBYTES) ||
|
||||||
|
(padded_ciphertext.size < crypto_box_BOXZEROBYTES)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(padded_ciphertext.size, &result)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_box_open(result.data, padded_ciphertext.data,
|
||||||
|
padded_ciphertext.size, nonce.data, pk.data,
|
||||||
|
sk.data)) {
|
||||||
|
enif_release_binary(&result);
|
||||||
|
return enacl_error_tuple(env, "failed_verification");
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
|
||||||
|
ERL_NIF_TERM ret_bin = enif_make_sub_binary(
|
||||||
|
env, enif_make_binary(env, &result), crypto_box_ZEROBYTES,
|
||||||
|
padded_ciphertext.size - crypto_box_ZEROBYTES);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, ret_ok, ret_bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Precomputed crypto boxes */
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary k, pk, sk;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &pk)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &sk)) ||
|
||||||
|
(pk.size != crypto_box_PUBLICKEYBYTES) ||
|
||||||
|
(sk.size != crypto_box_SECRETKEYBYTES)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) {
|
||||||
|
// error
|
||||||
|
enif_release_binary(&k);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return enif_make_binary(env, &k);
|
||||||
|
err:
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary result, m, nonce, k;
|
||||||
|
|
||||||
|
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &nonce)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[2], &k)) ||
|
||||||
|
(m.size < crypto_box_ZEROBYTES) ||
|
||||||
|
(nonce.size != crypto_box_NONCEBYTES) ||
|
||||||
|
(k.size != crypto_box_BEFORENMBYTES)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(m.size, &result)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data);
|
||||||
|
|
||||||
|
return enif_make_sub_binary(env, enif_make_binary(env, &result),
|
||||||
|
crypto_box_BOXZEROBYTES,
|
||||||
|
m.size - crypto_box_BOXZEROBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary result, m, nonce, k;
|
||||||
|
|
||||||
|
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &nonce)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[2], &k)) ||
|
||||||
|
(m.size < crypto_box_BOXZEROBYTES) ||
|
||||||
|
(nonce.size != crypto_box_NONCEBYTES) ||
|
||||||
|
(k.size != crypto_box_BEFORENMBYTES)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(m.size, &result)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data,
|
||||||
|
k.data)) {
|
||||||
|
enif_release_binary(&result);
|
||||||
|
return enacl_error_tuple(env, "failed_verification");
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
|
||||||
|
ERL_NIF_TERM ret_bin =
|
||||||
|
enif_make_sub_binary(env, enif_make_binary(env, &result),
|
||||||
|
crypto_box_ZEROBYTES, m.size - crypto_box_ZEROBYTES);
|
||||||
|
return enif_make_tuple2(env, ret_ok, ret_bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sealed box functions */
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary key, msg, ciphertext;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &msg)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &key))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary pk, sk, ciphertext, msg;
|
||||||
|
|
||||||
|
if ((argc != 3) ||
|
||||||
|
(!enif_inspect_iolist_as_binary(env, argv[0], &ciphertext)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &pk)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[2], &sk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ciphertext.size < crypto_box_SEALBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data,
|
||||||
|
sk.data) != 0) {
|
||||||
|
enif_release_binary(&msg);
|
||||||
|
return enacl_error_tuple(env, "failed_verification");
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
|
||||||
|
ERL_NIF_TERM ret_bin = enif_make_binary(env, &msg);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, ret_ok, ret_bin);
|
||||||
|
}
|
49
c_src/public.h
Normal file
49
c_src/public.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef ENACL_PUBLIC_H
|
||||||
|
#define ENACL_PUBLIC_H
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
180
c_src/pwhash.c
Normal file
180
c_src/pwhash.c
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "pwhash.h"
|
||||||
|
|
||||||
|
static size_t enacl_pwhash_opslimit(ErlNifEnv *env, ERL_NIF_TERM arg) {
|
||||||
|
ERL_NIF_TERM a;
|
||||||
|
size_t r;
|
||||||
|
|
||||||
|
if (enif_is_atom(env, arg)) {
|
||||||
|
a = enif_make_atom(env, "interactive");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_OPSLIMIT_INTERACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "moderate");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_OPSLIMIT_MODERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "sensitive");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_OPSLIMIT_SENSITIVE;
|
||||||
|
}
|
||||||
|
} else if (enif_get_ulong(env, arg, &r)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t enacl_pwhash_memlimit(ErlNifEnv *env, ERL_NIF_TERM arg) {
|
||||||
|
ERL_NIF_TERM a;
|
||||||
|
size_t r;
|
||||||
|
|
||||||
|
if (enif_is_atom(env, arg)) {
|
||||||
|
a = enif_make_atom(env, "interactive");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_MEMLIMIT_INTERACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "moderate");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_MEMLIMIT_MODERATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "sensitive");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_MEMLIMIT_SENSITIVE;
|
||||||
|
}
|
||||||
|
} else if (enif_get_ulong(env, arg, &r)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_SALTBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_pwhash_SALTBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int enacl_pwhash_alg(ErlNifEnv *env, ERL_NIF_TERM arg) {
|
||||||
|
ERL_NIF_TERM a;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (enif_is_atom(env, arg)) {
|
||||||
|
a = enif_make_atom(env, "default");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_ALG_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "argon2i13");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_ALG_ARGON2I13;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = enif_make_atom(env, "argon2id13");
|
||||||
|
if (enif_is_identical(a, arg)) {
|
||||||
|
return crypto_pwhash_ALG_ARGON2ID13;
|
||||||
|
}
|
||||||
|
} else if (enif_get_int(env, arg, &r)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary h, p, s;
|
||||||
|
size_t o, m;
|
||||||
|
int alg;
|
||||||
|
|
||||||
|
// Validate the arguments
|
||||||
|
if ((argc != 5) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &s)) ||
|
||||||
|
!(o = enacl_pwhash_opslimit(env, argv[2])) ||
|
||||||
|
!(m = enacl_pwhash_memlimit(env, argv[3])) ||
|
||||||
|
!(alg = enacl_pwhash_alg(env, argv[4]))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check limits
|
||||||
|
if ((o < crypto_pwhash_OPSLIMIT_MIN) || (o > crypto_pwhash_OPSLIMIT_MAX) ||
|
||||||
|
(m < crypto_pwhash_MEMLIMIT_MIN) || (m > crypto_pwhash_MEMLIMIT_MAX)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Salt size
|
||||||
|
if (s.size != crypto_pwhash_SALTBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate memory for return binary
|
||||||
|
if (!enif_alloc_binary(crypto_box_SEEDBYTES, &h)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_pwhash(h.data, h.size, (char *)p.data, p.size, s.data, o, m,
|
||||||
|
alg) != 0) {
|
||||||
|
/* out of memory */
|
||||||
|
enif_release_binary(&h);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enif_make_binary(env, &h);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary h, p;
|
||||||
|
size_t o, m;
|
||||||
|
|
||||||
|
// Validate the arguments
|
||||||
|
if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) ||
|
||||||
|
!(o = enacl_pwhash_opslimit(env, argv[1])) ||
|
||||||
|
!(m = enacl_pwhash_memlimit(env, argv[2]))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check limits
|
||||||
|
if ((o < crypto_pwhash_OPSLIMIT_MIN) || (o > crypto_pwhash_OPSLIMIT_MAX) ||
|
||||||
|
(m < crypto_pwhash_MEMLIMIT_MIN) || (m > crypto_pwhash_MEMLIMIT_MAX)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate memory for return binary
|
||||||
|
if (!enif_alloc_binary(crypto_pwhash_STRBYTES, &h)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_pwhash_str((char *)h.data, (char *)p.data, p.size, o, m) != 0) {
|
||||||
|
/* out of memory */
|
||||||
|
enif_release_binary(&h);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enif_make_binary(env, &h);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary h, p;
|
||||||
|
// Validate the arguments
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &h)) ||
|
||||||
|
(!enif_inspect_iolist_as_binary(env, argv[1], &p))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM ret = enif_make_atom(env, ATOM_TRUE);
|
||||||
|
if (crypto_pwhash_str_verify((char *)h.data, (char *)p.data, p.size) != 0) {
|
||||||
|
/* wrong password */
|
||||||
|
ret = enif_make_atom(env, ATOM_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
18
c_src/pwhash.h
Normal file
18
c_src/pwhash.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef ENACL_PWHASH_H
|
||||||
|
#define ENACL_PWHASH_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_SALTBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
49
c_src/randombytes.c
Normal file
49
c_src/randombytes.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
#include "enacl.h"
|
||||||
|
#include "randombytes.h"
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
unsigned req_size;
|
||||||
|
ErlNifBinary result;
|
||||||
|
|
||||||
|
if ((argc != 1) || (!enif_get_uint(env, argv[0], &req_size))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(req_size, &result)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
randombytes(result.data, result.size);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes_uint32(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifUInt64 result;
|
||||||
|
|
||||||
|
if (argc != 0) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = randombytes_random();
|
||||||
|
return enif_make_uint64(env, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes_uniform(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
unsigned upper_bound;
|
||||||
|
ErlNifUInt64 result;
|
||||||
|
|
||||||
|
if ((argc != 1) || (!enif_get_uint(env, argv[0], &upper_bound))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = randombytes_uniform(upper_bound);
|
||||||
|
return enif_make_uint64(env, result);
|
||||||
|
}
|
15
c_src/randombytes.h
Normal file
15
c_src/randombytes.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef ENACL_RANDOMBYTES_H
|
||||||
|
#define ENACL_RANDOMBYTES_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes_uint32(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enif_randombytes_uniform(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
324
c_src/secret.c
Normal file
324
c_src/secret.c
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
#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_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");
|
||||||
|
}
|
||||||
|
}
|
70
c_src/secret.h
Normal file
70
c_src/secret.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#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_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
|
460
c_src/secretstream.c
Normal file
460
c_src/secretstream.c
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#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) {
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
obj->alive = 1;
|
||||||
|
|
||||||
|
if ((obj->mtx = enif_mutex_create("enacl.secretstream")) == NULL) {
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_secretstream_xchacha20poly1305_init_pull(obj->state, header.data,
|
||||||
|
key.data);
|
||||||
|
|
||||||
|
ret = enif_make_resource(env, obj);
|
||||||
|
|
||||||
|
goto release;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
free:
|
||||||
|
if (obj->alive)
|
||||||
|
if (obj->state != NULL) {
|
||||||
|
sodium_memzero(obj->state,
|
||||||
|
crypto_secretstream_xchacha20poly1305_statebytes());
|
||||||
|
enif_free(obj->state);
|
||||||
|
obj->state = NULL;
|
||||||
|
}
|
||||||
|
release:
|
||||||
|
// This also frees the mutex via the destructor
|
||||||
|
enif_release_resource(obj);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void
|
||||||
|
crypto_secretstream_xchacha20poly1305_rekey
|
||||||
|
(crypto_secretstream_xchacha20poly1305_state *state)
|
||||||
|
*/
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_secretstream_xchacha20poly1305_rekey(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
enacl_secretstream_ctx *obj = NULL;
|
||||||
|
|
||||||
|
if (argc != 1) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_resource(env, argv[0],
|
||||||
|
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
|
||||||
|
(void **)&obj)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
enif_mutex_lock(obj->mtx);
|
||||||
|
if (!obj->alive) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_secretstream_xchacha20poly1305_rekey(obj->state);
|
||||||
|
|
||||||
|
ret = enif_make_atom(env, ATOM_OK);
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_error_finalized(env);
|
||||||
|
done:
|
||||||
|
enif_mutex_unlock(obj->mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int
|
||||||
|
crypto_secretstream_xchacha20poly1305_push
|
||||||
|
(crypto_secretstream_xchacha20poly1305_state *state,
|
||||||
|
unsigned char *out, unsigned long long *outlen_p,
|
||||||
|
const unsigned char *m, unsigned long long mlen,
|
||||||
|
const unsigned char *ad, unsigned long long adlen, unsigned char tag)
|
||||||
|
*/
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_secretstream_xchacha20poly1305_push(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary m, ad, out;
|
||||||
|
ErlNifUInt64 tag;
|
||||||
|
enacl_secretstream_ctx *obj = NULL;
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_resource(env, argv[0],
|
||||||
|
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
|
||||||
|
(void **)&obj)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &m)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &ad)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_uint64(env, argv[3], &tag)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(m.size + crypto_secretstream_xchacha20poly1305_ABYTES,
|
||||||
|
&out)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
enif_mutex_lock(obj->mtx);
|
||||||
|
if (!obj->alive) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_secretstream_xchacha20poly1305_push(obj->state, out.data, NULL, m.data,
|
||||||
|
m.size, ad.data, ad.size, tag);
|
||||||
|
|
||||||
|
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
|
||||||
|
if (obj->state) {
|
||||||
|
obj->alive = 0;
|
||||||
|
sodium_memzero(obj->state,
|
||||||
|
crypto_secretstream_xchacha20poly1305_statebytes());
|
||||||
|
enif_free(obj->state);
|
||||||
|
obj->state = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_binary(env, &out);
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_error_finalized(env);
|
||||||
|
enif_release_binary(&out);
|
||||||
|
done:
|
||||||
|
enif_mutex_unlock(obj->mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
crypto_secretstream_xchacha20poly1305_pull
|
||||||
|
(crypto_secretstream_xchacha20poly1305_state *state,
|
||||||
|
unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
|
||||||
|
const unsigned char *in, unsigned long long inlen,
|
||||||
|
const unsigned char *ad, unsigned long long adlen)
|
||||||
|
*/
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_secretstream_xchacha20poly1305_pull(ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]) {
|
||||||
|
ERL_NIF_TERM ret;
|
||||||
|
ErlNifBinary m, in, ad;
|
||||||
|
unsigned char tag;
|
||||||
|
enacl_secretstream_ctx *obj = NULL;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_get_resource(env, argv[0],
|
||||||
|
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
|
||||||
|
(void **)&obj)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[1], &in)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_inspect_binary(env, argv[2], &ad)) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
|
||||||
|
goto bad_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(in.size - crypto_secretstream_xchacha20poly1305_ABYTES,
|
||||||
|
&m)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
enif_mutex_lock(obj->mtx);
|
||||||
|
if (!obj->alive) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != crypto_secretstream_xchacha20poly1305_pull(obj->state, m.data, NULL,
|
||||||
|
&tag, in.data, in.size,
|
||||||
|
ad.data, ad.size)) {
|
||||||
|
ret = enacl_error_tuple(env, "failed_verification");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
|
||||||
|
if (obj->state) {
|
||||||
|
obj->alive = 0;
|
||||||
|
sodium_memzero(obj->state,
|
||||||
|
crypto_secretstream_xchacha20poly1305_statebytes());
|
||||||
|
enif_free(obj->state);
|
||||||
|
obj->state = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = enif_make_tuple2(env, enif_make_binary(env, &m),
|
||||||
|
enif_make_int64(env, tag));
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bad_arg:
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
err:
|
||||||
|
ret = enacl_error_finalized(env);
|
||||||
|
release:
|
||||||
|
enif_release_binary(&m);
|
||||||
|
done:
|
||||||
|
enif_mutex_unlock(obj->mtx);
|
||||||
|
return ret;
|
||||||
|
}
|
78
c_src/secretstream.h
Normal file
78
c_src/secretstream.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef ENACL_SECRETSTREAM_H
|
||||||
|
#define ENACL_SECRETSTREAM_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
int enacl_init_secretstream_ctx(ErlNifEnv *env);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_ABYTES(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_keygen(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_rekey(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_push(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_pull(
|
||||||
|
ErlNifEnv *env, int argc,
|
||||||
|
const ERL_NIF_TERM argv[]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
484
c_src/sign.c
Normal file
484
c_src/sign.c
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
#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) {
|
||||||
|
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:
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &curve25519_pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary curve25519_sk, ed25519_sk;
|
||||||
|
|
||||||
|
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &ed25519_sk)) ||
|
||||||
|
(ed25519_sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_sk)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.data, ed25519_sk.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &curve25519_sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_sign_ed25519_PUBLICKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_sign_ed25519_SECRETKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_sign_PUBLICKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_sign_SECRETKEYBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_SEEDBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_sign_SEEDBYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary pk, sk;
|
||||||
|
|
||||||
|
if (argc != 0) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
|
||||||
|
enif_release_binary(&pk);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign_keypair(pk.data, sk.data);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, enif_make_binary(env, &pk),
|
||||||
|
enif_make_binary(env, &sk));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_seed_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary pk, sk, seed;
|
||||||
|
|
||||||
|
if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &seed))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
|
||||||
|
enif_release_binary(&pk);
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign_seed_keypair(pk.data, sk.data, seed.data);
|
||||||
|
|
||||||
|
return enif_make_tuple2(env, enif_make_binary(env, &pk),
|
||||||
|
enif_make_binary(env, &sk));
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary m, sk, sm;
|
||||||
|
unsigned long long smlen;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &sk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sk.size != crypto_sign_SECRETKEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(m.size + crypto_sign_BYTES, &sm)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign(sm.data, &smlen, m.data, m.size, sk.data);
|
||||||
|
|
||||||
|
return enif_make_sub_binary(env, enif_make_binary(env, &sm), 0, smlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary m, sm, pk;
|
||||||
|
unsigned long long mlen;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &sm)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &pk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pk.size != crypto_sign_PUBLICKEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(sm.size, &m)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == crypto_sign_open(m.data, &mlen, sm.data, sm.size, pk.data)) {
|
||||||
|
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
|
||||||
|
ERL_NIF_TERM ret_bin =
|
||||||
|
enif_make_sub_binary(env, enif_make_binary(env, &m), 0, mlen);
|
||||||
|
return enif_make_tuple2(env, ret_ok, ret_bin);
|
||||||
|
} else {
|
||||||
|
enif_release_binary(&m);
|
||||||
|
return enacl_error_tuple(env, "failed_verification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_detached(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary m, sk, sig;
|
||||||
|
unsigned long long siglen;
|
||||||
|
|
||||||
|
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[1], &sk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sk.size != crypto_sign_SECRETKEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
|
||||||
|
return enacl_internal_error(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sign_detached(sig.data, &siglen, m.data, m.size, sk.data);
|
||||||
|
|
||||||
|
return enif_make_binary(env, &sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]) {
|
||||||
|
ErlNifBinary m, sig, pk;
|
||||||
|
|
||||||
|
if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &sig)) ||
|
||||||
|
(!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
|
||||||
|
(!enif_inspect_binary(env, argv[2], &pk))) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sig.size != crypto_sign_BYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pk.size != crypto_sign_PUBLICKEYBYTES) {
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == crypto_sign_verify_detached(sig.data, m.data, m.size, pk.data)) {
|
||||||
|
return enif_make_atom(env, ATOM_TRUE);
|
||||||
|
} else {
|
||||||
|
return enif_make_atom(env, ATOM_FALSE);
|
||||||
|
}
|
||||||
|
}
|
70
c_src/sign.h
Normal file
70
c_src/sign.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef ENACL_SIGN_H
|
||||||
|
#define ENACL_SIGN_H
|
||||||
|
|
||||||
|
#include <erl_nif.h>
|
||||||
|
|
||||||
|
int enacl_init_sign_ctx(ErlNifEnv *env);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_ed25519_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_ed25519_sk_to_pk(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_SEEDBYTES(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_seed_keypair(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_open(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM enacl_crypto_sign_detached(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
ERL_NIF_TERM
|
||||||
|
enacl_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
|
||||||
|
ERL_NIF_TERM const argv[]);
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +1,6 @@
|
|||||||
-module(enacl_eqc).
|
-module(enacl_eqc).
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
-compile(export_all).
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
-ifndef(mini).
|
-ifndef(mini).
|
||||||
-compile({parse_transform, eqc_parallelize}).
|
-compile({parse_transform, eqc_parallelize}).
|
||||||
@ -83,8 +83,8 @@ v_binary(_, _) -> false.
|
|||||||
|
|
||||||
|
|
||||||
%% Typical generators based on the binaries
|
%% Typical generators based on the binaries
|
||||||
nonce() -> g_binary(enacl:box_nonce_size()).
|
nonce() -> g_binary(enacl:box_NONCEBYTES()).
|
||||||
nonce_valid(N) -> v_binary(enacl:box_nonce_size(), N).
|
nonce_valid(N) -> v_binary(enacl:box_NONCEBYTES(), N).
|
||||||
|
|
||||||
%% Generator of natural numbers
|
%% Generator of natural numbers
|
||||||
g_nat() ->
|
g_nat() ->
|
||||||
@ -111,10 +111,10 @@ keypair_bad() ->
|
|||||||
#{ public := PK, secret := SK} = enacl:box_keypair(),
|
#{ public := PK, secret := SK} = enacl:box_keypair(),
|
||||||
case X of
|
case X of
|
||||||
pk ->
|
pk ->
|
||||||
PKBytes = enacl:box_public_key_bytes(),
|
PKBytes = enacl:box_PUBLICKEYBYTES(),
|
||||||
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
|
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
|
||||||
sk ->
|
sk ->
|
||||||
SKBytes = enacl:box_secret_key_bytes(),
|
SKBytes = enacl:box_SECRETKEYBYTES(),
|
||||||
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
|
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
|
||||||
end
|
end
|
||||||
end).
|
end).
|
||||||
@ -122,6 +122,35 @@ keypair_bad() ->
|
|||||||
keypair() ->
|
keypair() ->
|
||||||
?FAULT(keypair_bad(), keypair_good()).
|
?FAULT(keypair_bad(), keypair_good()).
|
||||||
|
|
||||||
|
kx_keypair_good() ->
|
||||||
|
#{ public := PK, secret := SK} = enacl:kx_keypair(),
|
||||||
|
{PK, SK}.
|
||||||
|
|
||||||
|
kx_keypair_bad() ->
|
||||||
|
?LET(X, elements([pk, sk]),
|
||||||
|
begin
|
||||||
|
#{ public := PK, secret := SK} = enacl:box_keypair(),
|
||||||
|
case X of
|
||||||
|
pk ->
|
||||||
|
PKBytes = enacl:kx_public_key_size(),
|
||||||
|
{oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= PKBytes)]), SK};
|
||||||
|
sk ->
|
||||||
|
SKBytes = enacl:kx_secret_key_size(),
|
||||||
|
{PK, oneof([return(a), nat(), ?SUCHTHAT(B, binary(), byte_size(B) /= SKBytes)])}
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
|
g_generichash_data() ->
|
||||||
|
binary().
|
||||||
|
|
||||||
|
g_generichash_key() ->
|
||||||
|
?LET({Min, Max}, {return(enacl_nif:crypto_generichash_KEYBYTES_MIN()), return(enacl_nif:crypto_generichash_KEYBYTES_MAX())},
|
||||||
|
largebinary({limit, Min, Max})).
|
||||||
|
|
||||||
|
g_generichash_size() ->
|
||||||
|
?LET({Min, Max}, {return(enacl_nif:crypto_generichash_BYTES_MIN()), return(enacl_nif:crypto_generichash_BYTES_MAX())},
|
||||||
|
choose(Min, Max)).
|
||||||
|
|
||||||
%% CRYPTO BOX
|
%% CRYPTO BOX
|
||||||
%% ---------------------------
|
%% ---------------------------
|
||||||
%% * box/4
|
%% * box/4
|
||||||
@ -130,8 +159,8 @@ keypair() ->
|
|||||||
%% * box_afternm/3
|
%% * box_afternm/3
|
||||||
%% * box_open_afternm/3
|
%% * box_open_afternm/3
|
||||||
keypair_valid(PK, SK) when is_binary(PK), is_binary(SK) ->
|
keypair_valid(PK, SK) when is_binary(PK), is_binary(SK) ->
|
||||||
PKBytes = enacl:box_public_key_bytes(),
|
PKBytes = enacl:box_PUBLICKEYBYTES(),
|
||||||
SKBytes = enacl:box_secret_key_bytes(),
|
SKBytes = enacl:box_SECRETKEYBYTES(),
|
||||||
byte_size(PK) == PKBytes andalso byte_size(SK) == SKBytes;
|
byte_size(PK) == PKBytes andalso byte_size(SK) == SKBytes;
|
||||||
keypair_valid(_PK, _SK) -> false.
|
keypair_valid(_PK, _SK) -> false.
|
||||||
|
|
||||||
@ -235,11 +264,11 @@ beforenm_key() ->
|
|||||||
oneof([
|
oneof([
|
||||||
elements([a,b,c]),
|
elements([a,b,c]),
|
||||||
real(),
|
real(),
|
||||||
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_beforenm_bytes())
|
?SUCHTHAT(X, binary(), byte_size(X) /= enacl:box_BEFORENMBYTES())
|
||||||
])
|
])
|
||||||
end).
|
end).
|
||||||
|
|
||||||
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_beforenm_bytes();
|
v_key(K) when is_binary(K) -> byte_size(K) == enacl:box_BEFORENMBYTES();
|
||||||
v_key(_) -> false.
|
v_key(_) -> false.
|
||||||
|
|
||||||
prop_beforenm_correct() ->
|
prop_beforenm_correct() ->
|
||||||
@ -295,11 +324,11 @@ sign_keypair_bad() ->
|
|||||||
KP = enacl:sign_keypair(),
|
KP = enacl:sign_keypair(),
|
||||||
case X of
|
case X of
|
||||||
pk ->
|
pk ->
|
||||||
Sz = enacl:sign_keypair_public_size(),
|
Sz = enacl:sign_PUBLICBYTES(),
|
||||||
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
|
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
|
||||||
KP#{ public := Wrong });
|
KP#{ public := Wrong });
|
||||||
sk ->
|
sk ->
|
||||||
Sz = enacl:sign_keypair_secret_size(),
|
Sz = enacl:sign_SECRETBYTES(),
|
||||||
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
|
?LET(Wrong, oneof([a, int(), ?SUCHTHAT(B, binary(), byte_size(B) /= Sz)]),
|
||||||
KP#{ secret := Wrong })
|
KP#{ secret := Wrong })
|
||||||
end
|
end
|
||||||
@ -313,12 +342,12 @@ sign_keypair() ->
|
|||||||
|
|
||||||
sign_keypair_public_valid(#{ public := Public })
|
sign_keypair_public_valid(#{ public := Public })
|
||||||
when is_binary(Public) ->
|
when is_binary(Public) ->
|
||||||
byte_size(Public) == enacl:sign_keypair_public_size();
|
byte_size(Public) == enacl:sign_PUBLICBYTES();
|
||||||
sign_keypair_public_valid(_) -> false.
|
sign_keypair_public_valid(_) -> false.
|
||||||
|
|
||||||
sign_keypair_secret_valid(#{ secret := Secret })
|
sign_keypair_secret_valid(#{ secret := Secret })
|
||||||
when is_binary(Secret) ->
|
when is_binary(Secret) ->
|
||||||
byte_size(Secret) == enacl:sign_keypair_secret_size();
|
byte_size(Secret) == enacl:sign_SECRETBYTES();
|
||||||
sign_keypair_secret_valid(_) -> false.
|
sign_keypair_secret_valid(_) -> false.
|
||||||
|
|
||||||
sign_keypair_valid(KP) ->
|
sign_keypair_valid(KP) ->
|
||||||
@ -379,18 +408,18 @@ signed_message_good_d(M) ->
|
|||||||
end)}]).
|
end)}]).
|
||||||
|
|
||||||
signed_message_bad() ->
|
signed_message_bad() ->
|
||||||
Sz = enacl:sign_keypair_public_size(),
|
Sz = enacl:sign_PUBLICBYTES(),
|
||||||
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
|
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
|
||||||
|
|
||||||
signed_message_bad_d() ->
|
signed_message_bad_d() ->
|
||||||
Sz = enacl:sign_keypair_public_size(),
|
Sz = enacl:sign_PUBLICBYTES(),
|
||||||
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
|
{binary(), oneof([a, int(), ?SUCHTHAT(B, binary(Sz), byte_size(B) /= Sz)])}.
|
||||||
|
|
||||||
signed_message(M) ->
|
signed_message(M) ->
|
||||||
?FAULT(signed_message_bad(), signed_message_good(M)).
|
?FAULT(signed_message_bad(), signed_message_good(M)).
|
||||||
|
|
||||||
signed_message_d(M) ->
|
signed_message_d(M) ->
|
||||||
?FAULT(signed_message_bad(), signed_message_good(M)).
|
?FAULT(signed_message_bad_d(), signed_message_good_d(M)).
|
||||||
|
|
||||||
signed_message_valid({valid, _}, _) -> true;
|
signed_message_valid({valid, _}, _) -> true;
|
||||||
signed_message_valid({invalid, _}, _) -> true;
|
signed_message_valid({invalid, _}, _) -> true;
|
||||||
@ -403,9 +432,9 @@ prop_sign_detached_open() ->
|
|||||||
true ->
|
true ->
|
||||||
case SignMsg of
|
case SignMsg of
|
||||||
{valid, Sig} ->
|
{valid, Sig} ->
|
||||||
equals({ok, Msg}, enacl:sign_verify_detached(Sig, Msg, PK));
|
equals(true, enacl:sign_verify_detached(Sig, Msg, PK));
|
||||||
{invalid, Sig} ->
|
{invalid, Sig} ->
|
||||||
equals({error, failed_verification}, enacl:sign_verify_detached(Sig, Msg, PK))
|
equals(false, enacl:sign_verify_detached(Sig, Msg, PK))
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
badargs(fun() -> enacl:sign_verify_detached(SignMsg, Msg, PK) end)
|
badargs(fun() -> enacl:sign_verify_detached(SignMsg, Msg, PK) end)
|
||||||
@ -467,19 +496,19 @@ prop_seal_box_correct() ->
|
|||||||
%% * secretbox/3
|
%% * secretbox/3
|
||||||
%% * secretbo_open/3
|
%% * secretbo_open/3
|
||||||
secret_key_good() ->
|
secret_key_good() ->
|
||||||
Sz = enacl:secretbox_key_size(),
|
Sz = enacl:secretbox_KEYBYTES(),
|
||||||
binary(Sz).
|
binary(Sz).
|
||||||
|
|
||||||
secret_key_bad() ->
|
secret_key_bad() ->
|
||||||
oneof([return(a),
|
oneof([return(a),
|
||||||
nat(),
|
nat(),
|
||||||
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_key_size())]).
|
?SUCHTHAT(B, binary(), byte_size(B) /= enacl:secretbox_KEYBYTES())]).
|
||||||
|
|
||||||
secret_key() ->
|
secret_key() ->
|
||||||
?FAULT(secret_key_bad(), secret_key_good()).
|
?FAULT(secret_key_bad(), secret_key_good()).
|
||||||
|
|
||||||
secret_key_valid(SK) when is_binary(SK) ->
|
secret_key_valid(SK) when is_binary(SK) ->
|
||||||
Sz = enacl:secretbox_key_size(),
|
Sz = enacl:secretbox_KEYBYTES(),
|
||||||
byte_size(SK) == Sz;
|
byte_size(SK) == Sz;
|
||||||
secret_key_valid(_SK) -> false.
|
secret_key_valid(_SK) -> false.
|
||||||
|
|
||||||
@ -525,20 +554,45 @@ prop_secretbox_failure_integrity() ->
|
|||||||
%% ------------------------------------------------------------
|
%% ------------------------------------------------------------
|
||||||
%% * aead_chacha20poly1305_encrypt/4,
|
%% * aead_chacha20poly1305_encrypt/4,
|
||||||
%% * aead_chacha20poly1305_decrypt/4,
|
%% * aead_chacha20poly1305_decrypt/4,
|
||||||
prop_aead_chacha20poly1305() ->
|
prop_aead_chacha20poly1305_ietf() ->
|
||||||
|
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
|
||||||
?FORALL({Key, Msg, AD, Nonce},
|
?FORALL({Key, Msg, AD, Nonce},
|
||||||
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), largeint()},
|
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
|
||||||
begin
|
begin
|
||||||
EncryptMsg = enacl:aead_chacha20poly1305_encrypt(Key, Nonce, AD, Msg),
|
EncryptMsg = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
|
||||||
equals(enacl:aead_chacha20poly1305_decrypt(Key, Nonce, AD, EncryptMsg), Msg)
|
equals(enacl:aead_chacha20poly1305_ietf_decrypt(EncryptMsg, AD, Nonce, Key), Msg)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
prop_aead_chacha20poly1305_fail() ->
|
prop_aead_chacha20poly1305_ietf_fail() ->
|
||||||
|
NPubBytes = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
|
||||||
?FORALL({Key, Msg, AD, Nonce},
|
?FORALL({Key, Msg, AD, Nonce},
|
||||||
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), largeint()},
|
{binary(32), binary(), ?LET(ADBytes, choose(0,16), binary(ADBytes)), binary(NPubBytes)},
|
||||||
begin
|
begin
|
||||||
EncryptMsg = enacl:aead_chacha20poly1305_encrypt(Key, Nonce, AD, Msg),
|
EncryptMsg = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
|
||||||
case enacl:aead_chacha20poly1305_decrypt(Key, Nonce, AD, <<0:8, EncryptMsg/binary>>) of
|
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;
|
{error, _} -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
@ -564,23 +618,26 @@ xor_bytes(<<A, As/binary>>, <<B, Bs/binary>>) ->
|
|||||||
[A bxor B | xor_bytes(As, Bs)];
|
[A bxor B | xor_bytes(As, Bs)];
|
||||||
xor_bytes(<<>>, <<>>) -> [].
|
xor_bytes(<<>>, <<>>) -> [].
|
||||||
|
|
||||||
%% prop_stream_xor_correct() ->
|
positive() ->
|
||||||
%% ?FORALL({Msg, Nonce, Key},
|
?LET(N, nat(), N+1).
|
||||||
%% {?FAULT_RATE(1, 40, g_iodata()),
|
|
||||||
%% ?FAULT_RATE(1, 40, nonce()),
|
chacha20_nonce() ->
|
||||||
%% ?FAULT_RATE(1, 40, secret_key())},
|
Sz = enacl:stream_chacha20_NONCEBYTES(),
|
||||||
%% case v_iodata(Msg) andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of
|
binary(Sz).
|
||||||
%% true ->
|
|
||||||
%% Stream = enacl:stream(iolist_size(Msg), Nonce, Key),
|
chacha20_key() ->
|
||||||
%% CipherText = enacl:stream_xor(Msg, Nonce, Key),
|
Sz = enacl:stream_chacha20_KEYBYTES(),
|
||||||
%% StreamXor = enacl:stream_xor(CipherText, Nonce, Key),
|
binary(Sz).
|
||||||
%% conjunction([
|
|
||||||
%% {'xor', equals(iolist_to_binary(Msg), StreamXor)},
|
prop_stream_chacha20_correct() ->
|
||||||
%% {stream, equals(iolist_to_binary(xor_bytes(Stream, iolist_to_binary(Msg))), CipherText)}
|
?FORALL(Len, positive(),
|
||||||
%% ]);
|
?FORALL({Msg, Nonce, Key}, {binary(Len), chacha20_nonce(), chacha20_key()},
|
||||||
%% false ->
|
begin
|
||||||
%% badargs(fun() -> enacl:stream_xor(Msg, Nonce, Key) end)
|
CT = enacl:stream_chacha20_xor(Msg, Nonce, Key),
|
||||||
%% end).
|
Stream = enacl:stream_chacha20(Len, Nonce, Key),
|
||||||
|
CT2 = list_to_binary(xor_bytes(Stream, Msg)),
|
||||||
|
equals(CT, CT2)
|
||||||
|
end)).
|
||||||
|
|
||||||
%% CRYPTO AUTH
|
%% CRYPTO AUTH
|
||||||
%% ------------------------------------------------------------
|
%% ------------------------------------------------------------
|
||||||
@ -599,19 +656,19 @@ prop_auth_correct() ->
|
|||||||
end).
|
end).
|
||||||
|
|
||||||
authenticator_bad() ->
|
authenticator_bad() ->
|
||||||
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_size())]).
|
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_BYTES())]).
|
||||||
|
|
||||||
authenticator_good(Msg, Key) when is_binary(Key) ->
|
authenticator_good(Msg, Key) when is_binary(Key) ->
|
||||||
Sz = enacl:secretbox_key_size(),
|
Sz = enacl:secretbox_KEYBYTES(),
|
||||||
case v_iodata(Msg) andalso byte_size(Key) == Sz of
|
case v_iodata(Msg) andalso byte_size(Key) == Sz of
|
||||||
true ->
|
true ->
|
||||||
frequency([{1, ?LAZY({invalid, binary(enacl:auth_size())})},
|
frequency([{1, ?LAZY({invalid, binary(enacl:auth_BYTES())})},
|
||||||
{3, return({valid, enacl:auth(Msg, Key)})}]);
|
{3, return({valid, enacl:auth(Msg, Key)})}]);
|
||||||
false ->
|
false ->
|
||||||
binary(enacl:auth_size())
|
binary(enacl:auth_BYTES())
|
||||||
end;
|
end;
|
||||||
authenticator_good(_Msg, _Key) ->
|
authenticator_good(_Msg, _Key) ->
|
||||||
binary(enacl:auth_size()).
|
binary(enacl:auth_BYTES()).
|
||||||
|
|
||||||
authenticator(Msg, Key) ->
|
authenticator(Msg, Key) ->
|
||||||
?FAULT(authenticator_bad(), authenticator_good(Msg, Key)).
|
?FAULT(authenticator_bad(), authenticator_good(Msg, Key)).
|
||||||
@ -654,19 +711,19 @@ prop_onetimeauth_correct() ->
|
|||||||
end).
|
end).
|
||||||
|
|
||||||
ot_authenticator_bad() ->
|
ot_authenticator_bad() ->
|
||||||
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_size())]).
|
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_BYTES())]).
|
||||||
|
|
||||||
ot_authenticator_good(Msg, Key) when is_binary(Key) ->
|
ot_authenticator_good(Msg, Key) when is_binary(Key) ->
|
||||||
Sz = enacl:secretbox_key_size(),
|
Sz = enacl:secretbox_KEYBYTES(),
|
||||||
case v_iodata(Msg) andalso byte_size(Key) == Sz of
|
case v_iodata(Msg) andalso byte_size(Key) == Sz of
|
||||||
true ->
|
true ->
|
||||||
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_size())})},
|
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_BYTES())})},
|
||||||
{3, return({valid, enacl:onetime_auth(Msg, Key)})}]);
|
{3, return({valid, enacl:onetime_auth(Msg, Key)})}]);
|
||||||
false ->
|
false ->
|
||||||
binary(enacl:onetime_auth_size())
|
binary(enacl:onetime_auth_BYTES())
|
||||||
end;
|
end;
|
||||||
ot_authenticator_good(_Msg, _Key) ->
|
ot_authenticator_good(_Msg, _Key) ->
|
||||||
binary(enacl:auth_size()).
|
binary(enacl:auth_BYTES()).
|
||||||
|
|
||||||
ot_authenticator(Msg, Key) ->
|
ot_authenticator(Msg, Key) ->
|
||||||
?FAULT(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
|
?FAULT(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
|
||||||
@ -704,6 +761,13 @@ pwhash(Passwd, Salt) ->
|
|||||||
error:badarg -> badarg
|
error:badarg -> badarg
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
pwhash(Password, Salt, Ops, Mem, Alg) ->
|
||||||
|
try
|
||||||
|
enacl:pwhsah(Password, Salt, Ops, Mem, Alg)
|
||||||
|
catch
|
||||||
|
error:badarg -> badarg
|
||||||
|
end.
|
||||||
|
|
||||||
pwhash_str(Passwd) ->
|
pwhash_str(Passwd) ->
|
||||||
try
|
try
|
||||||
enacl:pwhash_str(Passwd)
|
enacl:pwhash_str(Passwd)
|
||||||
@ -718,13 +782,29 @@ pwhash_str_verify(PasswdHash, Passwd) ->
|
|||||||
error:badarg -> badarg
|
error:badarg -> badarg
|
||||||
end.
|
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() ->
|
prop_pwhash_str_verify() ->
|
||||||
?FORALL({Passwd},
|
?FORALL({Passwd, OLimit, MLimit},
|
||||||
{?FAULT_RATE(1, 40, g_iodata())},
|
{?FAULT_RATE(1, 40, g_iodata()),
|
||||||
|
elements([interactive, moderate]),
|
||||||
|
elements([interactive, moderate])},
|
||||||
begin
|
begin
|
||||||
case v_iodata(Passwd) of
|
case v_iodata(Passwd) of
|
||||||
true ->
|
true ->
|
||||||
{ok, Ascii} = enacl:pwhash_str(Passwd),
|
Ascii = enacl:pwhash_str(Passwd, OLimit, MLimit),
|
||||||
S = enacl:pwhash_str_verify(Ascii, Passwd),
|
S = enacl:pwhash_str_verify(Ascii, Passwd),
|
||||||
equals(S, true);
|
equals(S, true);
|
||||||
false ->
|
false ->
|
||||||
@ -758,6 +838,41 @@ prop_crypto_hash_neq() ->
|
|||||||
enacl:hash(X) /= enacl:hash(Y)
|
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
|
%% STRING COMPARISON
|
||||||
%% -------------------------
|
%% -------------------------
|
||||||
%% * verify_16/2,
|
%% * verify_16/2,
|
||||||
@ -817,7 +932,8 @@ prop_randombytes() ->
|
|||||||
?FORALL(X, g_nat(),
|
?FORALL(X, g_nat(),
|
||||||
case is_nat(X) of
|
case is_nat(X) of
|
||||||
true ->
|
true ->
|
||||||
is_binary(enacl:randombytes(X));
|
R = enacl:randombytes(X),
|
||||||
|
is_binary(R) andalso (byte_size(R) == X);
|
||||||
false ->
|
false ->
|
||||||
try
|
try
|
||||||
enacl:randombytes(X),
|
enacl:randombytes(X),
|
||||||
@ -828,8 +944,84 @@ prop_randombytes() ->
|
|||||||
end
|
end
|
||||||
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
|
%% INTERNAL FUNCTIONS
|
||||||
%% ------------------------------------------------------------
|
%% ------------------------------------------------------------
|
||||||
|
|
||||||
badargs(Thunk) ->
|
badargs(Thunk) ->
|
||||||
try
|
try
|
||||||
Thunk(),
|
Thunk(),
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
-module(enacl_ext_eqc).
|
-module(enacl_ext_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
-compile(export_all).
|
-compile({parse_transform, eqc_parallelize}).
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
public_keypair() ->
|
public_keypair() ->
|
||||||
?LET(#{ public := PK, secret := SK}, enacl_ext:curve25519_keypair(),
|
?LET(#{ public := PK, secret := SK}, enacl_ext:curve25519_keypair(),
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
{plugins, [pc]}.
|
{plugins, [pc]}.
|
||||||
|
|
||||||
|
{project_plugins, [rebar3_hex]}.
|
||||||
|
|
||||||
{provider_hooks, [
|
{provider_hooks, [
|
||||||
{pre, [
|
{pre, [
|
||||||
{compile, {pc, compile}},
|
{compile, {pc, compile}},
|
||||||
|
12
shell.nix
Normal file
12
shell.nix
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.hello
|
||||||
|
|
||||||
|
# keep this line if you use bash
|
||||||
|
pkgs.bashInteractive
|
||||||
|
pkgs.erlang
|
||||||
|
pkgs.libsodium
|
||||||
|
];
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{application,enacl,
|
{application,enacl,
|
||||||
[{description,"Erlang libsodium (NaCl) bindings"},
|
[{description,"Erlang libsodium (NaCl) bindings"},
|
||||||
{vsn,"0.17.2"},
|
{vsn,"1.2.1"},
|
||||||
{registered,[]},
|
{registered,[]},
|
||||||
{applications,[kernel,stdlib]},
|
{applications,[kernel,stdlib]},
|
||||||
{env,[]},
|
{env,[]},
|
||||||
|
768
src/enacl.erl
768
src/enacl.erl
File diff suppressed because it is too large
Load Diff
@ -25,8 +25,10 @@
|
|||||||
|
|
||||||
crypto_sign_PUBLICKEYBYTES/0,
|
crypto_sign_PUBLICKEYBYTES/0,
|
||||||
crypto_sign_SECRETKEYBYTES/0,
|
crypto_sign_SECRETKEYBYTES/0,
|
||||||
|
crypto_sign_SEEDBYTES/0,
|
||||||
|
|
||||||
crypto_sign_keypair/0,
|
crypto_sign_keypair/0,
|
||||||
|
crypto_sign_seed_keypair/1,
|
||||||
|
|
||||||
crypto_sign/2,
|
crypto_sign/2,
|
||||||
crypto_sign_open/2,
|
crypto_sign_open/2,
|
||||||
@ -34,6 +36,11 @@
|
|||||||
crypto_sign_detached/2,
|
crypto_sign_detached/2,
|
||||||
crypto_sign_verify_detached/3,
|
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/2,
|
||||||
crypto_box_seal_open/3,
|
crypto_box_seal_open/3,
|
||||||
crypto_box_SEALBYTES/0
|
crypto_box_SEALBYTES/0
|
||||||
@ -67,12 +74,19 @@
|
|||||||
crypto_stream_xor/3,
|
crypto_stream_xor/3,
|
||||||
crypto_stream_xor_b/3,
|
crypto_stream_xor_b/3,
|
||||||
|
|
||||||
crypto_aead_chacha20poly1305_encrypt/4,
|
crypto_aead_chacha20poly1305_ietf_encrypt/4,
|
||||||
crypto_aead_chacha20poly1305_decrypt/4,
|
crypto_aead_chacha20poly1305_ietf_decrypt/4,
|
||||||
crypto_aead_chacha20poly1305_KEYBYTES/0,
|
crypto_aead_chacha20poly1305_ietf_KEYBYTES/0,
|
||||||
crypto_aead_chacha20poly1305_NPUBBYTES/0,
|
crypto_aead_chacha20poly1305_ietf_NPUBBYTES/0,
|
||||||
crypto_aead_chacha20poly1305_ABYTES/0,
|
crypto_aead_chacha20poly1305_ietf_ABYTES/0,
|
||||||
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX/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_BYTES/0,
|
||||||
crypto_auth_KEYBYTES/0,
|
crypto_auth_KEYBYTES/0,
|
||||||
@ -105,6 +119,7 @@
|
|||||||
%% Ed 25519
|
%% Ed 25519
|
||||||
-export([
|
-export([
|
||||||
crypto_sign_ed25519_keypair/0,
|
crypto_sign_ed25519_keypair/0,
|
||||||
|
crypto_sign_ed25519_sk_to_pk/1,
|
||||||
crypto_sign_ed25519_public_to_curve25519/1,
|
crypto_sign_ed25519_public_to_curve25519/1,
|
||||||
crypto_sign_ed25519_secret_to_curve25519/1,
|
crypto_sign_ed25519_secret_to_curve25519/1,
|
||||||
crypto_sign_ed25519_PUBLICKEYBYTES/0,
|
crypto_sign_ed25519_PUBLICKEYBYTES/0,
|
||||||
@ -132,11 +147,19 @@
|
|||||||
|
|
||||||
%% Password Hashing - Argon2 Algorithm
|
%% Password Hashing - Argon2 Algorithm
|
||||||
-export([
|
-export([
|
||||||
crypto_pwhash/2,
|
crypto_pwhash_SALTBYTES/0,
|
||||||
crypto_pwhash_str/1,
|
crypto_pwhash/5,
|
||||||
|
crypto_pwhash_str/3,
|
||||||
crypto_pwhash_str_verify/2
|
crypto_pwhash_str_verify/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
%% Key Derivation
|
||||||
|
-export([
|
||||||
|
crypto_kdf_KEYBYTES/0,
|
||||||
|
crypto_kdf_CONTEXTBYTES/0,
|
||||||
|
crypto_kdf_derive_from_key/3
|
||||||
|
]).
|
||||||
|
|
||||||
%% Generic hash
|
%% Generic hash
|
||||||
-export([
|
-export([
|
||||||
crypto_generichash_BYTES/0,
|
crypto_generichash_BYTES/0,
|
||||||
@ -147,13 +170,33 @@
|
|||||||
crypto_generichash_KEYBYTES_MAX/0,
|
crypto_generichash_KEYBYTES_MAX/0,
|
||||||
crypto_generichash/3,
|
crypto_generichash/3,
|
||||||
crypto_generichash_init/2,
|
crypto_generichash_init/2,
|
||||||
crypto_generichash_update/3,
|
crypto_generichash_update/2,
|
||||||
crypto_generichash_final/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
|
%% Access to the RNG
|
||||||
-export([
|
-export([
|
||||||
randombytes/1
|
randombytes/1,
|
||||||
|
randombytes_uint32/0,
|
||||||
|
randombytes_uniform/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Undocumented features :>
|
%% Undocumented features :>
|
||||||
@ -185,13 +228,33 @@ crypto_generichash_KEYBYTES_MAX() -> erlang:nif_error(nif_not_loaded).
|
|||||||
crypto_generichash(_HashSize, _Message, _Key) -> 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_init(_HashSize, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_generichash_update(_HashSize, _HashState, _Message) -> erlang:nif_error(nif_not_loaded).
|
crypto_generichash_update(_HashState, _Message) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_generichash_final(_HashSize, _HashState) -> erlang:nif_error(nif_not_loaded).
|
crypto_generichash_final(_HashState) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
crypto_pwhash(_Password, _Salt) -> erlang:nif_error(nif_not_loaded).
|
crypto_secretstream_xchacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_pwhash_str(_Password) -> 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_pwhash_str_verify(_HashedPassword, _Password) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
|
crypto_kdf_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
|
crypto_kdf_CONTEXTBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
|
crypto_kdf_derive_from_key(_MasterKey, _Context, _Id) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
crypto_box_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_box_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_box_ZEROBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_box_ZEROBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_box_BOXZEROBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_box_BOXZEROBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
@ -211,8 +274,10 @@ crypto_box_open_afternm_b(_CipherText, _Nonce, _K) -> erlang:nif_error(nif_not_l
|
|||||||
|
|
||||||
crypto_sign_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_sign_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_sign_SECRETKEYBYTES() -> 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_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(_M, _SK) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_sign_open(_SignedMessage, _PK) -> erlang:nif_error(nif_not_loaded).
|
crypto_sign_open(_SignedMessage, _PK) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
@ -220,6 +285,11 @@ crypto_sign_detached(_M, _SK) -> erlang:nif_error(nif_not_loaded).
|
|||||||
|
|
||||||
crypto_sign_verify_detached(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded).
|
crypto_sign_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(_Msg, _PK) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_box_seal_open(_CipherText, _PK, _SK) -> 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).
|
crypto_box_SEALBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
@ -248,12 +318,19 @@ crypto_stream_b(_Bytes, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
|||||||
crypto_stream_xor(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
crypto_stream_xor(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_stream_xor_b(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
crypto_stream_xor_b(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
crypto_aead_chacha20poly1305_encrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded).
|
crypto_aead_chacha20poly1305_ietf_encrypt(_Message, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_aead_chacha20poly1305_decrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded).
|
crypto_aead_chacha20poly1305_ietf_decrypt(_CipherText, _AD, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_aead_chacha20poly1305_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_aead_chacha20poly1305_ietf_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_aead_chacha20poly1305_NPUBBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_aead_chacha20poly1305_ietf_NPUBBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_aead_chacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_aead_chacha20poly1305_ietf_ABYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX() -> 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_BYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_auth_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_auth_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
@ -277,6 +354,7 @@ crypto_curve25519_scalarmult(_Secret, _BasePoint) -> erlang:nif_error(nif_not_lo
|
|||||||
crypto_curve25519_scalarmult_base(_Secret) -> 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_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_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_secret_to_curve25519(_SecretKey) -> erlang:nif_error(nif_not_loaded).
|
||||||
crypto_sign_ed25519_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_sign_ed25519_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
@ -296,5 +374,7 @@ crypto_kx_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
|||||||
crypto_kx_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
crypto_kx_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||||
|
|
||||||
randombytes(_RequestedSize) -> 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).
|
scramble_block_16(_Block, _Key) -> erlang:nif_error(nif_not_loaded).
|
||||||
|
196
test/enacl_SUITE.erl
Normal file
196
test/enacl_SUITE.erl
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
-module(enacl_SUITE).
|
||||||
|
-include_lib("common_test/include/ct.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
suite() ->
|
||||||
|
[{timetrap, {seconds, 30}}].
|
||||||
|
|
||||||
|
init_per_group(_Group, Config) ->
|
||||||
|
Config.
|
||||||
|
|
||||||
|
end_per_group(_Group, _Config) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
init_per_suite(Config) ->
|
||||||
|
application:ensure_all_started(enacl),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
end_per_suite(_Config) ->
|
||||||
|
application:stop(enacl),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
init_per_testcase(x, Config) ->
|
||||||
|
{ok, _} = dbg:tracer(),
|
||||||
|
dbg:p(all, c),
|
||||||
|
dbg:tpl(graphql_execute, lookup_field, '_', cx),
|
||||||
|
Config;
|
||||||
|
init_per_testcase(_Case, Config) ->
|
||||||
|
Config.
|
||||||
|
|
||||||
|
end_per_testcase(x, _Config) ->
|
||||||
|
dbg:stop_clear(),
|
||||||
|
ok;
|
||||||
|
end_per_testcase(_Case, _Config) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
groups() ->
|
||||||
|
Neg = {negative, [shuffle, parallel],
|
||||||
|
[generichash_basic_neg]},
|
||||||
|
Pos = {positive, [shuffle, parallel],
|
||||||
|
[
|
||||||
|
aead_chacha20poly1305_ietf,
|
||||||
|
aead_xchacha20poly1305,
|
||||||
|
generichash_basic_pos,
|
||||||
|
generichash_chunked,
|
||||||
|
kx,
|
||||||
|
pwhash,
|
||||||
|
secretstream,
|
||||||
|
sign,
|
||||||
|
verify_detached
|
||||||
|
]},
|
||||||
|
|
||||||
|
[Neg, Pos].
|
||||||
|
|
||||||
|
all() ->
|
||||||
|
[{group, negative},
|
||||||
|
{group, positive}].
|
||||||
|
|
||||||
|
%% -- BASIC --------------------------------------
|
||||||
|
generichash_basic_neg(_Config) ->
|
||||||
|
%% Negative generichash invocations
|
||||||
|
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
|
||||||
|
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
||||||
|
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
||||||
|
Key = <<"Hash Key 123456789">>,
|
||||||
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(9, Msg, Key)),
|
||||||
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(65, Msg, Key)),
|
||||||
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(32, Msg, <<"Small">>)),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
generichash_basic_pos(_Config) ->
|
||||||
|
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
|
||||||
|
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
||||||
|
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
||||||
|
Key = <<"Hash Key 123456789">>,
|
||||||
|
<<189,104,45,187,170,229,212,4,121,43,137,74,241,173,181,77,
|
||||||
|
67,211,133,70,196,6,128,97>> = enacl:generichash(24, Msg, Key),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
generichash_chunked(_Config) ->
|
||||||
|
Msg = <<"I've seen things you people wouldn't believe: attack ships on fire off the shoulder of Orion. "
|
||||||
|
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
||||||
|
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
||||||
|
Key = <<"Hash Key 123456789">>,
|
||||||
|
State = enacl:generichash_init(24, Key),
|
||||||
|
State = generichash_chunked(State, Msg, 10000),
|
||||||
|
Expected = <<46,49,32,18,13,186,182,105,106,122,253,139,89,176,169,141,
|
||||||
|
73,93,99,6,41,216,110,41>>,
|
||||||
|
Expected = enacl:generichash_final(State),
|
||||||
|
try enacl:generichash_final(State) of
|
||||||
|
_ -> ct:fail(must_finalize)
|
||||||
|
catch
|
||||||
|
error:enacl_finalized ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
try enacl:generichash_update(State, <<"x">>) of
|
||||||
|
_ -> ct:fail(must_finalize)
|
||||||
|
catch
|
||||||
|
error:enacl_finalized ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
ok.
|
||||||
|
|
||||||
|
generichash_chunked(State, _Msg, 0) -> State;
|
||||||
|
generichash_chunked(State, Msg, N) ->
|
||||||
|
State2 = enacl:generichash_update(State, Msg),
|
||||||
|
generichash_chunked(State2, Msg, N-1).
|
||||||
|
|
||||||
|
aead_xchacha20poly1305(_Config) ->
|
||||||
|
NonceLen = enacl:aead_xchacha20poly1305_ietf_NPUBBYTES(),
|
||||||
|
KLen = enacl:aead_xchacha20poly1305_ietf_KEYBYTES(),
|
||||||
|
Key = binary:copy(<<"K">>, KLen),
|
||||||
|
Msg = <<"test">>,
|
||||||
|
AD = <<1,2,3,4,5,6>>,
|
||||||
|
Nonce = binary:copy(<<"N">>, NonceLen),
|
||||||
|
|
||||||
|
CipherText = enacl:aead_xchacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
|
||||||
|
Msg = enacl:aead_xchacha20poly1305_ietf_decrypt(CipherText, AD, Nonce, Key),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
aead_chacha20poly1305_ietf(_Config) ->
|
||||||
|
NonceLen = enacl:aead_chacha20poly1305_ietf_NPUBBYTES(),
|
||||||
|
KLen = enacl:aead_chacha20poly1305_ietf_KEYBYTES(),
|
||||||
|
Key = binary:copy(<<"K">>, KLen),
|
||||||
|
Msg = <<"test">>,
|
||||||
|
AD = <<1,2,3,4,5,6>>,
|
||||||
|
Nonce = binary:copy(<<"N">>, NonceLen),
|
||||||
|
|
||||||
|
CipherText = enacl:aead_chacha20poly1305_ietf_encrypt(Msg, AD, Nonce, Key),
|
||||||
|
Msg = enacl:aead_chacha20poly1305_ietf_decrypt(CipherText, AD, Nonce, Key),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
pwhash(_Config) ->
|
||||||
|
PW = <<"XYZZY">>,
|
||||||
|
Salt = <<"1234567890abcdef">>,
|
||||||
|
Hash1 = <<164,75,127,151,168,101,55,77,48,77,240,204,64,20,43,23,88,
|
||||||
|
18,133,11,53,151,2,113,232,95,84,165,50,7,60,20>>,
|
||||||
|
Hash1 = enacl:pwhash(PW, Salt),
|
||||||
|
Str1 = enacl:pwhash_str(PW),
|
||||||
|
true = enacl:pwhash_str_verify(Str1, PW),
|
||||||
|
false = enacl:pwhash_str_verify(Str1, <<PW/binary, 1>>),
|
||||||
|
16 = enacl:pwhash_SALTBYTES(),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
sign(_Config) ->
|
||||||
|
#{public := PK, secret := SK} = enacl:sign_keypair(),
|
||||||
|
Msg = <<"Test">>,
|
||||||
|
State = enacl:sign_init(),
|
||||||
|
Create = sign_chunked(State, Msg, 10000),
|
||||||
|
{ok, Signature} = enacl:sign_final_create(Create, SK),
|
||||||
|
StateVerify = enacl:sign_init(),
|
||||||
|
Verify = sign_chunked(StateVerify, Msg, 10000),
|
||||||
|
true = enacl:sign_final_verify(Verify, Signature, PK),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
sign_chunked(S, _M, 0) -> S;
|
||||||
|
sign_chunked(S, M, N) ->
|
||||||
|
S2 = enacl:sign_update(S, M),
|
||||||
|
sign_chunked(S2, M, N-1).
|
||||||
|
|
||||||
|
kx(_Config) ->
|
||||||
|
#{ public := CPK, secret := CSK} = enacl:kx_keypair(),
|
||||||
|
#{ public := SPK, secret := SSK} = enacl:kx_keypair(),
|
||||||
|
#{ client_tx := CTX, client_rx := CRX} = enacl:kx_client_session_keys(CPK, CSK, SPK),
|
||||||
|
#{ server_tx := STX, server_rx := SRX} = enacl:kx_server_session_keys(SPK, SSK, CPK),
|
||||||
|
%% Verify we got a shared keypair
|
||||||
|
CTX = SRX,
|
||||||
|
STX = CRX,
|
||||||
|
ok.
|
||||||
|
|
||||||
|
secretstream(_Config) ->
|
||||||
|
Part1 = <<"Arbitrary data to encrypt">>,
|
||||||
|
Part2 = <<"split into">>,
|
||||||
|
Part3 = <<"three messages">>,
|
||||||
|
|
||||||
|
Key = enacl:secretstream_xchacha20poly1305_keygen(),
|
||||||
|
|
||||||
|
%% Encrypt
|
||||||
|
{Header, State} = enacl:secretstream_xchacha20poly1305_init_push(Key),
|
||||||
|
Block1 = enacl:secretstream_xchacha20poly1305_push(State, Part1, <<"AD1">>, message),
|
||||||
|
Block2 = enacl:secretstream_xchacha20poly1305_push(State, Part2, <<>>, message),
|
||||||
|
Block3 = enacl:secretstream_xchacha20poly1305_push(State, Part3, <<"AD3">>, final),
|
||||||
|
|
||||||
|
%% Decrypt
|
||||||
|
DState = enacl:secretstream_xchacha20poly1305_init_pull(Header, Key),
|
||||||
|
{Part1, message} = enacl:secretstream_xchacha20poly1305_pull(DState, Block1, <<"AD1">>),
|
||||||
|
{Part2, message} = enacl:secretstream_xchacha20poly1305_pull(DState, Block2, <<>>),
|
||||||
|
{Part3, final} = enacl:secretstream_xchacha20poly1305_pull(DState, Block3, <<"AD3">>),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
verify_detached(_Config) ->
|
||||||
|
#{ public := PK, secret := SK} = enacl:sign_keypair(),
|
||||||
|
M = <<"Arbitrary data to encrypt">>,
|
||||||
|
Sig = enacl:sign_detached(M, SK),
|
||||||
|
true = enacl:sign_verify_detached(Sig, M, PK),
|
||||||
|
ok.
|
Loading…
x
Reference in New Issue
Block a user