-
Notifications
You must be signed in to change notification settings - Fork 95
Secret key encryption
#define CONTEXT "Examples"
#define MESSAGE "test"
#define MESSAGE_LEN 4
#define CIPHERTEXT_LEN (hydro_secretbox_HEADERBYTES + MESSAGE_LEN)
uint8_t key[hydro_secretbox_KEYBYTES];
uint8_t ciphertext[CIPHERTEXT_LEN];
hydro_secretbox_keygen(key);
hydro_secretbox_encrypt(ciphertext, MESSAGE, MESSAGE_LEN, 0, CONTEXT, key);
char decrypted[MESSAGE_LEN];
if (hydro_secretbox_decrypt(decrypted, ciphertext, CIPHERTEXT_LEN, 0, CONTEXT, key) != 0) {
/* message forged! */
}
This operation:
- Encrypts a message with a secret key to keep it confidential
- Computes a nonce and an authentication tag. This tag is used to make sure that the message hasn't been tampered with before decrypting it.
A single key is used both to encrypt/sign and verify/decrypt messages. For this reason, it is critical to keep the key confidential.
void hydro_secretbox_keygen(uint8_t key[hydro_secretbox_KEYBYTES]);
The hydro_secretbox_keygen()
function generates a secret key suitable for the secretbox
API.
int hydro_secretbox_encrypt(uint8_t *c, const void *m_, size_t mlen,
uint64_t msg_id, const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES]);
The hydro_secretbox_encrypt()
function encrypts a message m_
of length mlen
bytes using a context ctx
, a secret key key
and a message counter msg_id
.
It puts the ciphertext whose length is hydro_secretbox_HEADERBYTES + mlen
into c
.
The header includes an automatically-generated 160-bit nonce as well as a 128-bit authentication tag.
A nonce doesn't have to be provided: it is automatically computed using the output of the PRNG and a keyed hash of the message and its metadata. This prevents catastrophic failures even if the PRNG cannot be trusted.
msg_id
is an optional message tag. For example, if 3 messages are sent to the same recipient using the same key, these messages can sequentially use 0
, 1
and 2
as identifiers.
If the recipient expects message 2
, but receives a message with a different identifier, it will not decrypt it even if it was encrypted with the correct key.
This can be used to discard duplicate or old messages.
A msg_id
doesn't have to be secret and it doesn't have to be sequential either. Some applications might prefer a coarse timestamp instead. Any value up to 2^64-1 is acceptable.
If this mechanism is not required by an application, using a constant msg_id
such as 0
is also totally fine. Message identifiers are optional and do not have to be unique.
int hydro_secretbox_decrypt(void *m_, const uint8_t *c, size_t clen,
uint64_t msg_id, const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES])
__attribute__((warn_unused_result));
The hydro_secretbox_decrypt()
function decrypts the ciphertext c
of length clen
(which includes the hydro_secretbox_HEADERBYTES
bytes header) using the secret key key
, the context ctx
and the message identifier msg_id
.
If the authentication tag can be verified using these parameters, the function stores the decrypted message into m_
. The length of this decrypted message is clen - hydro_secretbox_HEADERBYTES
. It then returns 0
.
If the authentication tag doesn't appear to be valid for these parameters, the function returns -1
.
In the decryption function, the whole ciphertext has to be processed before the authentication tag can be verified. Attackers can thus send large, invalid ciphertexts that will consume CPU resources before being eventually rejected.
Probes can help mitigate this. A probe is a 128-bit value computed from the MAC and a secret key, that can be quickly verified before decrypting the actual ciphertext if the probe happens to pass verification. The key can be the same as the one used for encryption.
- The sender sends the probe, along with the ciphertext
- The recipient reads the probe, verifies it. If it doesn't pass, the ciphertext can be ignored.
- If it does pass, the recipient can then decrypt the ciphertext, whose MAC will still be verified.
Probes do not replace MACs. They introduce a small overhead and they are just an initial barrier, only useful for online protocols, on servers accepting potentially large, untrusted messages. They do not protect against MITM attacks. However, they help against blind attackers flooding servers with large, invalid ciphertexts.
Only the first hydro_secretbox_HEADERBYTES
bytes of the ciphertext are required to create and verify a probe. A recipient can thus choose to only receive the first bytes of the ciphertext before downloading the rest if the probe verification passes.
void
hydro_secretbox_probe_create(uint8_t probe[hydro_secretbox_PROBEBYTES],
const uint8_t *c, size_t c_len,
const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES]);
The hydro_secretbox_probe_create()
function computes a probe for the ciphertext c
whose length is c_len
, using the context ctx
and a shared secret key key
.
The probe is put into probe
whose size is hydro_secretbox_PROBEBYTES
bytes.
int
hydro_secretbox_probe_verify(const uint8_t probe[hydro_secretbox_PROBEBYTES],
const uint8_t *c, size_t c_len,
const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES])
__attribute__((warn_unused_result));
The hydro_secretbox_probe_verify()
function verifies that a received probe probe
is valid for the ciphertext c
whose length is c_len
, using the context ctx
and the shared secret key key
that was initially used to compute the probe.
It returns 0
on success, and -1
if the probe didn't pass verification.
#define hydro_secretbox_CONTEXTBYTES 8
#define hydro_secretbox_HEADERBYTES (20 + 16)
#define hydro_secretbox_KEYBYTES 32
#define hydro_secretbox_PROBEBYTES 16
The construction is similar to the nonce misuse-resistant version of the NORX v3.0 AEAD construction, with the following differences:
- The header includes all the metadata, including the nonce
- Gimli is the permutation function
- Since this API doesn't delegate nonce generation to users, the synthetic nonce used for encryption is returned instead of the random nonce used to compute it.