Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_crypto/src/enc.rs

8.8 KiB, 41 runs

created by r1870400018:228, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 keys::Keys,
3};
4
5use oxedyne_fe2o3_core::{
6 prelude::*,
7};
8use oxedyne_fe2o3_iop_crypto::{
9 enc::Encrypter,
10 keys::KeyManager,
11};
12use oxedyne_fe2o3_namex::{
13 id::{
14 LocalId,
15 InNamex,
16 NamexId,
17 },
18};
19
20use std::{
21 convert::TryFrom,
22 fmt,
23 str,
24};
25
26use aes_gcm::{
27 aead::Aead,
28 Aes256Gcm,
29 KeyInit,
30 Nonce,
31};
32use rand_core::{
33 OsRng,
34 RngCore,
35};
36use secrecy::{
37 ExposeSecret,
38 Secret,
39};
40
41
42#[derive(Clone)]
43pub enum EncryptionScheme {
44 // Symmetric
45 AES_256_GCM(Keys<
46 0,
47 {Self::AES_256_GCM_SK_LEN},
48 >),
49}
50
51impl fmt::Display for EncryptionScheme {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{:?}", self)
54 }
55}
56
57impl fmt::Debug for EncryptionScheme {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 match self {
60 Self::AES_256_GCM(..) => write!(f, "AES-256-GCM"),
61 }
62 }
63}
64
65impl InNamex for EncryptionScheme {
66
67 fn name_id(&self) -> Outcome<NamexId> {
68 Ok(match self {
69 Self::AES_256_GCM(..) =>
70 res!(NamexId::try_from("4IaH4F8elJw60EkIr2N9+S1avkvUDHX5IaH1GkEKoXQ=")),
71 })
72 }
73
74 /// Version-dependent identifier for the encryption scheme. The type of the identifier can
75 /// change with verisons. This offers a much more compact alternative to the 256 bit Namex
76 /// id.
77 fn local_id(&self) -> LocalId {
78 match self {
79 Self::AES_256_GCM(..) => LocalId(1),
80 }
81 }
82
83 fn assoc_names_base64(
84 gname: &'static str,
85 )
86 -> Outcome<Option<Vec<(
87 &'static str,
88 &'static str,
89 )>>>
90 {
91 let ids = match gname {
92 "schemes" => [
93 ("AES-256-GCM", "4IaH4F8elJw60EkIr2N9+S1avkvUDHX5IaH1GkEKoXQ="),
94 ],
95 _ => return Err(err!(
96 "The Namex group name '{}' is not recognised for EncryptionScheme.", gname;
97 Invalid, Input)),
98 };
99 Ok(if ids.len() == 0 {
100 None
101 } else {
102 Some(ids.to_vec())
103 })
104 }
105}
106
107impl Encrypter for EncryptionScheme {
108
109 fn encrypt(&self, data: &[u8]) -> Outcome<Vec<u8>> {
110 match self {
111 Self::AES_256_GCM(keys) => match keys {
112 Keys { sks: Some(sks), .. } => {
113 let sk = sks.expose_secret();
114 let mut nbyts = [0u8; Self::AES_256_GCM_NONCE_BYTES];
115 OsRng.fill_bytes(&mut nbyts);
116 let nonce = Nonce::from_slice(&nbyts[..]);
117 let cipher = res!(Aes256Gcm::new_from_slice(&sk[..]));
118 let mut cipherdata = match cipher.encrypt(nonce, data) {
119 Err(e) => return Err(err!(e,
120 "While encrypting input of {} byts using scheme {:?}.",
121 data.len(), self;
122 Encrypt)),
123 Ok(result) => result,
124 };
125 cipherdata.extend_from_slice(&nbyts[..]);
126 Ok(cipherdata)
127 },
128 _ => Err(err!(
129 "Require secret key to encrypt.";
130 Missing, Configuration)),
131 },
132 }
133 }
134
135 fn decrypt(&self, data: &[u8]) -> Outcome<Vec<u8>> {
136 match self {
137 Self::AES_256_GCM(keys) => match keys {
138 Keys { sks: Some(sks), .. } => {
139 let sk = sks.expose_secret();
140 if data.len() < Self::AES_256_GCM_NONCE_BYTES {
141 return Err(err!(
142 "Data length only {}. Data to be decrypted using \
143 this scheme must have a minimum length of {} bytes \
144 so as to include the appended nonce.",
145 data.len(), Self::AES_256_GCM_NONCE_BYTES;
146 Decrypt, Invalid, Input));
147 }
148 let datlen = data.len() - Self::AES_256_GCM_NONCE_BYTES;
149 let nonce = Nonce::from_slice(&data[datlen..]);
150 let cipher = res!(Aes256Gcm::new_from_slice(&sk[..]));
151 match cipher.decrypt(nonce, &data[..datlen]) {
152 Err(e) => Err(err!(e,
153 "While decrypting input of {} byts (minus nonce) \
154 using scheme {:?}.", datlen, self;
155 Decrypt)),
156 Ok(result) => Ok(result),
157 }
158 },
159 _ => Err(err!(
160 "Require secret key to decrypt.";
161 Missing, Configuration)),
162 },
163 }
164 }
165
166 fn is_identity(&self) -> bool { false }
167}
168
169impl KeyManager for EncryptionScheme {
170
171 /// Clone using the specified keys.
172 fn clone_with_keys(&self, _pk: Option<&[u8]>, sk: Option<&[u8]>) -> Outcome<Self> {
173 Ok(match self {
174 Self::AES_256_GCM(..) => Self::AES_256_GCM(Keys {
175 pk: None,
176 sks: match sk {
177 Some(sk) => Some(Secret::new(
178 res!(<[u8; Self::AES_256_GCM_SK_LEN]>::try_from(&sk[..]))
179 )),
180 None => None,
181 },
182 }),
183 })
184 }
185
186 fn get_public_key(&self) -> Outcome<Option<&[u8]>> {
187 Ok(match self {
188 Self::AES_256_GCM(keys) => match &keys.pk {
189 Some(k) => Some(&k[..]),
190 None => None,
191 },
192 })
193 }
194
195 fn get_secret_key(&self) -> Outcome<Option<&[u8]>> {
196 Ok(match self {
197 Self::AES_256_GCM(keys) => match &keys.sks {
198 Some(sks) => {
199 let sk = sks.expose_secret();
200 Some(&sk[..])
201 },
202 None => None,
203 },
204 })
205 }
206
207 fn set_public_key(mut self, _pk: Option<&[u8]>) -> Outcome<Self> {
208 match &mut self {
209 Self::AES_256_GCM(..) => (),
210 }
211 Ok(self)
212 }
213
214 fn set_secret_key(mut self, sk: Option<&[u8]>) -> Outcome<Self> {
215 match &mut self {
216 Self::AES_256_GCM(keys) => keys.sks = match sk {
217 Some(sk) => Some(Secret::new(
218 res!(<[u8; Self::AES_256_GCM_SK_LEN]>::try_from(&sk[..]))
219 )),
220 None => None,
221 },
222 }
223 Ok(self)
224 }
225}
226
227impl str::FromStr for EncryptionScheme {
228 type Err = Error<ErrTag>;
229
230 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
231 match name {
232 "AES-256-GCM" => Ok(Self::new_aes_256_gcm()),
233 _ => Err(err!(
234 "The encryption scheme '{}' is not recognised.", name;
235 Invalid, Input)),
236 }
237 }
238}
239
240impl TryFrom<&LocalId> for EncryptionScheme {
241 type Error = Error<ErrTag>;
242
243 fn try_from(n: &LocalId) -> std::result::Result<Self, Self::Error> {
244 match *n {
245 LocalId(1) => Ok(Self::new_aes_256_gcm()),
246 _ => Err(err!(
247 "The encryption scheme with local id {} is not recognised.", n;
248 Invalid, Input)),
249 }
250 }
251}
252
253impl TryFrom<(&LocalId, &[u8])> for EncryptionScheme {
254 type Error = Error<ErrTag>;
255
256 fn try_from((n, sk): (&LocalId, &[u8])) -> std::result::Result<Self, Self::Error> {
257 match *n {
258 LocalId(1) => {
259 let result = res!(Self::new_aes_256_gcm_with_key(sk));
260 Ok(result)
261 },
262 _ => Err(err!(
263 "The encryption scheme with local id {} is not recognised.", n;
264 Invalid, Input)),
265 }
266 }
267}
268
269impl EncryptionScheme {
270
271 pub const AES_256_GCM_NONCE_BYTES: usize = 12;
272 pub const AES_256_GCM_SK_LEN: usize = 32;
273
274 pub fn new_aes_256_gcm() -> Self {
275 Self::AES_256_GCM(Keys::randef_sk_only())
276 }
277
278 pub fn new_aes_256_gcm_with_key(sk: &[u8]) -> Outcome<Self> {
279 let sks = Some(Secret::new(res!(<[u8; Self::AES_256_GCM_SK_LEN]>::try_from(&sk[..]))));
280 Ok(Self::AES_256_GCM(Keys::new(None, sks)))
281 }
282
283 /// The increase in the length of the encrypted data due to inclusion of essential metadata
284 /// (e.g. in the case of AES-GCM, the nonce).
285 pub fn len_inc(&self) -> usize {
286 match self {
287 Self::AES_256_GCM(_) => Self::AES_256_GCM_NONCE_BYTES,
288 }
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 #[test]
297 fn test_enc_scheme_aes_gcm_00() -> Outcome<()> {
298 let aes = EncryptionScheme::new_aes_256_gcm();
299 for len in (1..100_000usize).step_by(1_000) {
300 let mut plain = vec![0u8; len];
301 OsRng.fill_bytes(&mut plain);
302 let encrypted = res!(aes.encrypt(&plain));
303 let result = res!(aes.decrypt(&encrypted));
304 assert_eq!(result, plain, "Length of plain data = {}", len);
305 }
306 Ok(())
307 }
308}