Skip to content

soatok/experimental-caead

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
September 9, 2020 05:50

cAEAD - Committing AEAD

Committing AEAD with ChaCha20 and BLAKE3.

Warning: This is an experiment created by Soatok for fun. Don't use it.

Soatok disapproves of using this

Make sure you read the blog post that accompanies this repository.

What does this do?

This implements an RKR-secure alternative to XChaCha20-Poly1305, for use in protocols that require RKR security (i.e. OPAQUE). The primitives used (ChaCha20, BLAKE3) are secure and constant-time in software.

Although large nonces (32 bytes) are employed by this construction, it is not strictly speaking nonce misuse resistant. If you reuse a (nonce, key) tuple with two different messages, attackers will learn the XOR of the two plaintexts.

(We're using the IETF variant of ChaCha20 with 96-bit nonces and 32-bit counters.)

How to Test this Code

git clone https://github.com/soatok/experimental-caead
cd js
npm install
npm test

Algorithm Definition

Notation

Symbol Meaning
:= Assignment (store right-side value in left-side variable)
|| Concatenation
var[x:y] Slice var from index x to y

Constants

Algorithm prefix: CRYPTO_CAEAD_CHACHA20BLAKE3_

DOMAIN_ENCRYPT := "Soatok01"
DOMAIN_AUTH    := "Soatok}~"
NONCE_BYTES    := 32
KEY_BYTES      := 32
TAG_BYTES      := 32

Encryption Algorithm

  1. Split the key into an encryption key and an authentication key.

    encKey := BLAKE3.keyedHash(key, DOMAIN_ENCRYPT || nonce[0:19])
    authKey := BLAKE3.keyedHash(key, DOMAIN_AUTH || nonce[0:19])
    
  2. Encrypt the message:

    C := ChaCha20.encrypt(plaintext, nonce[20:31], encKey, block_counter = 0)
    
  3. Calculate the authentication tag:

    T := BLAKE3.keyedHash(authKey, aad || C || STORE64LE(aad.length) || STORE64LE(C.length))
    
  4. Return T || C

Decryption Algorithm

  1. Split the key into an encryption key and an authentication key.

    encKey := BLAKE3.keyedHash(key, DOMAIN_ENCRYPT || nonce[0:19])
    authKey := BLAKE3.keyedHash(key, DOMAIN_AUTH || nonce[0:19])
    
  2. Realculate the authentication tag:

    T' := BLAKE3.keyedHash(authKey, aad || C || STORE64LE(aad.length) || STORE64LE(C.length))
    
  3. Compare T with T' in constant-time. If it fails, abort.

  4. Decrypt the message:

    P := ChaCha20.decrypt(C, nonce[20:31], encKey, block_counter = 0)
    
  5. Return the decrypted plaintext.