aes/
aes.rs

1// Copyright 2023 The rust-ggstd authors. All rights reserved.
2// Copyright 2009 The Go Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6use ggstd::crypto::aes;
7use ggstd::crypto::cipher::{self, Block, BlockMode, Stream};
8use ggstd::encoding::hex;
9
10fn main() {
11    let key: &[u8] = b"0123456789abcdef";
12    let plaintext: &[u8] = b"hello world.....hello world.....hello world.....";
13
14    println!("plaintext:      {}", String::from_utf8_lossy(plaintext));
15    aes_ecb(key, plaintext);
16    aes_cbc(key, plaintext);
17
18    // in CTR mode plaintext doesn't have to be a multiple of the block size
19    let plaintext: &[u8] = b"hello world.....hello world.....hello worl";
20    println!("plaintext:      {}", String::from_utf8_lossy(plaintext));
21    aes_ctr(key, plaintext);
22}
23
24/// Shows the simplest mode of operation of a block ciper - Electronic Codebook (ECB).
25/// In ECB mode, each block of plaintext is independently encrypted into a block of ciphertext,
26/// without any interaction between the blocks.
27fn aes_ecb(key: &[u8], plaintext: &[u8]) {
28    let block = aes::Cipher::new(key).unwrap();
29    assert!(
30        plaintext.len() % aes::BLOCK_SIZE == 0,
31        "Plaintext length must be a multiple of the block size"
32    );
33
34    let mut encrypted = vec![0; plaintext.len()];
35
36    for offset in (0..plaintext.len()).step_by(aes::BLOCK_SIZE) {
37        block.encrypt(
38            &mut encrypted[offset..offset + aes::BLOCK_SIZE],
39            &plaintext[offset..offset + aes::BLOCK_SIZE],
40        );
41    }
42
43    // let mut decrypted = vec![0; plaintext.len()];
44    // block.decrypt(&mut decrypted, &encrypted);
45    // block.decrypt(
46    //     &mut decrypted[aes::BLOCK_SIZE..],
47    //     &encrypted[aes::BLOCK_SIZE..],
48    // );
49
50    // println!("plaintext:      {}", String::from_utf8_lossy(plaintext));
51    println!("ECB encrypted:  {}", hex::encode_to_string(&encrypted));
52    // println!("decrypted:      {}", String::from_utf8_lossy(&decrypted));
53    // println!()
54}
55
56/// In CBC (Cipher Block Chaining) mode, the plaintext is divided into fixed-size blocks,
57/// and each block is XORed with the ciphertext of the previous block before being encrypted.
58/// The first block is XORed with an Initialization Vector (IV) to start the chain.
59fn aes_cbc(key: &[u8], plaintext: &[u8]) {
60    let block = aes::Cipher::new(key).unwrap();
61    assert!(
62        plaintext.len() % aes::BLOCK_SIZE == 0,
63        "Plaintext length must be a multiple of the block size"
64    );
65
66    // Using the initialization vector of all zeroes for demo purposes.
67    // In practice the IV should be unique for each encryption operation and upredictable,
68    // for example, generated using a secure random generator.
69    let iv = vec![0; aes::BLOCK_SIZE];
70    let mut mode = cipher::CBCEncrypter::new(&block, &iv);
71
72    let mut encrypted = vec![0; plaintext.len()];
73    mode.crypt_blocks(&mut encrypted, plaintext);
74
75    // let mut mode = cipher::CBCDecrypter::new(&block, &iv);
76    // let mut decrypted = vec![0; plaintext.len()];
77    // mode.crypt_blocks(&mut decrypted, &encrypted);
78
79    // println!("plaintext:      {}", String::from_utf8_lossy(plaintext));
80    println!("CBC encrypted:  {}", hex::encode_to_string(&encrypted));
81    // println!("decrypted:      {}", String::from_utf8_lossy(&decrypted));
82    // println!();
83}
84
85/// CTR (Counter mode), is a mode of operation that turns a block cipher into a stream cipher.
86fn aes_ctr(key: &[u8], plaintext: &[u8]) {
87    let block = aes::Cipher::new(key).unwrap();
88
89    // Using the initialization vector of all zeroes for demo purposes.
90    // In practice the IV should be unique for each encryption operation and upredictable,
91    // for example, generated using a secure random generator.
92    let iv = vec![0; aes::BLOCK_SIZE];
93
94    let mut stream = cipher::CTR::new(&block, &iv);
95
96    let mut encrypted = vec![0; plaintext.len()];
97    stream.xor_key_stream(&mut encrypted, &plaintext);
98
99    // // decrypting the ciphertext back to plaintext using the same key, iv, and block
100    // let mut stream = cipher::CTR::new(&block, &iv);
101    // let mut decrypted = vec![0; plaintext.len()];
102    // stream.xor_key_stream(&mut decrypted, &encrypted);
103
104    // println!("plaintext:      {}", String::from_utf8_lossy(plaintext));
105    println!("CTR encrypted:  {}", hex::encode_to_string(&encrypted));
106    // println!("decrypted:      {}", String::from_utf8_lossy(&decrypted));
107    // println!();
108}