1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! # Byte-AES
//!
//! ### Developer: Omkarium
//!
//! `byte-aes` is a simple wrapper around the popular `aes` crate. The goal is to perform Encrypt and Decrypt operations
//! using the **Advanced Encryption Standard 256 bit** Algorithm conveninent to use instead of use Low level functions of the `aes` crate

// Bringing all of these items into scope so they can be used in the individual modules without declaring full path
use aes::{
    cipher::{crypto_common::generic_array::GenericArray, typenum::U16},
    Block,
};

pub mod cryptor;

pub use cryptor::Aes256Cryptor;

// This function is for internal use
// It takes those structs which implement the OMFE trait. In this case, the Encryptor and Decryptor structs are implementing it.
// It takes raw_bytes and splits them into chunks of 16 bytes. If any chunk is having less than 16 bytes, this function resize that particular chunk to a
// capacity of 16 bytes filled with data specified by Pkcs7Padding algorithm

fn split_into_16byte_blocks(mut origin: Vec<u8>, is_decrypt: bool) -> Vec<Vec<u8>> {
    let round = origin.len() % 16;
    if round == 0 && !is_decrypt {
        let extra = [16u8; 16];
        origin.extend_from_slice(&extra[..]);
    } else if !is_decrypt {
        let required_padding = 16 - round;
        let extra = vec![required_padding as u8; required_padding];
        origin.extend_from_slice(&extra[..]);
    }
    origin.chunks(16).map(|v| v.to_vec()).collect()
}

// This function gets us a GenericArray key and blocks(data)
// We need a Box here in the return type because the GenericArray type is not sized because its some kind of linked list
// and we cannot return a type whose size is not known during compilation

fn get_generic_array(item: Vec<u8>, is_decrypt: bool) -> Vec<Block> {
    // Once the Encrypted or Decrypted Bytes are provided via self we split then into a a Vec<Vec<u8> where the inner Vec is always 16 bytes long
    let blocks = split_into_16byte_blocks(item, is_decrypt);

    // We can't use the Vec<u8> to directly decrypt, so we need to use the GenericArray struct provided by the aes crate

    // Same logic as the above, but the data we are planning to encrypt shall be 16 byte long blocks. Hence the U16 type.
    let generic_block = blocks
        .into_iter()
        .map(|v| GenericArray::<u8, U16>::from_slice(&v[..]).to_owned())
        .collect();

    // deferencing the Generic block from the Vec as a single Unit
    //let deref_generic_block = generic_block.as_mut_slice();
    generic_block
}

/// This is my create
#[cfg(test)]
mod tests {
    use crate::Aes256Cryptor;

    #[test]
    fn test_with_strings() {
        let my_32byte_key = "Thisi$MyKeyT0Encryp!thislastTime".to_owned();
        let original_text = "I am Omkaram Venkatesh and 
        this is my plain text and some random chars 223@#$^$%*%^(!#@%$~@#$[]]'///\\drewe. Lets see if this gets encrypted now)".to_string();

        let cryptor = Aes256Cryptor::try_from(&my_32byte_key).unwrap();
        let encrypted_bytes: Vec<u8> = cryptor.encrypt(&original_text as &str);

        let decrypted_text: String =
            String::from_utf8_lossy(&cryptor.decrypt(encrypted_bytes).unwrap_or_default())
                .to_string();

        assert_eq!(original_text, decrypted_text);
    }

    #[test]
    fn test_with_bytes() {
        let key = "c4ca4238a0b923820dcc509a6f75849b";
        let cryptor = Aes256Cryptor::try_from(key).unwrap();
        let buf: [u8; 4] = [1, 0, 0, 1];
        let encrypt_buf = cryptor.encrypt(buf);

        let clear_buf = cryptor.decrypt(encrypt_buf);
        let clear_buf = clear_buf.as_ref().map(|v| &v[..]).map_err(|_| ());
        assert_eq!(Ok(&buf[..]), clear_buf);

        let buf: [u8; 16] = [1, 0, 0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13];
        let encrypt_buf = cryptor.encrypt(buf);

        let clear_buf = cryptor.decrypt(encrypt_buf);
        let clear_buf = clear_buf.as_ref().map(|v| &v[..]).map_err(|_| ());
        assert_eq!(Ok(&buf[..]), clear_buf);

        let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 200]; // invalid data for decrypting
        let clear_buf = cryptor.decrypt(buf);
        assert!(clear_buf.is_err());
    }
}