1use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
3use serde_bytes::ByteBuf;
4use serde_cbor::Error as CborError;
5use serde_cbor::Value as CborValue;
6
7use crate::crypto::{Decryption, Encryption, Entropy};
8use crate::error::CoseError;
9use crate::header_map::{map_to_empty_or_serialized, HeaderMap};
10
11const KTY: i8 = 1;
12const IV: i8 = 5;
13
14pub enum CipherConfiguration {
16 Gcm,
18}
19
20impl CipherConfiguration {
21 fn cose_alg(&self, key: &[u8]) -> Option<CoseAlgorithm> {
22 Some(match self {
23 CipherConfiguration::Gcm => match key.len() {
24 16 => CoseAlgorithm::AesGcm96_128_128,
25 24 => CoseAlgorithm::AesGcm96_128_192,
26 32 => CoseAlgorithm::AesGcm96_128_256,
27 _ => return None,
28 },
29 })
30 }
31}
32
33pub(crate) enum CoseAlgorithm {
34 AesGcm96_128_128,
36 AesGcm96_128_192,
38 AesGcm96_128_256,
40}
41
42impl CoseAlgorithm {
43 fn value(&self) -> usize {
44 match self {
45 CoseAlgorithm::AesGcm96_128_128 => 1,
46 CoseAlgorithm::AesGcm96_128_192 => 2,
47 CoseAlgorithm::AesGcm96_128_256 => 3,
48 }
49 }
50
51 fn from_value(value: i8) -> Option<CoseAlgorithm> {
52 Some(match value {
53 1 => CoseAlgorithm::AesGcm96_128_128,
54 2 => CoseAlgorithm::AesGcm96_128_192,
55 3 => CoseAlgorithm::AesGcm96_128_256,
56 _ => return None,
57 })
58 }
59
60 fn tag_size(&self) -> usize {
62 match self {
63 CoseAlgorithm::AesGcm96_128_128 => 16,
64 CoseAlgorithm::AesGcm96_128_192 => 16,
65 CoseAlgorithm::AesGcm96_128_256 => 16,
66 }
67 }
68
69 fn iv_len(&self) -> Option<usize> {
70 match self {
71 CoseAlgorithm::AesGcm96_128_128 => Some(12),
72 CoseAlgorithm::AesGcm96_128_192 => Some(12),
73 CoseAlgorithm::AesGcm96_128_256 => Some(12),
74 }
75 }
76}
77
78#[derive(Debug, Clone, Deserialize)]
123struct EncStructure {
124 context: String,
126 protected: ByteBuf,
128 external_aad: ByteBuf,
130}
131
132impl Serialize for EncStructure {
133 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
134 where
135 S: Serializer,
136 {
137 let mut seq = serializer.serialize_seq(Some(3))?;
138 seq.serialize_element(&self.context)?;
139 seq.serialize_element(&self.protected)?;
140 seq.serialize_element(&self.external_aad)?;
141 seq.end()
142 }
143}
144
145impl EncStructure {
146 fn new_encrypt0(protected: &[u8]) -> Result<Self, CborError> {
147 Ok(EncStructure {
148 context: String::from("Encrypt0"),
149 protected: ByteBuf::from(protected.to_vec()),
150 external_aad: ByteBuf::new(),
151 })
152 }
153
154 fn as_bytes(&self) -> Result<Vec<u8>, CborError> {
157 serde_cbor::to_vec(self)
158 }
159}
160
161#[derive(Debug, Clone, Deserialize)]
195pub struct CoseEncrypt0 {
196 protected: ByteBuf,
198 unprotected: HeaderMap,
200 ciphertext: ByteBuf,
204}
205
206impl Serialize for CoseEncrypt0 {
207 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
208 where
209 S: Serializer,
210 {
211 let mut seq = serializer.serialize_seq(Some(3))?;
212 seq.serialize_element(&self.protected)?;
213 seq.serialize_element(&self.unprotected)?;
214 seq.serialize_element(&self.ciphertext)?;
215 seq.end()
216 }
217}
218
219impl CoseEncrypt0 {
220 pub fn new<C: Encryption + Entropy>(
223 payload: &[u8],
224 cipher_config: CipherConfiguration,
225 key: &[u8],
226 ) -> Result<Self, CoseError> {
227 let cose_alg = match cipher_config.cose_alg(key) {
228 Some(v) => v,
229 None => {
230 return Err(CoseError::UnsupportedError(
231 "Unsupported encryption algorithm".to_string(),
232 ))
233 }
234 };
235 let mut iv = vec![0; cose_alg.iv_len().unwrap()];
236 C::rand_bytes(&mut iv)?;
237
238 let cose_alg_value = cose_alg.value();
239 let mut protected = HeaderMap::new();
240 protected.insert(KTY.into(), CborValue::Integer(cose_alg_value as i128));
241 let mut unprotected = HeaderMap::new();
242 unprotected.insert(IV.into(), CborValue::Bytes(iv.to_owned()));
243
244 let protected_bytes =
245 map_to_empty_or_serialized(&protected).map_err(CoseError::SerializationError)?;
246
247 let enc_structure =
248 EncStructure::new_encrypt0(&protected_bytes).map_err(CoseError::SerializationError)?;
249
250 let mut tag = vec![0; cose_alg.tag_size()];
251 let mut ciphertext = C::encrypt_aead(
252 cose_alg.into(),
253 key,
254 Some(&iv[..]),
255 &enc_structure
256 .as_bytes()
257 .map_err(CoseError::SerializationError)?,
258 payload,
259 &mut tag,
260 )
261 .map_err(|e| CoseError::EncryptionError(Box::new(e)))?;
262
263 ciphertext.append(&mut tag);
264
265 Ok(CoseEncrypt0 {
266 protected: ByteBuf::from(protected_bytes),
267 unprotected,
268 ciphertext: ByteBuf::from(ciphertext),
269 })
270 }
271
272 pub fn decrypt<C: Decryption>(
276 &self,
277 key: &[u8],
278 ) -> Result<(HeaderMap, &HeaderMap, Vec<u8>), CoseError> {
279 let protected: HeaderMap =
280 HeaderMap::from_bytes(&self.protected).map_err(CoseError::SerializationError)?;
281
282 let protected_enc_alg = match protected.get(&CborValue::Integer(1)) {
283 Some(CborValue::Integer(val)) => val,
284 _ => {
285 return Err(CoseError::SpecificationError(
286 "Protected Header contains invalid Encryption Algorithm specification"
287 .to_string(),
288 ))
289 }
290 };
291
292 let cose_alg = match CoseAlgorithm::from_value(*protected_enc_alg as i8) {
293 Some(v) => v,
294 None => {
295 return Err(CoseError::UnsupportedError(
296 "Unsupported encryption algorithm".to_string(),
297 ))
298 }
299 };
300
301 let protected_bytes =
302 map_to_empty_or_serialized(&protected).map_err(CoseError::SerializationError)?;
303
304 let enc_structure =
305 EncStructure::new_encrypt0(&protected_bytes).map_err(CoseError::SerializationError)?;
306
307 let iv = match self.unprotected.get(&CborValue::Integer(5)) {
308 Some(CborValue::Bytes(val)) => val,
309 _ => {
310 return Err(CoseError::SpecificationError(
311 "Unprotected Header contains invalid IV specification".to_string(),
312 ))
313 }
314 };
315
316 let (ciphertext, tag) = self
317 .ciphertext
318 .split_at(self.ciphertext.len() - cose_alg.tag_size());
319
320 let payload = C::decrypt_aead(
321 cose_alg.into(),
322 key,
323 Some(iv),
324 &enc_structure
325 .as_bytes()
326 .map_err(CoseError::SerializationError)?,
327 ciphertext,
328 tag,
329 )
330 .map_err(|e| CoseError::EncryptionError(Box::new(e)))?;
331
332 Ok((protected, &self.unprotected, payload))
333 }
334
335 pub fn as_bytes(&self, tagged: bool) -> Result<Vec<u8>, CoseError> {
338 let bytes = if tagged {
339 serde_cbor::to_vec(&serde_cbor::tags::Tagged::new(Some(16), &self))
340 } else {
341 serde_cbor::to_vec(&self)
342 };
343 bytes.map_err(CoseError::SerializationError)
344 }
345
346 pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoseError> {
349 let coseencrypt0: serde_cbor::tags::Tagged<Self> =
350 serde_cbor::from_slice(bytes).map_err(CoseError::SerializationError)?;
351
352 match coseencrypt0.tag {
353 None | Some(16) => (),
354 Some(tag) => return Err(CoseError::TagError(Some(tag))),
355 }
356 let protected = coseencrypt0.value.protected.as_slice();
357 let _: HeaderMap =
358 serde_cbor::from_slice(protected).map_err(CoseError::SerializationError)?;
359 Ok(coseencrypt0.value)
360 }
361}
362
363#[cfg(all(test, feature = "openssl"))]
364mod tests {
365 use super::*;
366 use crate::crypto::Openssl;
367
368 #[test]
369 fn test_encrypt_decrypt() {
370 let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
371 let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
372 let cencrypt0 =
373 CoseEncrypt0::new::<Openssl>(plaintext, CipherConfiguration::Gcm, key).unwrap();
374 let (_, _, dec) = cencrypt0.decrypt::<Openssl>(key).unwrap();
375 assert_eq!(dec, plaintext);
376 assert_ne!(
377 plaintext.to_vec(),
378 serde_cbor::to_vec(&cencrypt0.ciphertext).unwrap()
379 );
380 let fromb = CoseEncrypt0::from_bytes(&cencrypt0.as_bytes(true).unwrap()[..]).unwrap();
381 let (_, _, dec) = fromb.decrypt::<Openssl>(key).unwrap();
382 assert_eq!(dec, plaintext);
383 assert_ne!(
384 plaintext.to_vec(),
385 serde_cbor::to_vec(&fromb.ciphertext).unwrap()
386 );
387 }
388
389 #[test]
390 fn test_encrypt_unsupported_alg() {
391 let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x56\x56";
392 let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
393 let cencrypt0 = CoseEncrypt0::new::<Openssl>(plaintext, CipherConfiguration::Gcm, key);
394 match cencrypt0.unwrap_err() {
395 CoseError::UnsupportedError(_) => (),
396 _ => panic!(),
397 }
398 }
399
400 #[test]
401 fn test_decrypt_invalid_alg_spec() {
402 let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
403 let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
404 let mut cencrypt0 =
405 CoseEncrypt0::new::<Openssl>(plaintext, CipherConfiguration::Gcm, key).unwrap();
406 let mut protected = HeaderMap::new();
407 protected.insert(KTY.into(), CborValue::Text("invalid".to_string()));
408 let protected_bytes = map_to_empty_or_serialized(&protected)
409 .map_err(CoseError::SerializationError)
410 .unwrap();
411 cencrypt0.protected = ByteBuf::from(protected_bytes);
412 match cencrypt0.decrypt::<Openssl>(key).unwrap_err() {
413 CoseError::SpecificationError(_) => (),
414 _ => panic!(),
415 }
416 }
417
418 #[test]
419 fn test_decrypt_unsupported_openssl_cipher() {
420 let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
421 let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
422 let mut cencrypt0 =
423 CoseEncrypt0::new::<Openssl>(plaintext, CipherConfiguration::Gcm, key).unwrap();
424 let mut protected = HeaderMap::new();
425 protected.insert(KTY.into(), CborValue::Integer(42));
426 let protected_bytes = map_to_empty_or_serialized(&protected)
427 .map_err(CoseError::SerializationError)
428 .unwrap();
429 cencrypt0.protected = ByteBuf::from(protected_bytes);
430 match cencrypt0.decrypt::<Openssl>(key).unwrap_err() {
431 CoseError::UnsupportedError(_) => (),
432 _ => panic!(),
433 }
434 }
435
436 #[test]
437 fn test_decrypt_invalid_iv() {
438 let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
439 let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
440 let mut cencrypt0 =
441 CoseEncrypt0::new::<Openssl>(plaintext, CipherConfiguration::Gcm, key).unwrap();
442 let mut unprotected = HeaderMap::new();
443 unprotected.insert(IV.into(), CborValue::Integer(42));
444 cencrypt0.unprotected = unprotected;
445 match cencrypt0.decrypt::<Openssl>(key).unwrap_err() {
446 CoseError::SpecificationError(_) => (),
447 _ => panic!(),
448 }
449 }
450}