crypto_lock_init,
crypto_lock_auth_ad,
crypto_lock_auth_message,
crypto_lock_update,
crypto_lock_final,
crypto_unlock_init,
crypto_unlock_auth_ad,
crypto_unlock_auth_message,
crypto_unlock_update,
crypto_unlock_final —
incremental authenticated encryption with
additional data
#include
<monocypher.h>
void
crypto_lock_init(
crypto_lock_ctx
*ctx,
const uint8_t key[32],
const uint8_t nonce[24]);
void
crypto_lock_auth_ad(
crypto_lock_ctx
*ctx,
const uint8_t *ad,
size_t ad_size);
void
crypto_lock_auth_message(
crypto_lock_ctx
*ctx,
const uint8_t *plain_text,
size_t text_size);
void
crypto_lock_update(
crypto_lock_ctx
*ctx,
uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size);
void
crypto_lock_final(
crypto_lock_ctx
*ctx,
uint8_t mac[16]);
void
crypto_unlock_init(
crypto_unlock_ctx
*ctx,
const uint8_t key[32],
const uint8_t nonce[24]);
void
crypto_unlock_auth_ad(
crypto_unlock_ctx
*ctx,
const uint8_t *ad,
size_t ad_size);
void
crypto_unlock_auth_message(
crypto_unlock_ctx
*ctx,
const uint8_t *plain_text,
size_t text_size);
void
crypto_unlock_update(
crypto_unlock_ctx
*ctx,
uint8_t *plain_text,
const uint8_t *cipher_text,
size_t text_size);
int
crypto_unlock_final(
crypto_unlock_ctx
*ctx,
const uint8_t mac[16]);
These functions are variants of
crypto_lock(3monocypher),
crypto_unlock(3monocypher),
crypto_lock_aead(3monocypher)
and
crypto_unlock_aead(3monocypher).
Prefer those simpler functions if possible.
This incremental interface can be used to encrypt and decrypt messages too large
to fit in a single buffer. The arguments are the same as described for the
direct interface described in
crypto_lock(3monocypher).
Encryption requires four steps:
- Initialise a context with
crypto_lock_init().
- Authenticate additional data, if any, with
crypto_lock_auth_ad().
- Encrypt and authenticate some data with
crypto_lock_update().
- Generate the MAC with
crypto_lock_final().
Decryption also requires four steps:
- Initialise a context with
crypto_unlock_init().
- Verify additional data, if any, with
crypto_unlock_auth_ad().
- Decrypt and verify some data with
crypto_unlock_update().
- Verify the MAC with
crypto_unlock_final().
crypto_lock_init(),
crypto_unlock_init(),
crypto_lock_auth_ad(),
crypto_unlock_auth_ad(),
crypto_lock_auth_message(),
crypto_unlock_auth_message(),
crypto_lock_update(),
crypto_unlock_update(), and
crypto_lock_final() return nothing.
crypto_unlock_final() returns 0 on success or -1 if
the message was corrupted. Corruption can be caused by transmission errors,
programmer error, or an attacker's interference.
Always check the return value.
Encryption:
const uint8_t key [ 32]; /* Session key */
const uint8_t nonce [ 32]; /* Unique per session key */
const uint8_t ad [500]; /* Optional additional data */
const uint8_t plain_text [500]; /* Secret message */
uint8_t cipher_text[500]; /* Encrypted message */
uint8_t mac [ 16]; /* Message authentication code */
/* Set up initial context */
crypto_lock_ctx ctx;
crypto_lock_init(&ctx, key, nonce);
/* Wipe the key if it is no longer needed */
crypto_wipe(key, 32);
/* Authenticate additional data */
for (size_t i = 0; i < 500; i += 100) {
crypto_lock_auth_ad(&ctx, ad + i, 100);
}
/* Encrypt message */
for (size_t i = 0; i < 500; i += 100) {
crypto_lock_update(&ctx, cipher_text + i, plain_text + i, 100);
/* Wipe the secret message if it is no longer needed */
crypto_wipe(plain_text + i, 100);
}
/* Produce the MAC */
crypto_lock_final(&ctx, mac);
To decrypt the above:
const uint8_t key [ 32]; /* Session key */
const uint8_t nonce [ 32]; /* Unique per session key */
const uint8_t mac [ 16]; /* Transmitted MAC */
const uint8_t ad [500]; /* Optional additional data */
const uint8_t cipher_text[500]; /* Encrypted message */
uint8_t plain_text [500]; /* Secret message */
/* Set up initial context */
crypto_unlock_ctx ctx;
crypto_unlock_init(&ctx, key, nonce);
/* Wipe the key if it is no longer needed */
crypto_wipe(key, 32);
/* Verify additional data */
for (size_t i = 0; i < 500; i += 100) {
crypto_unlock_auth_ad(&ctx, ad + i, 100);
}
/* Decrypt message */
for (size_t i = 0; i < 500; i += 100) {
crypto_unlock_update(&ctx, plain_text + i, cipher_text + i, 100);
}
/* Check the MAC */
if (crypto_unlock_final(&ctx, mac)) {
/* Corrupted message, abort processing */
} else {
/* Genuine message */
}
/* Wipe the secret message if it is no longer needed */
crypto_wipe(plain_text, 500);
To authenticate the above without decrypting it:
const uint8_t key [ 32]; /* Session key */
const uint8_t nonce [ 32]; /* Unique per session key */
const uint8_t mac [ 16]; /* Transmitted MAC */
const uint8_t ad [500]; /* Optional additional data */
const uint8_t cipher_text[500]; /* Encrypted message */
/* Set up initial context */
crypto_unlock_ctx ctx;
crypto_unlock_init(&ctx, key, nonce);
/* Wipe the key if it is no longer needed */
crypto_wipe(key, 32);
/* Verify additional data */
for (size_t i = 0; i < 500; i += 100) {
crypto_unlock_auth_ad(&ctx, ad + i, 100);
}
/* Verify message */
for (size_t i = 0; i < 500; i += 100) {
crypto_unlock_auth_message(&ctx, cipher_text + i, 100);
}
/* Check the MAC */
if (crypto_unlock_final(&ctx, mac)) {
/* Corrupted message */
} else {
/* Genuine message */
}
In-place encryption without additional data:
const uint8_t key [ 32]; /* Session key */
const uint8_t nonce [ 32]; /* Unique per session key */
uint8_t text [500]; /* Message */
uint8_t mac [ 16]; /* Message authentication code */
/* Set up initial context */
crypto_lock_ctx ctx;
crypto_lock_init(&ctx, key, nonce);
/* Wipe the key if it is no longer needed */
crypto_wipe(key, 32);
/* Encrypt message */
for (size_t i = 0; i < 500; i += 100) {
crypto_lock_update(&ctx, text + i, text + i, 100);
}
/* Produce the MAC */
crypto_lock_final(&ctx, mac);
crypto_key_exchange(3monocypher),
crypto_lock(3monocypher),
crypto_lock_aead(3monocypher),
crypto_unlock(3monocypher),
crypto_unlock_aead(3monocypher),
crypto_wipe(3monocypher),
intro(3monocypher)
These functions implement RFC 7539, with XChacha20 instead of Chacha20.
XChacha20 derives from Chacha20 the same way XSalsa20 derives from Salsa20,
and benefits from the same security reduction (proven secure as long as
Chacha20 itself is secure).
Messages are not verified until the call to
crypto_unlock_final(). Make sure to call it and
check the return value
before processing the
message. Messages may be stored before they are verified, but they cannot be
trusted. Processing untrusted messages increases the attack surface of the
system. Doing so securely is hard. Do not process messages before calling
crypto_unlock_final().
- crypto_unlock_ctx is an
alias to crypto_lock_ctx.
- crypto_unlock_init() is an
alias to crypto_lock_init().
- crypto_lock_auth_ad() and
crypto_unlock_auth_ad() are aliases to
crypto_lock_auth().
The incremental interface is roughly three times slower than the direct
interface at identifying corrupted messages. This is because the incremental
interface works in a single pass and has to interleave decryption and
verification. Users who expect a high corruption rate may want to perform a
first pass with
crypto_unlock_auth_message()
before decrypting the message.