1use std::io::Read;
10use std::ops::Deref;
11
12use chacha20poly1305::Key;
13use chacha20poly1305::{
14 aead::{Aead, KeyInit},
15 ChaCha20Poly1305, Nonce,
16};
17use serde::{Deserialize, Serialize};
18
19pub const NONCE_SIZE: usize = 12;
21pub const SECRET_SIZE: usize = 32;
23#[allow(dead_code)]
25pub const CHUNK_SIZE: usize = 4096;
26
27#[derive(Debug, thiserror::Error)]
29pub enum SecretError {
30 #[error("secret error: {0}")]
31 Default(#[from] anyhow::Error),
32 #[error("IO error: {0}")]
33 Io(#[from] std::io::Error),
34}
35
36#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
56pub struct Secret([u8; SECRET_SIZE]);
57
58impl Default for Secret {
59 fn default() -> Self {
60 Secret([0; SECRET_SIZE])
61 }
62}
63
64impl Deref for Secret {
65 type Target = [u8; SECRET_SIZE];
66 fn deref(&self) -> &Self::Target {
67 &self.0
68 }
69}
70
71impl From<[u8; SECRET_SIZE]> for Secret {
72 fn from(bytes: [u8; SECRET_SIZE]) -> Self {
73 Secret(bytes)
74 }
75}
76
77impl Secret {
78 pub fn generate() -> Self {
80 let mut buff = [0; SECRET_SIZE];
81 getrandom::getrandom(&mut buff).expect("failed to generate random bytes");
82 Self(buff)
83 }
84
85 pub fn from_slice(data: &[u8]) -> Result<Self, SecretError> {
91 if data.len() != SECRET_SIZE {
92 return Err(anyhow::anyhow!(
93 "invalid secret size, expected {}, got {}",
94 SECRET_SIZE,
95 data.len()
96 )
97 .into());
98 }
99 let mut buff = [0; SECRET_SIZE];
100 buff.copy_from_slice(data);
101 Ok(buff.into())
102 }
103
104 pub fn bytes(&self) -> &[u8] {
106 self.0.as_ref()
107 }
108
109 pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, SecretError> {
118 let key = Key::from_slice(self.bytes());
119 let cipher = ChaCha20Poly1305::new(key);
120
121 let mut nonce_bytes = [0u8; NONCE_SIZE];
123 getrandom::getrandom(&mut nonce_bytes)
124 .map_err(|e| anyhow::anyhow!("failed to generate nonce: {}", e))?;
125 let nonce = Nonce::from_slice(&nonce_bytes);
126
127 let ciphertext = cipher
128 .encrypt(nonce, data.as_ref())
129 .map_err(|_| anyhow::anyhow!("encrypt error"))?;
130
131 let mut out = Vec::with_capacity(NONCE_SIZE + ciphertext.len());
132 out.extend_from_slice(nonce.as_ref());
133 out.extend_from_slice(ciphertext.as_ref());
134
135 Ok(out)
136 }
137
138 pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, SecretError> {
148 if data.len() < NONCE_SIZE {
149 return Err(anyhow::anyhow!("data too short for nonce").into());
150 }
151
152 let key = Key::from_slice(self.bytes());
153 let nonce = Nonce::from_slice(&data[..NONCE_SIZE]);
154 let cipher = ChaCha20Poly1305::new(key);
155 let decrypted = cipher
156 .decrypt(nonce, &data[NONCE_SIZE..])
157 .map_err(|_| anyhow::anyhow!("decrypt error"))?;
158
159 Ok(decrypted.to_vec())
160 }
161
162 pub fn encrypt_reader<R>(&self, reader: R) -> Result<impl Read, SecretError>
167 where
168 R: Read,
169 {
170 let mut data = Vec::new();
171 let mut reader = reader;
172 reader.read_to_end(&mut data).map_err(SecretError::Io)?;
173
174 let encrypted = self.encrypt(&data)?;
175 Ok(std::io::Cursor::new(encrypted))
176 }
177
178 pub fn decrypt_reader<R>(&self, reader: R) -> Result<impl Read, SecretError>
183 where
184 R: Read,
185 {
186 let mut encrypted_data = Vec::new();
187 let mut reader = reader;
188 reader
189 .read_to_end(&mut encrypted_data)
190 .map_err(SecretError::Io)?;
191
192 let decrypted = self.decrypt(&encrypted_data)?;
193 Ok(std::io::Cursor::new(decrypted))
194 }
195}
196
197#[cfg(test)]
198mod test {
199 use super::*;
200 use std::io::Cursor;
201
202 #[test]
203 fn test_secret_encrypt_decrypt() {
204 let secret = Secret::generate();
205 let data = b"hello world, this is a test message for encryption";
206
207 let encrypted = secret.encrypt(data).unwrap();
208 let decrypted = secret.decrypt(&encrypted).unwrap();
209
210 assert_eq!(data.as_slice(), decrypted.as_slice());
211 }
212
213 #[test]
214 fn test_encrypt_decrypt_reader() {
215 let secret = Secret::generate();
216 let data = b"hello world, this is a test message for reader encryption and decryption";
217
218 let reader = Cursor::new(data.to_vec());
220 let mut encrypted_reader = secret.encrypt_reader(reader).unwrap();
221
222 let mut encrypted_data = Vec::new();
224 encrypted_reader.read_to_end(&mut encrypted_data).unwrap();
225
226 let encrypted_cursor = Cursor::new(encrypted_data);
228 let mut decrypted_reader = secret.decrypt_reader(encrypted_cursor).unwrap();
229
230 let mut decrypted_data = Vec::new();
231 decrypted_reader.read_to_end(&mut decrypted_data).unwrap();
232
233 assert_eq!(data.to_vec(), decrypted_data);
234 }
235
236 #[test]
237 fn test_secret_size_validation() {
238 let too_short = [1u8; 16];
239 let too_long = [1u8; 64];
240
241 assert!(Secret::from_slice(&too_short).is_err());
242 assert!(Secret::from_slice(&too_long).is_err());
243
244 let just_right = [1u8; SECRET_SIZE];
245 assert!(Secret::from_slice(&just_right).is_ok());
246 }
247}