gimli_crypto/
rustcrypto_aead.rs1use crate::{KEY_SIZE, NONCE_SIZE, TAG_SIZE, decrypt_in_place, encrypt_in_place};
6use aead::generic_array::GenericArray;
7use aead::{
8 AeadCore, AeadInPlace, Error, KeyInit, KeySizeUser,
9 consts::{U16, U32},
10};
11use zeroize::{Zeroize, ZeroizeOnDrop};
12
13#[derive(Zeroize, ZeroizeOnDrop)]
15pub struct GimliAead {
16 key: [u8; KEY_SIZE],
17}
18
19impl KeySizeUser for GimliAead {
20 type KeySize = U32;
21}
22
23impl KeyInit for GimliAead {
24 fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
25 let mut s = Self {
26 key: [0u8; KEY_SIZE],
27 };
28 s.key.copy_from_slice(key.as_slice());
29 s
30 }
31}
32
33impl AeadCore for GimliAead {
34 type NonceSize = U16;
35 type TagSize = U16;
36 type CiphertextOverhead = aead::consts::U0;
37}
38
39#[inline(always)]
42const fn ga_nonce_to_array(
43 nonce: &GenericArray<u8, <GimliAead as AeadCore>::NonceSize>,
44) -> &[u8; NONCE_SIZE] {
45 unsafe { core::mem::transmute(nonce) }
54}
55
56#[inline(always)]
59const fn ga_tag_to_array(
60 tag: &GenericArray<u8, <GimliAead as AeadCore>::TagSize>,
61) -> &[u8; TAG_SIZE] {
62 unsafe { core::mem::transmute(tag) }
71}
72
73#[inline(always)]
76const fn tag_array_to_ga(
77 tag: [u8; TAG_SIZE],
78) -> GenericArray<u8, <GimliAead as AeadCore>::TagSize> {
79 unsafe { core::mem::transmute(tag) }
89}
90
91impl AeadInPlace for GimliAead {
92 #[inline]
93 fn encrypt_in_place_detached(
94 &self,
95 nonce: &GenericArray<u8, Self::NonceSize>,
96 associated_data: &[u8],
97 buffer: &mut [u8],
98 ) -> Result<GenericArray<u8, Self::TagSize>, Error> {
99 let tag = encrypt_in_place(&self.key, ga_nonce_to_array(nonce), associated_data, buffer);
100
101 Ok(tag_array_to_ga(tag))
102 }
103
104 #[inline]
105 fn decrypt_in_place_detached(
106 &self,
107 nonce: &GenericArray<u8, Self::NonceSize>,
108 associated_data: &[u8],
109 buffer: &mut [u8],
110 tag: &GenericArray<u8, Self::TagSize>,
111 ) -> Result<(), Error> {
112 decrypt_in_place(
113 &self.key,
114 ga_nonce_to_array(nonce),
115 associated_data,
116 buffer,
117 ga_tag_to_array(tag),
118 )
119 .map_err(|_| Error)
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use aead::AeadInPlace;
127
128 #[test]
129 fn aead_roundtrip() {
130 let key = GenericArray::from([1u8; 32]);
131 let cipher = GimliAead::new(&key);
132
133 let nonce = GenericArray::from([2u8; 16]);
134 let plaintext = *b"Hello, RustCrypto AEAD!";
135 let aad = b"associated data";
136
137 let mut ciphertext = plaintext;
138 let tag = cipher
139 .encrypt_in_place_detached(&nonce, aad, &mut ciphertext)
140 .expect("encryption failed");
141
142 cipher
143 .decrypt_in_place_detached(&nonce, aad, &mut ciphertext, &tag)
144 .expect("decryption failed");
145
146 assert_eq!(&ciphertext, b"Hello, RustCrypto AEAD!");
147 }
148
149 #[test]
150 fn aead_in_place() {
151 let key = GenericArray::from([42u8; 32]);
152 let cipher = GimliAead::new(&key);
153
154 let nonce = GenericArray::from([99u8; 16]);
155 let aad = b"metadata";
156
157 let mut buffer = *b"In-place test! ";
158 let original = buffer;
159
160 let tag = cipher
161 .encrypt_in_place_detached(&nonce, aad, &mut buffer)
162 .expect("encryption failed");
163
164 assert_ne!(&buffer, &original);
165
166 cipher
167 .decrypt_in_place_detached(&nonce, aad, &mut buffer, &tag)
168 .expect("decryption failed");
169
170 assert_eq!(&buffer, &original);
171 }
172
173 #[test]
174 fn aead_wrong_tag() {
175 let key = GenericArray::from([1u8; 32]);
176 let cipher = GimliAead::new(&key);
177
178 let nonce = GenericArray::from([2u8; 16]);
179 let mut buffer = *b"Test message";
180
181 let mut tag = cipher
182 .encrypt_in_place_detached(&nonce, b"", &mut buffer)
183 .expect("encryption failed");
184
185 tag[0] ^= 1;
187
188 let result = cipher.decrypt_in_place_detached(&nonce, b"", &mut buffer, &tag);
189 assert!(result.is_err());
190 }
191}