1use nonce_extension::nonce_extension_aes256;
2
3pub mod reexports {
4 pub use nonce_extension;
5}
6use aes_gcm::{
7 aead::{AeadInPlace, KeyInit},
8 Aes256Gcm, Nonce, Tag,
9};
10use getrandom::getrandom;
11
12#[derive(Debug)]
14pub struct Error;
15
16impl std::error::Error for Error {}
17
18impl std::fmt::Display for Error {
19 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
20 write!(f, "Error")
21 }
22}
23
24pub struct XAes256Gcm;
36
37impl XAes256Gcm {
38 pub fn keygen() -> [u8; 32] {
44 let mut key = [0u8; 32];
45 getrandom(&mut key).unwrap();
46 key
47 }
48
49 pub fn encrypt(
61 key: &[u8; 32],
62 plaintext: impl AsRef<[u8]>,
63 associated_data: Option<&[u8]>,
64 ) -> Vec<u8> {
65 let plaintext = plaintext.as_ref();
66 let mut nonce = [0u8; 24];
67 getrandom(&mut nonce).unwrap();
68 let dk = nonce_extension_aes256(key, &nonce);
69 let ks = Aes256Gcm::new((&dk).into());
70 let mut out = Vec::with_capacity(nonce.len() + plaintext.len() + 16);
71 out.extend_from_slice(&nonce);
72 out.extend_from_slice(plaintext);
73 out.extend_from_slice(&[0u8; 16]);
74 let associated_data = associated_data.unwrap_or(&[]);
75 let zero_nonce = Nonce::from([0u8; 12]);
76 let tag = ks
77 .encrypt_in_place_detached(
78 &zero_nonce,
79 associated_data,
80 &mut out[nonce.len()..][0..plaintext.len()],
81 )
82 .unwrap();
83 out[nonce.len() + plaintext.len()..].copy_from_slice(tag.as_slice());
84 out
85 }
86
87 pub fn decrypt(
100 key: &[u8; 32],
101 ciphertext: impl AsRef<[u8]>,
102 associated_data: Option<&[u8]>,
103 ) -> Result<Vec<u8>, Error> {
104 let ciphertext = ciphertext.as_ref();
105 if ciphertext.len() < 24 + 16 {
106 return Err(Error);
107 }
108 let nonce = &ciphertext[..24];
109 let dk = nonce_extension_aes256(key, nonce);
110 let ks = Aes256Gcm::new((&dk).into());
111 let plaintext_len = ciphertext.len() - (24 + 16);
112 let mut out = ciphertext[24..][0..plaintext_len].to_vec();
113 let associated_data = associated_data.unwrap_or(&[]);
114 let mut tag = Tag::default();
115 tag.as_mut_slice()
116 .copy_from_slice(&ciphertext[ciphertext.len() - 16..]);
117 let zero_nonce = Nonce::from([0u8; 12]);
118 ks.decrypt_in_place_detached(&zero_nonce, associated_data, &mut out, &tag)
119 .map_err(|_| Error)?;
120 Ok(out)
121 }
122}
123
124#[test]
125fn test() {
126 let key = XAes256Gcm::keygen();
127 let plaintext = b"hello world";
128 let ciphertext = XAes256Gcm::encrypt(&key, plaintext, None);
129 let decrypted = XAes256Gcm::decrypt(&key, ciphertext, None).unwrap();
130 assert_eq!(plaintext, &decrypted[..]);
131}