antimatter 2.0.13

antimatter.io Rust library for data control
Documentation
use ciborium::de::from_reader;
use serde_tuple::Deserialize_tuple;
use std::collections::HashMap;
use std::io::Cursor;

// Note: types presented here are copied out of the Go implementation
pub type AEADType = u8;
const AEAD_MAJOR_TYPE: AEADType = 7;
// For this version we only expect AESGCM256, in future we can add other types
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 {
    // major_type identifies a scheme of objects that all have the same purpose
    // and rough functionality
    pub major_type: u8,
    // minor_type identifies a specific algorithm or object within a major type
    pub minor_type: u8,
    pub placeholder: HashMap<String, ciborium::Value>,
}

/// Deserializes a CBOR byte slice into an `AEADCiphertext` object.
///
/// # Arguments
///
/// * `cbor` - A slice of bytes (`&Vec<u8>`) representing the CBOR-encoded data.
///
/// # Returns
///
/// `AEADCiphertext` object if deserialization is successful, otherwise a
/// SessionError
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() {
        // Prepare a test AEADCiphertext object and serialize it to CBOR
        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();

        // Deserialize and test
        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() {
        // Prepare a test AEADCiphertext object and serialize it to CBOR
        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();

        // Deserialize and test
        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() {
        // Prepare a test AEADCiphertext object and serialize it to CBOR
        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();

        // Deserialize and test
        match deserialize_ciphertext(&buffer) {
            Ok(_) => {
                panic!("Expected  deserialize to fail")
            }
            Err(e) => assert_eq!(e, "invalid algorithm, expected 2, got 9".to_string()),
        }
    }
}