Skip to content

Commit

Permalink
CRYPTO: update formula to MathJax syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
commial authored Aug 14, 2024
1 parent d3f6466 commit a3c3edc
Showing 1 changed file with 67 additions and 54 deletions.
121 changes: 67 additions & 54 deletions CRYPTO.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ To encrypt to a target recipient $i$, knowing $pk_{ecc}^i$ and $pk_{mlkem}^i$:

1. Compute shared secrets and ciphertexts for both KEM:

$$
\begin{aligned}
(ss_{ecc}^i, ct_{ecc}^i) = \textrm{Encapsulate}_{DHKEM}(pk_{ecc}^i) \\
(ss_{mlkem}^i, ct_{mlkem}^i) = \textrm{Encapsulate}_{MLKEM}(pk_{mlkem}^i)
\end{aligned}
$$
```math
\begin{align}
(ss_{ecc}^i, ct_{ecc}^i) &= \textrm{Encapsulate}_{DHKEM}(pk_{ecc}^i) \\
(ss_{mlkem}^i, ct_{mlkem}^i) &= \textrm{Encapsulate}_{MLKEM}(pk_{mlkem}^i)
\end{align}
```

2. Combine the shared secrets (implemented in `mla::crypto::hybrid::combine`):

Expand All @@ -117,20 +117,22 @@ def combine(ss1, ss2, ct1, ct2):
return key
```

$$
```math
ss_{recipient}^i = \textrm{combine}(ss_{ecc}^i, ss_{mlkem}^i, ct_{ecc}^i, ct_{mlkem}^i)
$$
```

3. Wrap the recipients' shared secret:

$$
(key^i, nonce^i) = \textrm{KeySchedule}_{recipient}(
```math
\begin{align}
(key^i, nonce^i) &= \textrm{KeySchedule}_{recipient}(
\textrm{shared\ secret}=ss_{recipient}^i,
\textrm{info}=\mathtt{"MLA\ Recipient"}
)\\
ct_{wrap}^i = \textrm{Encrypt}_{AES\ 256\ GCM}(\textrm{key}=key^i, \textrm{nonce}=nonce^i, \textrm{data}=ss_{recipients})\\
ct_{recipient}^i = ct_{wrap}^i\ .\ ct_{ecc}^i\ .\ ct_{mlkem}^i
$$
ct_{wrap}^i &= \textrm{Encrypt}_{AES\ 256\ GCM}(\textrm{key}=key^i, \textrm{nonce}=nonce^i, \textrm{data}=ss_{recipients})\\
ct_{recipient}^i &= ct_{wrap}^i\ .\ ct_{ecc}^i\ .\ ct_{mlkem}^i
\end{align}
```

Informally, this process can be viewed as a per-recipient KEM taking a shared secret $ss_{recipients}$, the recipient public key (made of the elliptic curve and the PQC public keys) and returning a ciphertext $ct_{recipient}^i$.

Expand All @@ -140,21 +142,25 @@ To obtain the shared secret from $ct_{recipient}^i$ for a recipient $i$ knowing

1. Compute the recipient's shared secret:

$$
ss_{ecc}^i = \textrm{Decapsulate}_{DHKEM}(sk_{ecc}^i, ct_{ecc}^i) \\
ss_{mlkem}^i = \textrm{Decapsulate}_{MLKEM}(sk_{mlkem}^i, ct_{mlkem}^i)\\
ss_{recipient}^i = \textrm{combine}(ss_{ecc}^i, ss_{mlkem}^i, ct_{ecc}^i, ct_{mlkem}^i)
$$
```math
\begin{align}
ss_{ecc}^i &= \textrm{Decapsulate}_{DHKEM}(sk_{ecc}^i, ct_{ecc}^i) \\
ss_{mlkem}^i &= \textrm{Decapsulate}_{MLKEM}(sk_{mlkem}^i, ct_{mlkem}^i)\\
ss_{recipient}^i &= \textrm{combine}(ss_{ecc}^i, ss_{mlkem}^i, ct_{ecc}^i, ct_{mlkem}^i)
\end{align}
```

2. Try to decrypt the secret shared among recipients:

$$
(key^i, nonce^i) = \textrm{KeySchedule}_{recipient}(
```math
\begin{align}
(key^i, nonce^i) &= \textrm{KeySchedule}_{recipient}(
\textrm{shared\ secret}=ss_{recipient}^i,
\textrm{info}=\mathtt{"MLA\ Recipient"}
)\\
ss_{recipients} = \textrm{Decrypt}_{AES\ 256\ GCM}(\textrm{key}=key^i, \textrm{nonce}=nonce^i, \textrm{data}=ct_{wrap}^i)
$$
ss_{recipients} &= \textrm{Decrypt}_{AES\ 256\ GCM}(\textrm{key}=key^i, \textrm{nonce}=nonce^i, \textrm{data}=ct_{wrap}^i)
\end{align}
```

If the decryption is a success, returns $ss_{recipients}$. Otherwise, returns an error.

Expand Down Expand Up @@ -203,7 +209,7 @@ $\mathrm{CSPRNG(n)}$ is a cryptographically secured RNG producing a n-bytes secr

To encapsulate to a list of recipient $[(pk_{ecc}^0, pk_{mlkem}^0), ..., (pk_{ecc}^{n-1}, pk_{mlkem}^{n-1})]$:

$$
```math
\begin{align*}
\mathtt{def\ } & \mathrm{HybridKEM.Encapsulate}([(pk_{ecc}^0, pk_{mlkem}^0), ..., (pk_{ecc}^{n-1}, pk_{mlkem}^{n-1})])\\
& ss_{recipients} = \mathrm{CSPRNG(32)}\\
Expand All @@ -213,11 +219,12 @@ $$
& ct_{recipients} = ct_{recipient}^0\ .\ \dots\ .\ ct_{recipient}^{n-1}\\
& \mathtt{return}\ ss_{recipients},\ ct_{recipients}
\end{align*}
$$
```
----

To decapsulate from a ciphertext $ct_{recipients}$, knowing a recipient private key $(sk_{ecc}^i,sk_{mlkem}^i)$:
$$

```math
\begin{align*}
\mathtt{def\ } & \mathrm{HybridKEM.Decapsulate}((sk_{ecc}^i,sk_{mlkem}^i), ct_{recipients})\\
& \begin{align*}
Expand All @@ -233,7 +240,7 @@ $$
\end{align*}\\
& \mathtt{throw\ KeyNotFoundError}
\end{align*}
$$
```

#### Arguments

Expand Down Expand Up @@ -266,42 +273,42 @@ To encrypt n-bytes `data` to a list of public keys $[(pk_{ecc}^0, pk_{mlkem}^0),

1. Compute a shared secret and the corresponding ciphertext:

$$
```math
ss_{recipients},\ ct_{recipients} = \mathrm{HybridKEM.Encapsulate}([(pk_{ecc}^0, pk_{mlkem}^0), ..., (pk_{ecc}^{n-1}, pk_{mlkem}^{n-1})])
$$
```

2. Derive the key and base nonce using HPKE

$$
```math
(key, base\_nonce) = \textrm{KeySchedule}_{hybrid}(
\textrm{shared\ secret}=ss_{recipients},
\textrm{info}=\mathtt{"MLA\ Encrypt\ Layer"}
)\\
$$
```

3. Ensure key-commitment

$$
```math
\begin{align*}
key\_commit& = \textrm{Encrypt}_{AES\ 256\ GCM}(\\
&\textrm{key}=key,\\
&\textrm{nonce}=\mathrm{ComputeNonce}(base\_nonce, 0),\\
&\textrm{data}=\textrm{KeyCommitmentChain}\\
)&
\end{align*}
$$
```

4. For each 4MB $chunk_j$ of data:

$$
```math
\begin{align*}
enc_j& = \textrm{Encrypt}_{AES\ 256\ GCM}(\\
&\textrm{key}=key,\\
&\textrm{nonce}=\mathrm{ComputeNonce}(base\_nonce, j + 1),\\
&\textrm{data}=chunk_j\\
)&
\end{align*}
$$
```

5. When the layer is finalized, the last chunk $chunk_n$ of data (with a length lower than or equals to 4MB) is encrypted the same way

Expand All @@ -316,45 +323,49 @@ To decrypt the data at position $pos$:

1. Once for the whole session, get the cryptographic materials

$$
ss_{recipients} = \mathrm{HybridKEM.Decapsulate}((sk_{ecc}^i, sk_{mlkem}^i), ct_{recipients})\\
(key, base\_nonce) = \textrm{KeySchedule}_{hybrid}(
```math
\begin{align}
ss_{recipients} &= \mathrm{HybridKEM.Decapsulate}((sk_{ecc}^i, sk_{mlkem}^i), ct_{recipients})\\
(key, base\_nonce) &= \textrm{KeySchedule}_{hybrid}(
\textrm{shared\ secret}=ss_{recipients},
\textrm{info}=\mathtt{"MLA\ Encrypt\ Layer"}
)\\
$$
)
\end{align}
```

2. Once for the whole session, check the key commitment

$$
```math
\begin{align*}
commit& = \textrm{Decrypt}_{AES\ 256\ GCM}(\\
&\textrm{key}=key,\\
&\textrm{nonce}=\mathrm{ComputeNonce}(base\_nonce, 0),\\
&\textrm{data}=key\_commit\\
)&
\end{align*}\\
$$
$$
```
```math
\mathtt{assert\ }commit = \textrm{KeyCommitmentChain}
$$
```

3. Retrieve the encrypted chunk of data

$$
start = pos - \mathtt{sizeof}(key\_commit)\\
j = pos \div 4M\\
$$
```math
\begin{align}
start &= pos - \mathtt{sizeof}(key\_commit)\\
j &= pos \div 4M\\
\end{align}
```
Then:
$$
```math
\begin{align*}
chunk_j& = \textrm{Decrypt}_{AES\ 256\ GCM}(\\
&\textrm{key}=key,\\
&\textrm{nonce}=\mathrm{ComputeNonce}(base\_nonce, j + 1),\\
&\textrm{data}=enc_j\\
)&
\end{align*}
$$
```

#### Arguments

Expand Down Expand Up @@ -388,14 +399,16 @@ The derivation scheme is based on the same ideas than `mla::crypto::hybrid::comb

From a private key ($sk_{ecc}^i$ and $sk_{mlkem}^i$), the secret is derived from the path $path$ through:

$$
ecc\_rnd = \mathrm{HKDF.Extract_{SHA512}}(\mathrm{salt}=0, \mathrm{ikm}=sk_{ecc}^i)\\
seed = \mathrm{HKDF_{SHA512}}(
```math
\begin{align}
ecc\_rnd &= \mathrm{HKDF.Extract_{SHA512}}(\mathrm{salt}=0, \mathrm{ikm}=sk_{ecc}^i)\\
seed &= \mathrm{HKDF_{SHA512}}(
\mathrm{salt}=ecc\_rnd,
\mathrm{ikm}=sk_{mlkem}^i,
\mathrm{info}=\mathtt{"PATH\ DERIVATION"}\ .\ path
)
$$
\end{align}
```

To derive a key using a `seed`, a `ChaChaRng` is used.
If a `seed` is provided, the `ChaChaRng` is seeded with the first 32-bytes of $\mathrm{SHA512}(seed)$. Otherwise, the `ChaChaRng::from_entropy` is used, wrapping OS Cryptographic RNG sources.
Expand Down Expand Up @@ -515,4 +528,4 @@ In other words, the list of recipient is not public. Still, the number of recipi
[^reviewqb]: https://blog.quarkslab.com/security-audit-of-dalek-libraries.html
[^reviewcloudflare]: https://blog.cloudflare.com/using-hpke-to-encrypt-request-payloads/
[^issuezeroize]: https:/ANSSI-FR/MLA/issues/46
[^issueallowunauth]: https:/ANSSI-FR/MLA/issues/167
[^issueallowunauth]: https:/ANSSI-FR/MLA/issues/167

0 comments on commit a3c3edc

Please sign in to comment.