#[cfg(feature = "libolm-compat")]
use std::io::Cursor;
#[cfg(feature = "libolm-compat")]
use matrix_pickle::{Decode, Encode};
#[cfg(feature = "libolm-compat")]
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "libolm-compat")]
use super::{base64_decode, base64_encode};
#[cfg(feature = "libolm-compat")]
use crate::{LibolmPickleError, cipher::Cipher};
pub(crate) fn get_version(source: &[u8]) -> Option<u32> {
let version = source.get(0..4)?;
Some(u32::from_be_bytes(version.try_into().ok()?))
}
#[cfg(feature = "libolm-compat")]
pub(crate) fn unpickle_libolm<P: Decode, T: TryFrom<P, Error = LibolmPickleError>>(
pickle: &str,
pickle_key: &[u8],
pickle_version: u32,
) -> Result<T, LibolmPickleError> {
let decoded = base64_decode(pickle)?;
let cipher = Cipher::new_pickle(pickle_key);
let mut decrypted = cipher.decrypt_pickle(&decoded)?;
let version = get_version(&decrypted).ok_or(LibolmPickleError::MissingVersion)?;
if version == pickle_version {
let mut cursor = Cursor::new(&decrypted);
let pickle = P::decode(&mut cursor)?;
decrypted.zeroize();
pickle.try_into()
} else {
Err(LibolmPickleError::Version(pickle_version, version))
}
}
#[cfg(feature = "libolm-compat")]
pub(crate) fn pickle_libolm<P>(pickle: P, pickle_key: &[u8]) -> Result<String, LibolmPickleError>
where
P: Encode,
{
let mut encoded = pickle.encode_to_vec()?;
let cipher = Cipher::new_pickle(pickle_key);
let encrypted = cipher.encrypt_pickle(&encoded);
encoded.zeroize();
Ok(base64_encode(encrypted))
}
#[cfg(feature = "libolm-compat")]
#[derive(Encode, Decode, Zeroize, ZeroizeOnDrop)]
pub(crate) struct LibolmEd25519Keypair {
pub public_key: [u8; 32],
#[secret]
pub private_key: Box<[u8; 64]>,
}
#[cfg(all(feature = "libolm-compat", test))]
mod test {
use super::*;
#[test]
fn encode_cycle() {
let key_pair =
LibolmEd25519Keypair { public_key: [10u8; 32], private_key: [20u8; 64].into() };
let encoded = key_pair.encode_to_vec().unwrap();
let decoded = LibolmEd25519Keypair::decode_from_slice(&encoded).unwrap();
assert_eq!(key_pair.public_key, decoded.public_key);
assert_eq!(key_pair.private_key, decoded.private_key);
}
}