Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AES-GCM(includes GHASH) #157

Merged
merged 13 commits into from
Sep 23, 2024
82 changes: 82 additions & 0 deletions examples/aes_gcm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! This code example demonstrates the key feature of GCM cipher mode over CTR mode, which is
//! authentication.

#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

use std::{fmt::Write, str};

use rand::{thread_rng, Rng};
use ronkathon::encryption::symmetric::{
aes::{Key, AES},
modes::gcm::GCM,
};

/// Encode bytes to hex
pub fn encode_hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for &b in bytes {
write!(&mut s, "{:02x}", b).unwrap();
}
s
}

fn ideal_world(msg: &[u8]){
println!("---Ideal World!---\n");

let mut rng = thread_rng();
let key = Key::<128>::new(rng.gen());
let iv: [u8; 12] = rng.gen();
let gcm = GCM::<AES<128>>::new(key);

let (enc, tag1) = gcm.encrypt(&iv, msg, b"").unwrap();

println!("msg:\t{}(={})", encode_hex(msg), str::from_utf8(msg).unwrap());

println!("enc:\t{}", encode_hex(&enc));

println!("tag1:\t{}", encode_hex(&tag1));

let (dec, tag2) = gcm.decrypt(&iv, &enc, b"").unwrap();
println!("dec:\t{}(={})", encode_hex(&dec), str::from_utf8(&dec).unwrap());

assert_eq!(tag1, tag2);

println!("tag2:\t{}", encode_hex(&tag2));
}
fn real_world(msg: &[u8]) {
println!("\n---Real World!---\n");

let mut rng = thread_rng();
let key = Key::<128>::new(rng.gen());
let iv: [u8; 12] = rng.gen();
let gcm = GCM::<AES<128>>::new(key);

let (mut enc, tag1) = gcm.encrypt(&iv, msg, b"").unwrap();

println!("msg:\t{}(={})", encode_hex(msg), str::from_utf8(msg).unwrap());

println!("enc:\t{}", encode_hex(&enc));
println!("enc_tag:{}", encode_hex(&tag1));

enc[3] += 1;
enc[4] += 1;
enc[6] += 1;

println!("bad enc:{}", encode_hex(&enc));

let (dec, tag2) = gcm.decrypt(&iv, &enc, b"").unwrap();
println!("dec:\t{}(={})", encode_hex(&dec), str::from_utf8(&dec).unwrap());
println!("dec_tag:{}", encode_hex(&tag2));

assert!(tag1 != tag2);
println!("The tags are not equal!");
}

fn main(){
let message = b"Hello World!";

ideal_world(message);

real_world(message);
}
1 change: 0 additions & 1 deletion src/encryption/symmetric/aes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ where [(); N / 8]:
.try_into()
.unwrap(),
);
assert!(state != State::default(), "State is not instantiated");

// Round 0 - add round key
Self::add_round_key(&mut state, round_keys.next().unwrap());
Expand Down
62 changes: 62 additions & 0 deletions src/encryption/symmetric/modes/README.md
mrdaybird marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,68 @@ IV4["IV||2"]-->Fk2[F_k]-->xor2["⨁"]-->c2
m2-->xor2
```

## GCM: Galois/Counter Mode

GCM is a block cipher mode of operation that provides both confidentiality and authentication.
To provide confidentiality, it uses Counter(CTR) mode for encryption and decryption.
To provide authentication, it uses a universal hash function, GHASH.
Authentication is provided not only for confidential data but also other associated data.

In this section, we will give an informal overview of GCM mode for 128-bit block cipher.
*To see the formal definition of the operations of GCM, I recommend reading the original paper. [The Galois/Counter Mode of Operation (GCM)](https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf)*

The two operations of GCM are authenticated encryption and authenticated decryption.

Here is a figure that gives a complete overview of the authenticated encryption in GCM.

In the figure, we have taken
- the size of plaintext is `3 * 128-bit = 384 bits or 48 bytes`,
- Additionally Authenticated Data(AAD) is of `2 * 128-bit = 248 bits or 32 bytes`.

![GCM](./figure_full_gcm.svg)
*Note: The yellow diamonds represent functions/algorithms, the small rectangle with a blue outline represents 128-bit blocks.*
Also,
- *Enc(K)*: The encryption operation of the cipher used, for example AES, under the key K.
- *incr*: The increment function, which treats the rightmost 32-bit of the block as an unsigned integer and increments it by 1.

If you look at the figure carefully, you will notice that the GCM mode is composed of two main parts:
- Encryption: This part is the same as the CTR mode of operation, with minor changes to the counter block.
- Authentication: In this part, we generate an authentication tag for the ciphertext and some additional data, which we refer to as Additionally Authenticated Data(AAD).

The counter block is the same as in CTR mode. In general, it can be thought of as a 96-bit nonce value followed by a 32-bit counter value.

The tag is generated by XOR of:
1. Hash of ciphertext and AAD, using GHASH algorithm
2. Encryption of Counter block 0.

### GHASH

The GHASH algorithm can be viewed as a series of `ADD and MULTIPLY` in $GF(2^{128})$. Mathematically put the basic operation of GHASH is,

$$
X_{i} =
\begin{cases}
0 & \quad i = 0 \\
( X_{i-1} \oplus B_{i} ) * H & \quad \text{otherwise}
\end{cases}
$$

$B_{i}$ represents blocks of AAD followed by blocks of ciphertext followed by a special length block.
The length block consists of 64-bit lengths(in bits) of AAD and ciphertext.
$H$ called the hash key, is the encryption of 128-bit of zeros using the chosen cipher and key.

The interesting thing to note here is that the multiplication($*$) and addition($\oplus$) are operations of the Galois(finite) field of order $2^{128}$.
A brief summary of finite field arithmetic,
- The elements of the field are represented as polynomials. Each bit of the 128-bit block represents coefficients of a polynomial of degree strictly less than 128.
- Addition in a finite field is equivalent to bitwise XOR.
- Multiplication in a finite field is the multiplication of corresponding polynomials modulo an irreducible reducing polynomial.

In GCM the reducing polynomial is $f = 1 + x + x^2 + x^7 + x^{128}$

If you want to read about Finite Field, the Wikipedia article on [Finite Field Arithemtic](https://en.wikipedia.org/wiki/Galois/Counter_Mode) is pretty good!

The authenticated decryption operation is identical to authenticated encryption, except the tag is generated before the decryption.

## Next Steps
Implement more modes, and subsequent attacks/vulnerabilities:
- [ ] CFB
Expand Down
Loading
Loading