Advanced Libsodium Features
The functions documented in this chapter are meant for advanced developers. Some of the functions can be dangerous if used improperly, and thus their uses are discouraged for developers searching for general-purpose cryptography solutions.
Advanced Secret-key Cryptography
(This Space Reserved for the CAESAR Competition Winner)
There is a cryptography competition underway called CAESAR, which will determine the next generation algorithms of authenticated secret-key encryption.
The CAESAR winner is anticipated to be announced in December 2017 and should be
made available in Libsodium as crypto_aead()
soon after. In the meantime, you
can use the crypto_aead_chacha20poly1305
API.
Authenticated (secret-key) Encryption with Associated Data - ChaCha20 + Poly1305
Similar to the crypto_secretbox
API,
except its underlying algorithm is chacha20poly1305 instead of xsalsa20poly1305
and optional, non-confidential (non-encrypted) data can be included in the
Poly1305 authentication tag verification.
From the Libsodium documentation:
This operation:
- Encrypts a message with a key and a nonce to keep it confidential.
- Computes an authentication tag. This tag is used to make sure that the message, as well as optional, non-confidential (non-encrypted) data, haven't been tampered with.
A typical use case for additional data is to store protocol-specific metadata about the message, such as its length and encoding.
The chosen construction uses encrypt-then-MAC and decryption will never be performed, even partially, before verification.
Since this is a secret-key cryptography function, you can generate an encryption key like so:
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
AEAD Encryption
string \Sodium\crypto_aead_chacha20poly1305_encrypt(string $confidential_message, string $public_message, string $nonce, string $key)
Like crypto_secretbox
, you should never reuse the same nonce and key.
$nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES);
$ad = 'Additional (public) data';
$ciphertext = \Sodium\crypto_aead_chacha20poly1305_encrypt(
$message,
$ad,
$nonce,
$key
);
AEAD Decryption
string|bool \Sodium\crypto_aead_chacha20poly1305_decrypt(string $confidential_message, string $public_message, string $nonce, string $key)
$decrypted = \Sodium\crypto_aead_chacha20poly1305_decrypt(
$ciphertext,
$ad,
$nonce,
$key
);
if ($decrypted === false) {
throw new Exception("Bad ciphertext");
}
Authenticated (secret-key) Encryption with Associated Data - AES-256 + GCM
When supported by the CPU, AES-256-GCM is the fastest AEAD cipher available in this library. When unsupported by CPU, the encrypt/decrypt functions are not available.
bool \Sodium\crypto_aead_aes256gcm_is_available()
Make sure you check that AES-256-GCM is available before you attempt to use it.
From the Libsodium documentation:
This operation:
- Encrypts a message with a key and a nonce to keep it confidential.
- Computes an authentication tag. This tag is used to make sure that the message, as well as optional, non-confidential (non-encrypted) data, haven't been tampered with.
A typical use case for additional data is to store protocol-specific metadata about the message, such as its length and encoding.
The chosen construction uses encrypt-then-MAC and decryption will never be performed, even partially, before verification.
Since this is a secret-key cryptography function, you can generate an encryption key like so:
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_AES256GCM_KEYBYTES);
AEAD Encryption
string \Sodium\crypto_aead_aes256gcm_encrypt(string $confidential_message, string $public_message, string $nonce, string $key)
Like crypto_secretbox
, you should never reuse the same nonce and key.
if (\Sodium\crypto_aead_aes256gcm_is_available()) {
$nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_AEAD_AES256GCM_NPUBBYTES);
$ad = 'Additional (public) data';
$ciphertext = \Sodium\crypto_aead_aes256gcm_encrypt(
$message,
$ad,
$nonce,
$key
);
}
AEAD Decryption
string|bool \Sodium\crypto_aead_aes256gcm_decrypt(string $confidential_message, string $public_message, string $nonce, string $key)
if (\Sodium\crypto_aead_aes256gcm_is_available()) {
$decrypted = \Sodium\crypto_aead_aes256gcm_decrypt(
$ciphertext,
$ad,
$nonce,
$key
);
if ($decrypted === false) {
throw new Exception("Bad ciphertext");
}
}
Secret-key Encryption (Unauthenticated)
Before using these functions, you should make sure you understand the risks associated with unauthenticated encryption.
Encrypt a Message with a Stream Cipher, Without Authentication
string \Sodium\crypto_stream_xor($message, $nonce, $key)
This operation encrypts or decrypt a message with a key and a nonce. However, the ciphertext doesn't include an authentication tag, meaning that it is impossible to verify that the message hasn't been tampered with.
Unless you specifically need unauthenticated encryption,
\Sodium\crypto_secretbox()
is the
operation you should use instead.
$nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_STREAM_NONCEBYTES);
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_STREAM_KEYBYTES);
// This operation is reversible:
$ciphertext = \Sodium\crypto_stream_xor('test', $nonce, $key);
$plaintext = \Sodium\crypto_stream_xor($ciphertext, $nonce, $key);
Pseudorandom Bytes from Stream Cipher
string \Sodium\crypto_stream(int $length, string $nonce, string $key)
You can use crypto_stream
to generate a string of pseudorandom bytes. Take
care to never repeat a nonce with the same key.
$nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_STREAM_NONCEBYTES);
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_STREAM_KEYBYTES);
// Derive $length pseudorandom bytes from the nonce and the key
$stream = \Sodium\crypto_stream($length, $nonce, $key);
Advanced Public-key Cryptography
Sealed boxes (Anonymous Public-key Encryption)
Sealed boxes are designed to anonymously send messages to a recipient given its public key.
Only the recipient can decrypt these messages, using their private key. While the recipient can verify the integrity of the message, it cannot verify the identity of the sender.
A message is encrypted using an ephemeral key pair, whose secret part is destroyed right after the encryption process.
Without knowing the secret key used for a given message, the sender cannot decrypt its own message later. And without additional data, a message cannot be correlated with the identity of its sender.
Sealed Box Encryption
string \Sodium\crypto_box_seal(string $message, string $publickey)
This will encrypt a message with a user's public key.
$anonymous_message_to_bob = \Sodium\crypto_box_seal(
$message,
$bob_box_publickey
);
Sealed Box Decryption
string \Sodium\crypto_box_seal_open(string $message, string $recipient_keypair)
Opens a sealed box with a keypair from your secret key and public key.
$bob_box_kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey(
$bob_box_seceretkey,
$bob_box_publickey
);
$decrypted_message = \Sodium\crypto_box_seal_open(
$anonymous_message_to_bob,
$bob_box_kp
);
Scalar multiplication (Elliptic Curve Cryptography)
Sodium provides an API for Curve25519, a state-of-the-art Diffie-Hellman function suitable for a wide variety of applications.
string \Sodium\crypto_scalarmult(string $key_1, string $key_2)
The crypto_scalarmult
API allows deriving a shared secret from your secret key
and the other user's public key. It also allows the derivation of your public
key from your secret key.
Transform crypto_sign key into crypto_box key
string \Sodium\crypto_sign_ed25519_sk_to_curve25519(string $ed25519sk)
Pass a crypto_sign
secret key, get a crypto_box
secret key.
string \Sodium\crypto_sign_ed25519_pk_to_curve25519(string $ed25519pk)
Pass a crypto_sign
public key, get a crypto_box
public key.
Get Public-key from Secret-key
string \Sodium\crypto_box_publickey_from_secretkey(string $secretkey)
This is pretty straightforward.
$alice_box_publickey = \Sodium\crypto_box_publickey_from_secretkey(
$alice_box_secretkey
);
The function \Sodium\crypto_scalarmult_base()
is an alias for
\Sodium\crypto_box_publickey_from_secretkey()
.
string \Sodium\crypto_sign_publickey_from_secretkey(string $secretkey)
As above, but with crypto_sign
instead of crypto_box
:
$alice_sign_publickey = \Sodium\crypto_sign_publickey_from_secretkey(
$alice_sign_secretkey
);
Elliptic Curve Diffie Hellman Key Exchange
string \Sodium\crypto_kx(string $secretkey, string $publickey, string $client_publickey, string $server_publickey)
Compute a shared secret using Elliptic Curve Diffie Hellman over Curve25519.
// Alice's computer:
$alice_sharedsecret = \Sodium\crypto_kx(
$alice_box_secretkey, $bob_box_publickey,
$alice_box_publickey, $bob_box_publickey
);
// Bob's computer:
$bob_sharedsecret = \Sodium\crypto_kx(
$bob_box_secretkey, $alice_box_publickey,
$alice_box_publickey, $bob_box_publickey
);
Extra information
- Relevant Libsodium Documentation Pages:
- CAESAR: Competition for Authenticated Encryption: Security, Applicability, and Robustness