use chacha20poly1305::{
ChaCha20Poly1305, Nonce,
aead::{Aead, KeyInit},
};
use hkdf::Hkdf;
use nostr::secp256k1::rand::{RngCore, rngs::OsRng};
use sha2::Sha256;
use mdk_storage_traits::{MdkStorageProvider, Secret};
use crate::encrypted_media::types::EncryptedMediaError;
use crate::{GroupId, MDK};
pub const DEFAULT_SCHEME_VERSION: &str = "mip04-v2";
pub fn is_scheme_version_supported(version: &str) -> bool {
match version {
"mip04-v2" => true,
_ => false,
}
}
fn get_scheme_label(version: &str) -> Result<&[u8], EncryptedMediaError> {
match version {
"mip04-v2" => Ok(b"mip04-v2"),
_ => Err(EncryptedMediaError::UnknownSchemeVersion(
version.to_string(),
)),
}
}
fn build_hkdf_context(
scheme_label: &[u8],
file_hash: &[u8; 32],
mime_type: &str,
filename: &str,
suffix: &[u8],
) -> Vec<u8> {
let mut context = Vec::new();
context.extend_from_slice(scheme_label);
context.push(0x00);
context.extend_from_slice(file_hash);
context.push(0x00);
context.extend_from_slice(mime_type.as_bytes());
context.push(0x00);
context.extend_from_slice(filename.as_bytes());
context.push(0x00);
context.extend_from_slice(suffix);
context
}
fn build_aad(
scheme_label: &[u8],
file_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Vec<u8> {
let mut aad = Vec::new();
aad.extend_from_slice(scheme_label);
aad.push(0x00);
aad.extend_from_slice(file_hash);
aad.push(0x00);
aad.extend_from_slice(mime_type.as_bytes());
aad.push(0x00);
aad.extend_from_slice(filename.as_bytes());
aad
}
pub fn derive_encryption_key<Storage>(
mdk: &MDK<Storage>,
group_id: &GroupId,
scheme_version: &str,
original_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Result<Secret<[u8; 32]>, EncryptedMediaError>
where
Storage: MdkStorageProvider,
{
let exporter_secret = mdk
.mip04_exporter_secret(group_id)
.map_err(|_| EncryptedMediaError::GroupNotFound)?;
derive_encryption_key_with_secret(
&exporter_secret.secret,
scheme_version,
original_hash,
mime_type,
filename,
)
}
pub(crate) fn derive_encryption_key_with_secret(
exporter_secret: &Secret<[u8; 32]>,
scheme_version: &str,
original_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Result<Secret<[u8; 32]>, EncryptedMediaError> {
let scheme_label = get_scheme_label(scheme_version)?;
let context = build_hkdf_context(scheme_label, original_hash, mime_type, filename, b"key");
let hk = Hkdf::<Sha256>::from_prk(exporter_secret.as_ref()).map_err(|e| {
EncryptedMediaError::EncryptionFailed {
reason: format!("Invalid HKDF PRK: {}", e),
}
})?;
let mut key = [0u8; 32];
hk.expand(&context, &mut key)
.map_err(|e| EncryptedMediaError::EncryptionFailed {
reason: format!("Key derivation failed: {}", e),
})?;
Ok(Secret::new(key))
}
pub(crate) fn derive_legacy_encryption_key_with_secret(
exporter_secret: &Secret<[u8; 32]>,
scheme_version: &str,
original_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Result<Secret<[u8; 32]>, EncryptedMediaError> {
let scheme_label = get_scheme_label(scheme_version)?;
let context = build_hkdf_context(scheme_label, original_hash, mime_type, filename, b"key");
let hk = Hkdf::<Sha256>::new(None, exporter_secret.as_ref());
let mut key = [0u8; 32];
hk.expand(&context, &mut key)
.map_err(|e| EncryptedMediaError::EncryptionFailed {
reason: format!("Key derivation failed: {}", e),
})?;
Ok(Secret::new(key))
}
pub fn generate_encryption_nonce() -> Secret<[u8; 12]> {
let mut nonce = [0u8; 12];
let mut rng = OsRng;
rng.fill_bytes(&mut nonce);
Secret::new(nonce)
}
pub fn encrypt_data_with_aad(
data: &[u8],
key: &Secret<[u8; 32]>,
nonce: &Secret<[u8; 12]>,
scheme_version: &str,
file_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Result<Vec<u8>, EncryptedMediaError> {
let cipher = ChaCha20Poly1305::new_from_slice(key.as_ref()).map_err(|e| {
EncryptedMediaError::EncryptionFailed {
reason: format!("Failed to create cipher: {}", e),
}
})?;
let nonce_arr = Nonce::from_slice(nonce.as_ref());
let scheme_label = get_scheme_label(scheme_version)?;
let aad = build_aad(scheme_label, file_hash, mime_type, filename);
cipher
.encrypt(
nonce_arr,
chacha20poly1305::aead::Payload {
msg: data,
aad: &aad,
},
)
.map_err(|e| EncryptedMediaError::EncryptionFailed {
reason: format!("Encryption failed: {}", e),
})
}
pub fn decrypt_data_with_aad(
encrypted_data: &[u8],
key: &Secret<[u8; 32]>,
nonce: &Secret<[u8; 12]>,
scheme_version: &str,
file_hash: &[u8; 32],
mime_type: &str,
filename: &str,
) -> Result<Vec<u8>, EncryptedMediaError> {
let cipher = ChaCha20Poly1305::new_from_slice(key.as_ref()).map_err(|e| {
EncryptedMediaError::DecryptionFailed {
reason: format!("Failed to create cipher: {}", e),
}
})?;
let nonce_arr = Nonce::from_slice(nonce.as_ref());
let scheme_label = get_scheme_label(scheme_version)?;
let aad = build_aad(scheme_label, file_hash, mime_type, filename);
cipher
.decrypt(
nonce_arr,
chacha20poly1305::aead::Payload {
msg: encrypted_data,
aad: &aad,
},
)
.map_err(|e| EncryptedMediaError::DecryptionFailed {
reason: format!("Decryption failed: {}", e),
})
}
#[cfg(test)]
mod tests {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use sha2::Digest;
use mdk_memory_storage::MdkMemoryStorage;
use super::*;
fn create_test_mdk() -> MDK<MdkMemoryStorage> {
MDK::new(MdkMemoryStorage::default())
}
#[test]
fn test_errors_without_group() {
let mdk = create_test_mdk();
let group_id = GroupId::from_slice(&[1, 2, 3, 4]);
let original_data =
b"This is test image data that should be encrypted and decrypted properly";
let mime_type = "image/jpeg";
let filename = "test.jpg";
let original_hash: [u8; 32] = Sha256::digest(original_data).into();
let key_result = derive_encryption_key(
&mdk,
&group_id,
DEFAULT_SCHEME_VERSION,
&original_hash,
mime_type,
filename,
);
assert!(key_result.is_err());
if let Err(EncryptedMediaError::GroupNotFound) = key_result {
} else {
panic!("Expected GroupNotFound error for key derivation");
}
}
#[test]
fn test_encrypt_decrypt_with_known_key() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let original_data = b"Hello, encrypted world!";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let encrypted_result = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(encrypted_result.is_ok());
let encrypted_data = encrypted_result.unwrap();
assert_ne!(encrypted_data.as_slice(), original_data);
assert!(encrypted_data.len() > original_data.len());
let decrypted_result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(decrypted_result.is_ok());
let decrypted_data = decrypted_result.unwrap();
assert_eq!(decrypted_data.as_slice(), original_data);
}
#[test]
fn test_mip04_file_key_uses_hkdf_expand_with_exporter_secret_as_prk() {
let exporter_secret = Secret::new([0x11u8; 32]);
let file_hash = [0x22u8; 32];
let mime_type = "image/jpeg";
let filename = "photo.jpg";
let derived = derive_encryption_key_with_secret(
&exporter_secret,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.expect("MIP-04 key derivation should succeed");
let scheme_label = get_scheme_label(DEFAULT_SCHEME_VERSION).unwrap();
let context = build_hkdf_context(scheme_label, &file_hash, mime_type, filename, b"key");
let hk_expand_only = Hkdf::<Sha256>::from_prk(exporter_secret.as_ref())
.expect("32-byte exporter secret must be a valid HKDF PRK");
let mut expected = [0u8; 32];
hk_expand_only
.expand(&context, &mut expected)
.expect("HKDF expand-only should succeed");
let hk_extract_then_expand = Hkdf::<Sha256>::new(None, exporter_secret.as_ref());
let mut old_style = [0u8; 32];
hk_extract_then_expand
.expand(&context, &mut old_style)
.expect("HKDF extract+expand should succeed");
assert_eq!(*derived, expected);
assert_ne!(expected, old_style);
}
#[test]
fn test_encrypt_decrypt_with_different_aad() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let original_data = b"Hello, encrypted world!";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let encrypted_data = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let different_hash = [0x02u8; 32];
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&different_hash,
mime_type,
filename,
);
assert!(result.is_err());
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/png",
filename,
);
assert!(result.is_err());
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
"different.jpg",
);
assert!(result.is_err());
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(result.is_ok());
assert_eq!(result.unwrap().as_slice(), original_data);
}
#[test]
fn test_encrypt_decrypt_with_wrong_key() {
let key = Secret::new([0x42u8; 32]);
let wrong_key = Secret::new([0x43u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let original_data = b"Hello, encrypted world!";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let encrypted_data = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let result = decrypt_data_with_aad(
&encrypted_data,
&wrong_key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(result.is_err());
assert!(matches!(
result,
Err(EncryptedMediaError::DecryptionFailed { .. })
));
}
#[test]
fn test_encrypt_decrypt_with_wrong_nonce() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let wrong_nonce = Secret::new([0x25u8; 12]);
let original_data = b"Hello, encrypted world!";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let encrypted_data = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&wrong_nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(result.is_err());
assert!(matches!(
result,
Err(EncryptedMediaError::DecryptionFailed { .. })
));
}
#[test]
fn test_encrypt_empty_data() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let empty_data = b"";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "empty.jpg";
let encrypted_result = encrypt_data_with_aad(
empty_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(encrypted_result.is_ok());
let encrypted_data = encrypted_result.unwrap();
assert!(!encrypted_data.is_empty());
let decrypted_result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(decrypted_result.is_ok());
assert_eq!(decrypted_result.unwrap().as_slice(), empty_data);
}
#[test]
fn test_aad_construction() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let data = b"test data";
let file_hash = [0x01u8; 32];
let encrypted1 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"photo.jpg",
)
.unwrap();
let encrypted2 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/png",
"photo.jpg",
)
.unwrap();
let encrypted3 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"image.jpg",
)
.unwrap();
assert_ne!(encrypted1, encrypted2);
assert_ne!(encrypted1, encrypted3);
assert_ne!(encrypted2, encrypted3);
}
#[test]
fn test_secret_accessors() {
let original_key = [0xAAu8; 32];
let secret_key = Secret::new(original_key);
assert_eq!(secret_key.as_ref(), &original_key);
assert_eq!(*secret_key, original_key);
let cloned = secret_key.clone();
assert_eq!(*cloned, original_key);
assert_eq!(*secret_key, original_key);
let mut mut_secret = Secret::new([0xBBu8; 32]);
*mut_secret.as_mut() = [0xCCu8; 32];
assert_eq!(*mut_secret, [0xCCu8; 32]);
}
#[test]
fn test_secret_debug_format() {
let secret_key = Secret::new([0xAAu8; 32]);
let debug_str = format!("{:?}", secret_key);
assert_eq!(debug_str, "Secret(***)");
assert!(!debug_str.contains("AA"));
}
#[test]
fn test_decrypt_corrupted_data() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let original_data = b"Hello, encrypted world!";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let mut encrypted_data = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
encrypted_data[0] ^= 0xFF;
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(result.is_err());
assert!(matches!(
result,
Err(EncryptedMediaError::DecryptionFailed { .. })
));
}
#[test]
fn test_scheme_version_mismatch_causes_decryption_failure() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let original_data = b"Test data for version mismatch";
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let encrypted_data = encrypt_data_with_aad(
original_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
"mip04-v1", &file_hash,
mime_type,
filename,
);
assert!(result.is_err());
match result {
Err(EncryptedMediaError::UnknownSchemeVersion(v)) => assert_eq!(v, "mip04-v1"),
Err(e) => panic!("Expected UnknownSchemeVersion, got {:?}", e),
Ok(_) => panic!("Should have failed"),
}
}
#[test]
fn test_decrypt_too_short_data() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let too_short = vec![0u8; 5];
let result = decrypt_data_with_aad(
&too_short,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(result.is_err());
assert!(matches!(
result,
Err(EncryptedMediaError::DecryptionFailed { .. })
));
}
#[test]
fn test_encrypt_large_data() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let large_data = vec![0xABu8; 1024 * 1024]; let file_hash = [0x01u8; 32];
let mime_type = "application/octet-stream";
let filename = "large.bin";
let encrypted_result = encrypt_data_with_aad(
&large_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(encrypted_result.is_ok());
let encrypted_data = encrypted_result.unwrap();
assert!(encrypted_data.len() > large_data.len());
let decrypted_result = decrypt_data_with_aad(
&encrypted_data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
);
assert!(decrypted_result.is_ok());
assert_eq!(decrypted_result.unwrap(), large_data);
}
#[test]
fn test_encrypt_special_characters() {
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let data = b"test data";
let file_hash = [0x01u8; 32];
let encrypted1 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"test file (1).jpg",
)
.unwrap();
let encrypted2 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"тест.jpg",
)
.unwrap();
let encrypted3 = encrypt_data_with_aad(
data,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"document.docx",
)
.unwrap();
assert!(!encrypted1.is_empty());
assert!(!encrypted2.is_empty());
assert!(!encrypted3.is_empty());
let decrypted1 = decrypt_data_with_aad(
&encrypted1,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"test file (1).jpg",
)
.unwrap();
assert_eq!(decrypted1, data);
let decrypted2 = decrypt_data_with_aad(
&encrypted2,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"тест.jpg",
)
.unwrap();
assert_eq!(decrypted2, data);
}
#[test]
fn test_multiple_encryption_cycles() {
let key = Secret::new([0x42u8; 32]);
let file_hash = [0x01u8; 32];
let mime_type = "image/jpeg";
let filename = "test.jpg";
let data1 = b"First encryption";
let data2 = b"Second encryption";
let data3 = b"Third encryption";
let nonce1 = generate_encryption_nonce();
let nonce2 = generate_encryption_nonce();
let nonce3 = generate_encryption_nonce();
let enc1 = encrypt_data_with_aad(
data1,
&key,
&nonce1,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let enc2 = encrypt_data_with_aad(
data2,
&key,
&nonce2,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let enc3 = encrypt_data_with_aad(
data3,
&key,
&nonce3,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let dec1 = decrypt_data_with_aad(
&enc1,
&key,
&nonce1,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let dec2 = decrypt_data_with_aad(
&enc2,
&key,
&nonce2,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
let dec3 = decrypt_data_with_aad(
&enc3,
&key,
&nonce3,
DEFAULT_SCHEME_VERSION,
&file_hash,
mime_type,
filename,
)
.unwrap();
assert_eq!(dec1, data1);
assert_eq!(dec2, data2);
assert_eq!(dec3, data3);
}
#[test]
fn test_error_messages() {
let mdk = create_test_mdk();
let group_id = GroupId::from_slice(&[1, 2, 3, 4]);
let file_hash = [0x01u8; 32];
let key_result = derive_encryption_key(
&mdk,
&group_id,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"test.jpg",
);
assert!(matches!(
key_result,
Err(EncryptedMediaError::GroupNotFound)
));
let key = Secret::new([0x42u8; 32]);
let nonce = Secret::new([0x24u8; 12]);
let corrupted = vec![0u8; 10];
let result = decrypt_data_with_aad(
&corrupted,
&key,
&nonce,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"test.jpg",
);
match result {
Err(EncryptedMediaError::DecryptionFailed { reason }) => {
assert!(!reason.is_empty());
assert!(reason.contains("Decryption failed"));
}
other => panic!("Expected DecryptionFailed, got {:?}", other),
}
}
#[test]
fn test_secret_access_methods() {
let mut secret_key = Secret::new([0xAAu8; 32]);
let original = [0xAAu8; 32];
assert_eq!(secret_key.as_ref(), &original);
assert_eq!(*secret_key, original);
*secret_key.as_mut() = [0xBBu8; 32];
assert_eq!(*secret_key, [0xBBu8; 32]);
*secret_key = [0xCCu8; 32];
assert_eq!(*secret_key, [0xCCu8; 32]);
}
#[test]
fn test_secret_equality() {
let secret1 = Secret::new([0xAAu8; 32]);
let secret2 = Secret::new([0xAAu8; 32]);
let secret3 = Secret::new([0xBBu8; 32]);
assert_eq!(secret1, secret2);
assert_ne!(secret1, secret3);
let mut hasher1 = DefaultHasher::new();
secret1.hash(&mut hasher1);
let hash1 = hasher1.finish();
let mut hasher2 = DefaultHasher::new();
secret2.hash(&mut hasher2);
let hash2 = hasher2.finish();
assert_eq!(hash1, hash2);
}
#[test]
fn test_key_derivation_error() {
let mdk = create_test_mdk();
let group_id = GroupId::from_slice(&[1, 2, 3, 4]);
let file_hash = [0x01u8; 32];
let result = derive_encryption_key(
&mdk,
&group_id,
DEFAULT_SCHEME_VERSION,
&file_hash,
"image/jpeg",
"test.jpg",
);
assert!(result.is_err());
assert!(matches!(result, Err(EncryptedMediaError::GroupNotFound)));
}
#[test]
fn test_secret_ordering() {
let secret1 = Secret::new([0xAAu8; 32]);
let secret2 = Secret::new([0xBBu8; 32]);
let secret3 = Secret::new([0xAAu8; 32]);
assert!(secret1 < secret2);
assert!(secret2 > secret1);
assert!(secret1 <= secret3);
assert!(secret1 >= secret3);
}
#[test]
fn test_unknown_scheme_version() {
let result = get_scheme_label("unknown-version");
assert!(result.is_err());
match result {
Err(EncryptedMediaError::UnknownSchemeVersion(v)) => assert_eq!(v, "unknown-version"),
_ => panic!("Expected UnknownSchemeVersion error"),
}
}
}