Salchicha (Salchicha v0.2.0)
View SourceA pure-ish Elixir cryptography tool for the Salsa20 and ChaCha20 ciphers.
This library has a handful of crypto functions that are compatible with NaCl/libsodium for encryption and decryption with shared secret keys.
The Salsa20/XSalsa20 ciphers are implemented entirely in Elixir while the Poly1305 MAC
function is done through the Erlang :crypto
module, which is implemented as a NIF with
OpenSSL bindings.
The ChaCha20_Poly1305 AEAD cipher is already supported by the :crypto
module, but XChaCha20
is not. The HChaCha20 hash function, an intermediate step for generating an XChaCha20 sub-key,
is implemented in Elixir so :crypto
can be leveraged for XChaCha20_Poly1305.
The ChaCha20/XChaCha20 ciphers do also have pure Elixir implementations just like Salsa20/XSalsa20,
but unless you are concerned with long-running NIFs blocking schedulers, you should prefer to use
the versions that fully leverage :crypto
NIFs, the behaviour of applicable functions in this module.
If you wish to you use the elixir implementations, you can call them directly with the functions
available in Salchicha.Chacha
ending in _pure
.
While this module contains everything you'll need to encrypt and decrypt with XSalsa20_Poly1305
and XChaCha20_Poly1305 authenticated ciphers, the internal modules Salchicha.Salsa
and
Salchicha.Chacha
are documented for educational purposes and expose a few primitives.
Summary
Types
12-byte nonce used by the ChaCha20 (IETF) cipher
24-byte extended nonce used by the XSalsa20 and XChaCha20 ciphers
8-byte nonce used by the Salsa20 cipher
32-byte shared secret key used by all variations of Salsa/ChaCha
Functions
Generates a random 24-byte extended nonce
Generates a random 32-byte key
Encrypts a message with a secret key using the XSalsa20_Poly1305 authenticated cipher.
Decrypts a message that was encrypted with secretbox/3
using the XSalsa20_Poly1305 authenticated cipher.
Decrypts a message that was encrypted in "combined mode" using the XChaCha20_Poly1305 AEAD cipher.
Decrypts a message that was encrypted in "detacheded mode" using the XChaCha20_Poly1305 AEAD cipher.
Encrypts a message with a secret key using the XChaCha20_Poly1305 AEAD cipher in "combined mode".
Encrypts a message with a secret key using the XChaCha20_Poly1305 AEAD cipher in "detached mode".
Types
@type aad() :: iodata()
@type chacha_nonce() :: <<_::96>>
12-byte nonce used by the ChaCha20 (IETF) cipher
@type cipher_text() :: binary()
@type encrypted_message() :: iodata()
@type extended_nonce() :: <<_::192>>
24-byte extended nonce used by the XSalsa20 and XChaCha20 ciphers
@type message() :: iodata()
@type salsa_nonce() :: <<_::64>>
8-byte nonce used by the Salsa20 cipher
@type secret_key() :: <<_::256>>
32-byte shared secret key used by all variations of Salsa/ChaCha
@type tag() :: <<_::128>>
Functions
@spec generate_nonce() :: extended_nonce()
Generates a random 24-byte extended nonce
XSalsa20 and XChaCha20 use a 24-byte nonce, up from the 8 and 8/12 byte nonces of the respective Salsa20 and ChaCha20 ciphers.
You should never reuse the same nonce for a given secret key. 24 bytes are said to be large enough to generate nonces randomly - doing so would be ill-advised with 8-byte nonces since collision would be much more likely.
@spec generate_secret_key() :: secret_key()
Generates a random 32-byte key
@spec secretbox(message(), extended_nonce(), secret_key()) :: iolist()
Encrypts a message with a secret key using the XSalsa20_Poly1305 authenticated cipher.
This function behaves like crypto_secretbox()
does in NaCl.
Parameters
message
- Plaintext message to be encryptednonce
- 24-byte extended noncekey
- 32-byte secret key
The return value is the cipher text prepended by the 16-byte tag (MAC), compatible with NaCl.
Returns an iolist/0
to reduce binary copies. Call IO.iodata_to_binary/1
if you need a single binary.
@spec secretbox_open(encrypted_message(), extended_nonce(), secret_key()) :: iolist() | :error
Decrypts a message that was encrypted with secretbox/3
using the XSalsa20_Poly1305 authenticated cipher.
This function behaves like crypto_secretbox_open()
does in NaCl.
Parameters
cipher_message
- The encrypted message (tag prepended to cipher text)nonce
- 24-byte extended noncekey
- 32-byte secret key
The return value is the decrypted plaintext (as an iolist) or :error
if authentication failed.
Returns an iolist/0
to reduce binary copies. Call IO.iodata_to_binary/1
if you need the message as a binary.
@spec xchacha20_poly1305_decrypt( encrypted_message(), extended_nonce(), secret_key(), aad() ) :: binary() | :error
Decrypts a message that was encrypted in "combined mode" using the XChaCha20_Poly1305 AEAD cipher.
This function behaves like crypto_aead_xchacha20poly1305_ietf_decrypt()
does in libsodium.
Parameters
message
- The encrypted message (tag appended to cipher text)nonce
- 24-byte extended noncekey
- 32-byte secret keyaad
- Additional authenticated data (defaults to<<>>
i.e. no AAD)
The return value is the decrypted plaintext as a binary or :error
if authentication failed.
@spec xchacha20_poly1305_decrypt_detached( encrypted_message(), extended_nonce(), secret_key(), aad(), tag() ) :: binary() | :error
Decrypts a message that was encrypted in "detacheded mode" using the XChaCha20_Poly1305 AEAD cipher.
This function behaves like crypto_aead_xchacha20poly1305_ietf_decrypt_detached()
does in libsodium.
Parameters
cipher_text
- The encrypted message (only the cipher text, not appended with the tag)nonce
- 24-byte extended noncekey
- 32-byte secret keyaad
- Additional authenticated data (defaults to<<>>
i.e. no AAD)tag
- 16-byte Poly1305 authentication tag or MAC
The return value is the decrypted plaintext as a binary or :error
if authentication failed.
This function differs from xchacha20_poly1305_decrypt/4
by returning the tag and cipher text separately
This "detached mode" function differs from the "combined mode" xchacha20_poly1305_decrypt/4
in that
the cipher text and tag are supplied as separate parameters, not combined as a single message.
@spec xchacha20_poly1305_encrypt(message(), extended_nonce(), secret_key(), aad()) :: iolist()
Encrypts a message with a secret key using the XChaCha20_Poly1305 AEAD cipher in "combined mode".
This function behaves like crypto_aead_xchacha20poly1305_ietf_encrypt()
does in libsodium.
Parameters
message
- Plaintext message to be encryptednonce
- 24-byte extended noncekey
- 32-byte secret keyaad
- Additional authenticated data (defaults to<<>>
i.e. no AAD)
The return value is the cipher text appended by the 16-byte tag (MAC), i.e. "combined mode".
Returns an iolist/0
to reduce binary copies. Call IO.iodata_to_binary/1
if you need a single binary.
@spec xchacha20_poly1305_encrypt_detached( message(), extended_nonce(), secret_key(), aad() ) :: {cipher_text(), tag()}
Encrypts a message with a secret key using the XChaCha20_Poly1305 AEAD cipher in "detached mode".
This function behaves like crypto_aead_xchacha20poly1305_ietf_encrypt_detached()
does in libsodium.
Parameters
This "detached mode" function differs from the "combined mode" xchacha20_poly1305_encrypt/4
by returning the tag and cipher text separately in a tuple in the form {cipher_text, tag}
.
Both cipher_text
and tag
will already be binaries.