1use alloc::vec::Vec;
4
5use crate::HpkeError;
6use crate::sealed::Sealed;
7
8pub trait Aead: Sealed {
14 const ID: u16;
16 const KEY_LEN: usize;
18 const NONCE_LEN: usize;
20 const TAG_LEN: usize;
22}
23
24pub trait SealingAead: Aead {
31 fn seal(key: &[u8], nonce: &[u8], aad: &[u8], pt: &[u8]) -> Result<Vec<u8>, HpkeError>;
33 fn open(key: &[u8], nonce: &[u8], aad: &[u8], ct: &[u8]) -> Result<Vec<u8>, HpkeError>;
35}
36
37#[derive(Debug, Clone, Copy, Default)]
39pub struct ChaCha20Poly1305;
40
41impl Sealed for ChaCha20Poly1305 {}
42impl Aead for ChaCha20Poly1305 {
43 const ID: u16 = 0x0003;
44 const KEY_LEN: usize = 32;
45 const NONCE_LEN: usize = 12;
46 const TAG_LEN: usize = 16;
47}
48impl SealingAead for ChaCha20Poly1305 {
49 fn seal(key: &[u8], nonce: &[u8], aad: &[u8], pt: &[u8]) -> Result<Vec<u8>, HpkeError> {
50 use chacha20poly1305::{
51 KeyInit, Nonce,
52 aead::{Aead as _, Payload},
53 };
54 let cipher = chacha20poly1305::ChaCha20Poly1305::new_from_slice(key)
55 .map_err(|_| HpkeError::SealError)?;
56 let nonce = Nonce::from_slice(nonce);
57 cipher
58 .encrypt(nonce, Payload { msg: pt, aad })
59 .map_err(|_| HpkeError::SealError)
60 }
61 fn open(key: &[u8], nonce: &[u8], aad: &[u8], ct: &[u8]) -> Result<Vec<u8>, HpkeError> {
62 use chacha20poly1305::{
63 KeyInit, Nonce,
64 aead::{Aead as _, Payload},
65 };
66 let cipher = chacha20poly1305::ChaCha20Poly1305::new_from_slice(key)
67 .map_err(|_| HpkeError::OpenError)?;
68 let nonce = Nonce::from_slice(nonce);
69 cipher
70 .decrypt(nonce, Payload { msg: ct, aad })
71 .map_err(|_| HpkeError::OpenError)
72 }
73}
74
75#[derive(Debug, Clone, Copy, Default)]
80pub struct Aes128Gcm;
81
82impl Sealed for Aes128Gcm {}
83impl Aead for Aes128Gcm {
84 const ID: u16 = 0x0001;
85 const KEY_LEN: usize = 16;
86 const NONCE_LEN: usize = 12;
87 const TAG_LEN: usize = 16;
88}
89impl SealingAead for Aes128Gcm {
90 fn seal(key: &[u8], nonce: &[u8], aad: &[u8], pt: &[u8]) -> Result<Vec<u8>, HpkeError> {
91 use aes_gcm::{KeyInit, aead::Aead as _};
92 let cipher = aes_gcm::Aes128Gcm::new_from_slice(key).map_err(|_| HpkeError::SealError)?;
93 let nonce = aes_gcm::Nonce::from_slice(nonce);
94 cipher
95 .encrypt(nonce, aead::Payload { msg: pt, aad })
96 .map_err(|_| HpkeError::SealError)
97 }
98 fn open(key: &[u8], nonce: &[u8], aad: &[u8], ct: &[u8]) -> Result<Vec<u8>, HpkeError> {
99 use aes_gcm::{KeyInit, aead::Aead as _};
100 let cipher = aes_gcm::Aes128Gcm::new_from_slice(key).map_err(|_| HpkeError::OpenError)?;
101 let nonce = aes_gcm::Nonce::from_slice(nonce);
102 cipher
103 .decrypt(nonce, aead::Payload { msg: ct, aad })
104 .map_err(|_| HpkeError::OpenError)
105 }
106}
107
108#[derive(Debug, Clone, Copy, Default)]
112pub struct Aes256Gcm;
113
114impl Sealed for Aes256Gcm {}
115impl Aead for Aes256Gcm {
116 const ID: u16 = 0x0002;
117 const KEY_LEN: usize = 32;
118 const NONCE_LEN: usize = 12;
119 const TAG_LEN: usize = 16;
120}
121impl SealingAead for Aes256Gcm {
122 fn seal(key: &[u8], nonce: &[u8], aad: &[u8], pt: &[u8]) -> Result<Vec<u8>, HpkeError> {
123 use aes_gcm::{KeyInit, aead::Aead as _};
124 let cipher = aes_gcm::Aes256Gcm::new_from_slice(key).map_err(|_| HpkeError::SealError)?;
125 let nonce = aes_gcm::Nonce::from_slice(nonce);
126 cipher
127 .encrypt(nonce, aead::Payload { msg: pt, aad })
128 .map_err(|_| HpkeError::SealError)
129 }
130 fn open(key: &[u8], nonce: &[u8], aad: &[u8], ct: &[u8]) -> Result<Vec<u8>, HpkeError> {
131 use aes_gcm::{KeyInit, aead::Aead as _};
132 let cipher = aes_gcm::Aes256Gcm::new_from_slice(key).map_err(|_| HpkeError::OpenError)?;
133 let nonce = aes_gcm::Nonce::from_slice(nonce);
134 cipher
135 .decrypt(nonce, aead::Payload { msg: ct, aad })
136 .map_err(|_| HpkeError::OpenError)
137 }
138}
139
140#[derive(Debug, Clone, Copy, Default)]
146pub struct ExportOnly;
147
148impl Sealed for ExportOnly {}
149impl Aead for ExportOnly {
150 const ID: u16 = 0xFFFF;
151 const KEY_LEN: usize = 0;
152 const NONCE_LEN: usize = 0;
153 const TAG_LEN: usize = 0;
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use hex::FromHex;
160
161 #[test]
163 fn rfc8439_chacha20poly1305_test_vector() {
164 let key = Vec::from_hex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f")
165 .unwrap();
166 let nonce = Vec::from_hex("070000004041424344454647").unwrap();
167 let aad = Vec::from_hex("50515253c0c1c2c3c4c5c6c7").unwrap();
168 let pt = b"Ladies and Gentlemen of the class of '99: \
169 If I could offer you only one tip for the future, sunscreen would be it.";
170
171 let ct = ChaCha20Poly1305::seal(&key, &nonce, &aad, pt).unwrap();
172 let recovered = ChaCha20Poly1305::open(&key, &nonce, &aad, &ct).unwrap();
173 assert_eq!(recovered, pt);
174
175 let mut bad = ct.clone();
176 bad[0] ^= 1;
177 assert_eq!(
178 ChaCha20Poly1305::open(&key, &nonce, &aad, &bad),
179 Err(HpkeError::OpenError)
180 );
181 }
182
183 #[test]
184 fn aes128gcm_roundtrip_short() {
185 let key = [0u8; 16];
186 let nonce = [0u8; 12];
187 let aad = b"";
188 let pt = b"hello";
189 let ct = Aes128Gcm::seal(&key, &nonce, aad, pt).unwrap();
190 assert_eq!(ct.len(), pt.len() + 16);
191 assert_eq!(Aes128Gcm::open(&key, &nonce, aad, &ct).unwrap(), pt);
192 }
193
194 #[test]
195 fn aes256gcm_roundtrip_short() {
196 let key = [0u8; 32];
197 let nonce = [0u8; 12];
198 let pt = b"world";
199 let ct = Aes256Gcm::seal(&key, &nonce, b"aad", pt).unwrap();
200 assert_eq!(Aes256Gcm::open(&key, &nonce, b"aad", &ct).unwrap(), pt);
201 }
202
203 #[test]
204 fn aes128gcm_rejects_bad_key_len() {
205 let r = Aes128Gcm::seal(&[0u8; 15], &[0u8; 12], b"", b"");
206 assert!(r.is_err());
207 }
208
209 #[test]
210 fn export_only_implements_aead_only() {
211 fn assert_aead<A: Aead>() {}
212 assert_aead::<ExportOnly>();
213 assert_eq!(ExportOnly::ID, 0xFFFF);
214 assert_eq!(ExportOnly::KEY_LEN, 0);
215 assert_eq!(ExportOnly::NONCE_LEN, 0);
216 assert_eq!(ExportOnly::TAG_LEN, 0);
217 }
218}