File: docs/01-Protocol-Versions/Version1.md

Recommend this page to a friend!
  Classes of Scott Arciszewski  >  PHP PASeTo  >  docs/01-Protocol-Versions/Version1.md  >  Download  
File: docs/01-Protocol-Versions/Version1.md
Role: Auxiliary data
Content type: text/markdown
Description: Auxiliary data
Class: PHP PASeTo
Encrypt and decrypt data with PaSeTO protocol
Author: By
Last change:
Date: 5 months ago
Size: 6,120 bytes
 

Contents

Class file image Download

Paseto Version 1

GetNonce

Given a message (m) and a nonce (n):

  1. Calculate HMAC-SHA384 of the message m with n as the key.
  2. Return the leftmost 32 bytes of step 1.

Encrypt

Given a message m, key k, and optional footer f (which defaults to empty string):

  1. Set header h to v1.local.
  2. Generate 32 random bytes from the OS's CSPRNG.
  3. Calculate GetNonce() of m and the output of step 2 to get the 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.
  4. Split the key into an Encryption key (Ek) and Authentication key (Ak), using the leftmost 16 bytes of n as the HKDF salt: ` Ek = hkdf_sha384( len = 32 ikm = k, info = "paseto-encryption-key", salt = n[0:16] ); Ak = hkdf_sha384( len = 32 ikm = k, info = "paseto-auth-key-for-aead", salt = n[0:16] ); `
  5. Encrypt the message using AES-256-CTR, using Ek as the key and the rightmost 16 bytes of n as the nonce. We'll call this c: ` c = aes256ctr_encrypt( plaintext = m, nonce = n[16:] key = Ek ); `
  6. Pack h, n, c, and f together using PAE (pre-authentication encoding). We'll call this preAuth
  7. Calculate HMAC-SHA384 of the output of preAuth, using Ak as the authentication key. We'll call this t.
  8. If f is: * 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):

  1. If f is not empty, implementations MAY verify that the value appended to the token matches some expected string f, provided they do so using a constant-time string compare function.
  2. Verify that the message begins with v1.local., otherwise throw an exception. This constant will be referred to as h.
  3. Decode the payload (m sans h, f, and the optional trailing period between m and f) from b64 to raw binary. Set: * n to the leftmost 32 bytes * t to the rightmost 48 bytes * c to the middle remainder of the payload, excluding n and t
  4. Split the key (k) into an Encryption key (Ek) and an Authentication key (Ak), using the leftmost 16 bytes of n as the HKDF salt. For encryption keys, theinfoparameter for HKDFMUST* be set to paseto-encryption-key. For authentication keys, theinfoparameter for HKDFMUST* be set to paseto-auth-key-for-aead. The output lengthMUST* be 32 for both keys.

    ` Ek = hkdf_sha384( len = 32 ikm = k, info = "paseto-encryption-key", salt = n[0:16] ); Ak = hkdf_sha384( len = 32 ikm = k, info = "paseto-auth-key-for-aead", salt = n[0:16] ); `

  5. Pack h, n, c, and f together (in that order) using PAE. We'll call this preAuth.
  6. Recalculate HMAC-SHA-384 of preAuth using Ak as the key. We'll call this t2.
  7. Compare t with t2 using a constant-time string compare function. If they are not identical, throw an exception.
  8. Decrypt c using AES-256-CTR, using Ek as the key and the rightmost 16 bytes of n as the nonce, and return this value. ` return aes256ctr_decrypt( cipherext = c, nonce = n[16:] key = Ek ); `

Sign

Given a message m, 2048-bit RSA secret key sk, and optional footer f (which defaults to empty string):

  1. Set h to v1.public.
  2. Pack h, m, and f together using PAE (pre-authentication encoding). We'll call this m2.
  3. Sign m2 using RSA with the private key sk. We'll call this sig. ` sig = crypto_sign_rsa( message = m2, private_key = sk, padding_mode = "pss", public_exponent = 65537, hash = "sha384" mgf = "mgf1+sha384" ); ` Only the above parameters are supported. PKCS1v1.5 is explicitly forbidden.
  4. If f is: * 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.

Verify

Given a signed message sm, RSA public key pk, and optional footer f (which defaults to empty string):

  1. If f is not empty, implementations MAY verify that the value appended to the token matches some expected string f, provided they do so using a constant-time string compare function.
  2. Verify that the message begins with v1.public., otherwise throw an exception. This constant will be referred to as h.
  3. Decode the payload (sm sans h, f, and the optional trailing period between m and f) from b64 to raw binary. Set: * s to the rightmost 256 bytes * m to the leftmost remainder of the payload, excluding s
  4. Pack h, m, and f together (in that order) using PAE (see PAE. We'll call this m2.
  5. Use RSA to verify that the signature is valid for the message: ` valid = crypto_sign_rsa_verify( signature = s, message = m2, public_key = pk, padding_mode = "pss", public_exponent = 65537, hash = "sha384" mgf = "mgf1+sha384" ); `
  6. If the signature is valid, return m. Otherwise, throw an exception.

For more information send a message to info at phpclasses dot org.