Paseto Version 2
Encrypt
Given a message m, key k, and optional footer f.
- Set header
htov2.local. - Generate 24 random bytes from the OS's CSPRNG.
- Calculate BLAKE2b of the message
mwith the output of step 2 as the key, with an output length of 24. This will be our nonce,n.- This step is to ensure that an RNG failure does not result in a nonce-misuse condition that breaks the security of our stream cipher.
- Pack
h,n, andftogether (in that order) using PAE. We'll call thispreAuth. - Encrypt the message using XChaCha20-Poly1305, using an AEAD interface such as
the one provided in libsodium.
c = crypto_aead_xchacha20poly1305_encrypt( message = m aad = preAuth nonce = n key = k ); - If
fis:- Empty: return h || b64(n || c)
- Non-empty: return h || b64(n || c) ||
.|| base64url(f) - ...where || means "concatenate"
Decrypt
Given a message m, key k, and optional footer f.
- If
fis not empty, implementations MAY verify that the value appended to the token matches some expected stringf, provided they do so using a constant-time string compare function. - Verify that the message begins with
v2.local., otherwise throw an exception. This constant will be referred to ash. - Decode the payload (
msansh,f, and the optional trailing period betweenmandf) from base64url to raw binary. Set:nto the leftmost 24 bytescto the middle remainder of the payload, excludingn.
- Pack
h,n, andftogether (in that order) using PAE. We'll call thispreAuth - Decrypt
cusingXChaCha20-Poly1305, store the result inp.p = crypto_aead_xchacha20poly1305_decrypt( ciphertext = c aad = preAuth nonce = n key = k ); - If decryption failed, throw an exception. Otherwise, return
p.
Sign
Given a message m, Ed25519 secret key sk, and
optional footer f (which defaults to empty string):
- Set
htov2.public. - Pack
h,m, andftogether using PAE (pre-authentication encoding). We'll call thism2. - Sign
m2using Ed25519sk. We'll call thissig.sig = crypto_sign_detached( message = m2, private_key = sk ); - If
fis:- Empty: return "
h|| base64url(m||sig)" - Non-empty: return "
h|| base64url(m||sig) ||.|| base64url(f)" - ...where || means "concatenate"
- Note:
base64url()means Base64url from RFC 4648 without=padding.
- Empty: return "
Verify
Given a signed message sm, public key pk, and optional footer f
(which defaults to empty string):
- If
fis not empty, implementations MAY verify that the value appended to the token matches some expected stringf, provided they do so using a constant-time string compare function. - Verify that the message begins with
v2.public., otherwise throw an exception. This constant will be referred to ash. - Decode the payload (
smsansh,f, and the optional trailing period betweenmandf) from base64url to raw binary. Set:sto the rightmost 64 bytesmto the leftmost remainder of the payload, excludings
- Pack
h,m, andftogether using PAE. We'll call thism2. - Use Ed25519 to verify that the signature is valid for the message:
valid = crypto_sign_verify_detached( signature = s, message = m2, public_key = pk ); - If the signature is valid, return
m. Otherwise, throw an exception.