Note: Information about AES - Advanced Encryption Standard and mode GCM, GCM-SIV can be read here.
Background:
When I come across the Invisible Salamander paper that described a way to bypass Facebook attachment franking scheme: a malicious user can send an objectionable image to a recipient but that recipient cannot report it as abuse. And a blog about this attack can work with AES GCM SIV.
For more details, it can be understand that we can construct a poison ciphertext and a tag that is valid under two different keys. One key will decrypt to the message we need, the other will decrypt to some trash value. The case in the paper, the attacker would make the attachment twice as long, with the first part decrypt to a abuse picture under key 1, and the second part a normal picture under key 2.
Salamander example.
Facebook attack.
Details:
Constructing Salamander on AES GCM:
About this mode of AES, see here. For easy when writing the equation, I will denote addition operation as “+” and multiplication as $\cdot$. In the blog (my blog or this), we can see that the GHASH function can be define as:
$$GHASH(H,C,T) = \Sigma_{i=0}^{n} (X_i \cdot H^{n-i+1}) + T = C_0 \cdot H^{n+1} + C_1 \cdot H^{n} + \dotsb + C_n \cdot H^{1} +T$$
With H = AES_ECB_encryption(key,$0^{128}$), T = AES_ECB_encryption(key,IV $||$ $0^{31}$ $||$ 1), and C = AES_CTR(key,Plaintext,nonce = IV $||$ $0^{31}$ $||$ 2) is divided into blocks of 16 bytes $C_i$
To have a ciphertext that is valid under 2 different key. We need to fix the tag, that is $GHASH(H_1,C,T_1) = GHASH(H_2,C,T_2)$. And to achieve this we just add a sacrificial block append to the ciphertext (note: we can append and calculate it at any position, but for simplicity we will append it at the end of the ciphertext). So that the length of the poison ciphertext is one block more than normal ciphertext of that message.
Variants:
For the case we just need one key to work.
Need plaintext for 2 keys
But in this case we will have a trash block at the front of the key 2 decryption. So to avoid this we have to brute some bytes of ciphertext 1 to make the decryption by key 2 have opening and ending comment for plaintext block 1.
Implementation:
We will be using SageMath to implement the POC because it support finite field arithmetic.
Convert data into field element and reverse:
|
|
Calculation:
|
|
Constructing Salamander on AES GCM SIV:
About this mode of AES, see here. In the blog, I have depicted the different between the two functions GHASH and POLYVAL. GHASH is calculated using the ciphertext, but POLYVAL is calculated using the plaintext.
In AES-GCM-SIV, the output from POLYVAL function will be served as input to a AES-ECB encryption, which in turn (xor with nonce) is the input to AES-CTR encryption from plaintext to the ciphertext. So the approach making two authenticator function equal is not enough in this scenario.
Summary, AES-GCM-SIV will have this elements:
- $ \text{msg_auth_key,msg_enc_key = Key derivation(master key). we will denote}$ $H = ;\text{msg_auth_key} ; \cdot x^{-128} ; \text{and msg_enc_key} = K_e$
- $POVYVAL(H,P) = \sum_{i=0}^{n}(P_i \cdot H^{n+1-i}) = S_s$
- $\text{tag = AES-ECB(key=}K_E,POLYVAL(H,P))$
- $\text{C = AES-CTR(key}K_E,IV=tag)$
The plaintext block $P$ is consists of aad, plaintext, len(aad), len(plaintext).
So the approach for this will be fixed the tag first. And from that calculate $$S_{s,i} = \text{AES-EBC-Decrypt}(K_{E,i},tag)$$
Which will give us 2 linear equations will $2n$ variables. But out ciphertext need to be the same - by definition. So we have another constrain. $$ C_{i,1} = C_{i,2}$$.
Ciphertext is constructed using $AES-CTR$ and everything is on $GF(2)$ so the xor operation is just addition. Let $\text{key_stream1}$ and $\text{key_stream2}$ is the output of $AES-CTR$ using $K_{E,1}$ and $K_{E,2}$ respectively.
So we have to satisfy the equations:
$$ \text{key_stream1}[i] + P_{i,1} = \text{key_stream2}[i] + P_{i,2}$$
With give us $n$ more equations. So if our plaintext needed has $n$ blocks of 16 bytes and by adding $2$ sacrificial blocks to a total of $n+2$ blocks, we will have $2$ equations from $POLYVAL$, $n+2$ from $\text{key_stream}$ and $n$ from fixing our plaintext needed to a total of $2+n+2+n = 2\cdot(n+2)$ linear equations for $2\cdot(n+2)$ variables so it is sufficient to solve easily. All the equation can be written in matrix form.
$$P(\text{n blocks + 2 sacrificial block}) ; \Rightarrow \text{Matrix (n+2)x(n+2)}$$
$$ \begin{pmatrix} H_1^{n+3} & H_1^{n+2} & … & H_1^{2} & 0 & 0 & … & 0 \ 0 & 0 & … & 0 &H_2^{n+3} & H_2^{n+2} & … & H_2^{2} \ 1 & 0 & … & 0 & 1 & 0 & .. & 0 \ 0 & 1 & … & 0 & 0 & 1 & .. & 0 \ .\ .\ 0 & 0 & .. & 1 & 0 & 0 & .. & 1\ 1 & 0 & ..& 0 & 0 & 0 & .. & 0 \ 0 & 1 & .. & 0 & 0 & 0 & .. & 0 \ . \ . \ 0 & 0 & .. & 1 & 0 & 0 & .. & 0 \end{pmatrix} \cdot X = \begin{pmatrix} S_{s1} + H_1^{n+3+len(aad)}\cdot aad_0 + H_1^{n+3+len(aad)-1} \cdot aad_1 + … + H_1^{n+3+1} \cdot aad_{len(aad)-1}\ S_{s2} + H_2^{n+3+len(aad)}\cdot aad_0 + H_2^{n+3+len(aad)-1} \cdot aad_1 + … + H_2^{n+3+1} \cdot aad_{len(aad)-1}\ \text{key_stream1}[0] + \text{key_stream2}[0]\ \text{key_stream1}[1] + \text{key_stream2}[1]\ .\ .\ \text{key_stream1}[n+2] + \text{key_stream2}[n+2]\ \text{need_plaintext1}[0]\ \text{need_plaintext1}[1]\ .\ .\ \text{need_plaintext1}[n+2]\ \end{pmatrix} $$
$$ \begin{pmatrix} H_1^{n+3} & H_1^{n+2} & … & H_1^{2} & 0 & 0 & … & 0 \ 0 & 0 & … & 0 &H_2^{n+3} & H_2^{n+2} & … & H_2^{2} \ 1 & 0 & … & 0 & 1 & 0 & .. & 0 \ 0 & 1 & … & 0 & 0 & 1 & .. & 0 \ .\ .\ 0 & 0 & .. & 1 & 0 & 0 & .. & 1\ 1 & 0 & ..& 0 & 0 & 0 & .. & 0 \ 0 & 0 & .. & 0 & 0 & 1 & .. & 0 \ . \ . \ 0 & 0 & .. & 1 & 0 & 0 & .. & 0 \end{pmatrix} \cdot X = \begin{pmatrix} S_{s1} + H_1^{n+3+len(aad)}\cdot aad_0 + H_1^{n+3+len(aad)-1} \cdot aad_1 + … + H_1^{n+3+1} \cdot aad_{len(aad)-1}\ S_{s2} + H_2^{n+3+len(aad)}\cdot aad_0 + H_2^{n+3+len(aad)-1} \cdot aad_1 + … + H_2^{n+3+1} \cdot aad_{len(aad)-1}\ \text{key_stream1}[0] + \text{key_stream2}[0]\ \text{key_stream1}[1] + \text{key_stream2}[1]\ .\ .\ \text{key_stream1}[n+2] + \text{key_stream2}[n+2]\ \text{need_plaintext1}[0]\ \text{need_plaintext2}[1]\ .\ .\ \text{need_plaintext1}[n+2]\ \end{pmatrix} $$
Variants:
From the two matrix above, we can see that the variant from AES GCM still work here.
For the case we just need one key to work.
Need plaintext for 2 keys
Implementation:
Convert data into field element and reverse:
|
|
Check randomize a correct tag:
|
|
Calculation:
|
|
Need plaintext for 2 keys
References
-
Invisible Salamanders in AES-GCM-SIV
- Analysis of vulnerabilities in AES-GCM-SIV.
-
Another Look at Security of GCM
- Examination of GCM security and associated issues.