Secret-key single-message authentication using Poly1305
One-time authentication in Sodium uses Poly1305, a Wegman-Carter authenticator designed by D. J. Bernstein.
Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the message such that an attacker has a negligible chance of producing a valid tag for a inauthentic message.
Poly1305 keys have to be:
- secret. An attacker can compute a valid authentication tag for any message, for any given key. The security of Poly1305 relies on the fact that attackers don't know the key being used to compute the tag. This implies that they have to be:
- unpredictable. Do not use timestamps or counters.
- unique. Never reuse a key. A new key is required for every single message.
The standard way to use Poly1305's is to derive a dedicated subkey from a (key, nonce)
tuple, for example by taking the first bytes generated by a stream cipher.
Due to its output size, Poly1305 is recommended for online protocols, exchanging many small messages, rather than for authenticating very large files.
Finally, Poly1305 is not a replacement for a hash function.
Single-part example
#define MESSAGE ((const unsigned char *) "Data to authenticate")
#define MESSAGE_LEN 20
unsigned char out[crypto_onetimeauth_BYTES];
unsigned char key[crypto_onetimeauth_KEYBYTES];
randombytes_buf(key, sizeof key);
crypto_onetimeauth(out, MESSAGE, MESSAGE_LEN, key);
if (crypto_onetimeauth_verify(out, MESSAGE, MESSAGE_LEN, key) != 0) {
/* message forged! */
}
Multi-part example
#define MESSAGE1 ((const unsigned char *) "Multi-part")
#define MESSAGE1_LEN 10
#define MESSAGE2 ((const unsigned char *) "data")
#define MESSAGE2_LEN 4
unsigned char out[crypto_onetimeauth_BYTES];
unsigned char key[crypto_onetimeauth_KEYBYTES];
crypto_onetimeauth_state state;
randombytes_buf(key, sizeof key);
crypto_onetimeauth_init(&state, key);
crypto_onetimeauth_update(&state, MESSAGE1, MESSAGE1_LEN);
crypto_onetimeauth_update(&state, MESSAGE2, MESSAGE2_LEN);
crypto_onetimeauth_final(&state, out);
Usage
Single-part interface
int crypto_onetimeauth(unsigned char *out, const unsigned char *in,
unsigned long long inlen, const unsigned char *k);
The crypto_onetimeauth()
function authenticates a message in
whose length is inlen
using a secret key k
(crypto_onetimeauth_KEYBYTES
bytes) and puts the authenticator into out
(crypto_onetimeauth_BYTES
bytes).
int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in,
unsigned long long inlen, const unsigned char *k);
The crypto_onetimeauth_verify()
function verifies, in constant time, that h
is a correct authenticator for the message in
whose length is inlen
bytes, using the secret key k
.
It returns -1
is the verification fails, or 0
on success.
Multi-part (streaming) interface
int crypto_onetimeauth_init(crypto_onetimeauth_state *state,
const unsigned char *key);
int crypto_onetimeauth_update(crypto_onetimeauth_state *state,
const unsigned char *in,
unsigned long long inlen);
int crypto_onetimeauth_final(crypto_onetimeauth_state *state,
unsigned char *out);
The crypto_onetimeauth_init()
function initializes a structure pointed by state
using a key key
.
crypto_onetimeauth_update()
can then be called more than one in order to compute the authenticator from sequential chunks of the message.
Finally, crypto_onetimeauth_final()
puts the authenticator into out
.
The state must be initialized with crypto_onetimeauth_init()
before updating or finalizing it.
After crypto_onetimeauth_final()
returns, the state should not be used any more, unless it is reinitialized using crypto_onetimeauth_init()
.
Constants
crypto_onetimeauth_BYTES
crypto_onetimeauth_KEYBYTES
Data types
crypto_onetimeauth_state
Algorithm details
- Poly1305