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}