Paseto Version 4
January 9, 2023 ยท View on GitHub
Encrypt
Given a message m, key k, and optional footer f (which defaults to empty
string), and an optional implicit assertion i (which defaults to empty string):
- Before encrypting, first assert that the key being used is intended for use
with
v4.localtokens, and has a length of 256 bits (32 bytes). See Algorithm Lucidity for more information. - Set header
htov4.local.
Note: This includes the trailing period. - Generate 32 random bytes from the OS's CSPRNG,
n. - Split the key into an Encryption key (
Ek) and Authentication key (Ak), using keyed BLAKE2b, using the domain separation constants andnas the message, and the input key as the key. The first value will be 56 bytes, the second will be 32 bytes. The derived key will be the leftmost 32 bytes of the hash output. The remaining 24 bytes will be used as a counter nonce (n2):tmp = crypto_generichash( msg = "paseto-encryption-key" || n, key = key, length = 56 ); Ek = tmp[0:32] n2 = tmp[32:] Ak = crypto_generichash( msg = "paseto-auth-key-for-aead" || n, key = key, length = 32 ); - Encrypt the message using XChaCha20, using
n2from step 3 as the nonce andEkas the key.c = crypto_stream_xchacha20_xor( message = m nonce = n2 key = Ek ); - Pack
h,n,c,f, anditogether (in that order) using PAE. We'll call thispreAuth. - Calculate BLAKE2b-MAC of the output of
preAuth, usingAkas the authentication key. We'll call thist.t = crypto_generichash( message = preAuth key = Ak, length = 32 ); - If
fis:- Empty: return h || base64url(n || c || t)
- Non-empty: return h || base64url(n || c || t) ||
.|| base64url(f) - ...where || means "concatenate"
- Note:
base64url()means Base64url from RFC 4648 without=padding.
Decrypt
Given a message m, key k, and optional footer f
(which defaults to empty string), and an optional
implicit assertion i (which defaults to empty string):
- Before decrypting, first assert that the key being used is intended for use
with
v4.localtokens, and has a length of 256 bits (32 bytes). See Algorithm Lucidity for more information. - 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
v4.local., otherwise throw an exception. This constant will be referred to ash.- Note: This header includes the trailing period.
- Future-proofing: If a future PASETO variant allows for encodings other
than JSON (e.g., CBOR), future implementations MAY also permit those
values at this step (e.g.
v4c.local.).
- Decode the payload (
msansh,f, and the optional trailing period betweenmandf) from base64url to raw binary. Set:nto the leftmost 32 bytestto the rightmost 32 bytescto the middle remainder of the payload, excludingnandt.
- Split the key into an Encryption key (
Ek) and Authentication key (Ak), using keyed BLAKE2b, using the domain separation constants andnas the message, and the input key as the key. The first value will be 56 bytes, the second will be 32 bytes. The derived key will be the leftmost 32 bytes of the hash output. The remaining 24 bytes will be used as a counter nonce (n2):tmp = crypto_generichash( msg = "paseto-encryption-key" || n, key = key, length = 56 ); Ek = tmp[0:32] n2 = tmp[32:] Ak = crypto_generichash( msg = "paseto-auth-key-for-aead" || n, key = key, length = 32 ); - Pack
h,n,c,f, anditogether (in that order) using PAE. We'll call thispreAuth. - Re-calculate BLAKE2b-MAC of the output of
preAuth, usingAkas the authentication key. We'll call thist2.t2 = crypto_generichash( message = preAuth key = Ak, length = 32 ); - Compare
twitht2using a constant-time string compare function. If they are not identical, throw an exception.- You MUST use a constant-time string compare function to be compliant. If you do not have one available to you in your programming language/framework, you MUST use Double HMAC.
- Decrypt
cusingXChaCha20, store the result inp.p = crypto_stream_xchacha20_xor( ciphertext = c nonce = n2 key = Ek ); - 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), and an optional
implicit assertion i (which defaults to empty string):
- Before signing, first assert that the key being used is intended for use
with
v4.publictokens, and is the secret key of the intended keypair. See Algorithm Lucidity for more information. - Set
htov4.public.
Note: This includes the trailing period. - Pack
h,m,f, anditogether 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), and an optional
implicit assertion i (which defaults to empty string):
- Before verifying, first assert that the key being used is intended for use
with
v4.publictokens, and is the public key of the intended keypair. See Algorithm Lucidity for more information. - 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
v4.public., otherwise throw an exception. This constant will be referred to ash.
Note: This includes the trailing period. - 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,f,itogether 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.