use ciborium::de::from_reader;
use serde_tuple::Deserialize_tuple;
use std::collections::HashMap;
use std::io::Cursor;
pub type AEADType = u8;
const AEAD_MAJOR_TYPE: AEADType = 7;
const AES_GCM_256: AEADType = 2;
#[derive(Debug, Deserialize_tuple)]
pub struct AEADCiphertext {
pub algorithm: AEADTypedObject,
pub ciphertext: Vec<u8>,
}
#[derive(Debug, Deserialize_tuple)]
pub struct AEADTypedObject {
pub major_type: u8,
pub minor_type: u8,
pub placeholder: HashMap<String, ciborium::Value>,
}
pub fn deserialize_ciphertext(cbor: &Vec<u8>) -> Result<AEADCiphertext, String> {
let cursor = Cursor::new(cbor);
let ciphertext: AEADCiphertext =
from_reader(cursor).map_err(|e| format!("failed to deserialize: {}", e))?;
if ciphertext.algorithm.major_type != AEAD_MAJOR_TYPE {
return Err(format!(
"invalid major type, expected {}, got {}",
AEAD_MAJOR_TYPE, ciphertext.algorithm.major_type
));
}
if ciphertext.algorithm.minor_type != AES_GCM_256 {
return Err(format!(
"invalid algorithm, expected {}, got {}",
AES_GCM_256, ciphertext.algorithm.minor_type
));
}
Ok(ciphertext)
}
#[cfg(test)]
mod tests {
use super::*;
use ciborium::ser::into_writer;
use ciborium::value::Value;
use serde_tuple::Serialize_tuple;
#[derive(Serialize_tuple)]
struct TestAEADTag {
major_type: u8,
minor_type: u8,
placeholder: HashMap<String, Value>,
}
#[derive(Serialize_tuple)]
struct TestAEADCiphertext {
tag: TestAEADTag,
ciphertext: Vec<u8>,
}
#[test]
fn test_deserialize_ciphertext() {
let test_tag = TestAEADTag {
major_type: 7,
minor_type: 2,
placeholder: HashMap::new(),
};
let test_ciphertext = TestAEADCiphertext {
tag: test_tag,
ciphertext: vec![1, 2, 3, 4],
};
let mut buffer = Vec::new();
into_writer(&test_ciphertext, &mut buffer).unwrap();
match deserialize_ciphertext(&buffer) {
Ok(aead_ciphertext) => {
assert_eq!(aead_ciphertext.algorithm.major_type, 7);
assert_eq!(aead_ciphertext.algorithm.minor_type, 2);
assert_eq!(aead_ciphertext.ciphertext, vec![1, 2, 3, 4]);
}
Err(e) => panic!("Failed to deserialize: {:?}", e),
}
}
#[test]
fn test_deserialize_ciphertext_invalid_major() {
let test_tag = TestAEADTag {
major_type: 99,
minor_type: 2,
placeholder: HashMap::new(),
};
let test_ciphertext = TestAEADCiphertext {
tag: test_tag,
ciphertext: vec![1, 2, 3, 4],
};
let mut buffer = Vec::new();
into_writer(&test_ciphertext, &mut buffer).unwrap();
match deserialize_ciphertext(&buffer) {
Ok(_) => {
panic!("Expected deserialize to fail")
}
Err(e) => assert_eq!(e, "invalid major type, expected 7, got 99".to_string()),
}
}
#[test]
fn test_deserialize_ciphertext_invalid_minor() {
let test_tag = TestAEADTag {
major_type: 7,
minor_type: 9,
placeholder: HashMap::new(),
};
let test_ciphertext = TestAEADCiphertext {
tag: test_tag,
ciphertext: vec![1, 2, 3, 4],
};
let mut buffer = Vec::new();
into_writer(&test_ciphertext, &mut buffer).unwrap();
match deserialize_ciphertext(&buffer) {
Ok(_) => {
panic!("Expected deserialize to fail")
}
Err(e) => assert_eq!(e, "invalid algorithm, expected 2, got 9".to_string()),
}
}
}