use crate::error::{Error, Result};
fn check_default(registry_has: bool, kind: &'static str, identifier: &str) -> Result<()> {
if registry_has {
Ok(())
} else {
Err(Error::UnknownIdentifier {
kind,
identifier: identifier.to_string(),
})
}
}
macro_rules! manager_facade {
(
$(#[$struct_doc:meta])*
$name:ident, $capability:path, $kind:literal,
$(
$(#[$method_doc:meta])*
$method:ident with $with:ident ( $($arg:ident: $ty:ty),* $(,)? )
-> $ret:ty
),* $(,)?
) => {
$(#[$struct_doc])*
#[derive(Debug)]
pub struct $name {
registry: $crate::registry::Registry<Box<dyn $capability>>,
default_identifier: String,
}
impl $name {
pub fn new(
registry: $crate::registry::Registry<Box<dyn $capability>>,
default_identifier: impl Into<String>,
) -> $crate::error::Result<Self> {
let default_identifier = default_identifier.into();
$crate::manager::check_default(
registry.has(&default_identifier),
$kind,
&default_identifier,
)?;
Ok(Self {
registry,
default_identifier,
})
}
$(
$(#[$method_doc])*
pub fn $method(&self, $($arg: $ty),*) -> $ret {
self.$with(&self.default_identifier $(, $arg)*)
}
pub fn $with(&self, identifier: &str $(, $arg: $ty)*) -> $ret {
self.registry.get(identifier)?.$method($($arg),*)
}
)*
pub fn registry(&self) -> &$crate::registry::Registry<Box<dyn $capability>> {
&self.registry
}
pub fn registry_mut(
&mut self,
) -> &mut $crate::registry::Registry<Box<dyn $capability>> {
&mut self.registry
}
pub fn default_identifier(&self) -> &str {
&self.default_identifier
}
pub fn set_default_identifier(
&mut self,
identifier: impl Into<String>,
) -> $crate::error::Result<()> {
let identifier = identifier.into();
$crate::manager::check_default(
self.registry.has(&identifier),
$kind,
&identifier,
)?;
self.default_identifier = identifier;
Ok(())
}
}
};
}
mod asymmetric;
pub use asymmetric::{KeyAgreementManager, SignatureManager};
manager_facade! {
EncryptionManager, crate::contract::SymmetricCipher, "symmetric cipher",
encrypt with encrypt_with(plaintext: &[u8])
-> crate::error::Result<Vec<u8>>,
decrypt with decrypt_with(ciphertext: &[u8])
-> crate::error::Result<Vec<u8>>,
}
manager_facade! {
AsymmetricCryptoManager, crate::contract::AsymmetricCipher, "asymmetric cipher",
encrypt with encrypt_with(plaintext: &[u8], public_key_hex: &str)
-> crate::error::Result<String>,
decrypt with decrypt_with(ciphertext_hex: &str, private_key_hex: &str)
-> crate::error::Result<Vec<u8>>,
}
manager_facade! {
HashingManager, crate::contract::Hasher, "hasher",
digest with digest_with(data: &[u8])
-> crate::error::Result<Vec<u8>>,
digest_hex with digest_hex_with(data: &[u8])
-> crate::error::Result<String>,
}
manager_facade! {
KeyDerivationManager, crate::contract::KeyDerivation, "key derivation",
derive with derive_with(ikm: &[u8], salt: &[u8], length: usize, info: &[u8])
-> crate::error::Result<Vec<u8>>,
}
manager_facade! {
PasswordBasedKdfManager, crate::contract::PasswordBasedKdf, "password-based kdf",
derive_from_password with derive_from_password_with(
password: &[u8], salt: &[u8], length: usize
) -> crate::error::Result<Vec<u8>>,
}
manager_facade! {
KeyEncapsulationManager, crate::contract::KeyEncapsulation, "key encapsulation",
generate with generate_with()
-> crate::error::Result<(String, String)>,
encapsulate with encapsulate_with(public_key_hex: &str)
-> crate::error::Result<(String, String)>,
decapsulate with decapsulate_with(ciphertext_hex: &str, private_key_hex: &str)
-> crate::error::Result<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::contract::{
AsymmetricCipher, Hasher, KeyAgreement, KeyDerivation, KeyEncapsulation, PasswordBasedKdf,
Signer, SymmetricCipher,
};
use crate::registry::Registry;
#[test]
fn unknown_default_kind_is_pinned_for_every_facade() {
fn unknown(kind: &'static str) -> Error {
Error::UnknownIdentifier {
kind,
identifier: "missing".to_string(),
}
}
assert_eq!(
EncryptionManager::new(
Registry::<Box<dyn SymmetricCipher>>::new("unused"),
"missing"
)
.unwrap_err(),
unknown("symmetric cipher")
);
assert_eq!(
AsymmetricCryptoManager::new(
Registry::<Box<dyn AsymmetricCipher>>::new("unused"),
"missing"
)
.unwrap_err(),
unknown("asymmetric cipher")
);
assert_eq!(
HashingManager::new(Registry::<Box<dyn Hasher>>::new("unused"), "missing").unwrap_err(),
unknown("hasher")
);
assert_eq!(
KeyDerivationManager::new(Registry::<Box<dyn KeyDerivation>>::new("unused"), "missing")
.unwrap_err(),
unknown("key derivation")
);
assert_eq!(
PasswordBasedKdfManager::new(
Registry::<Box<dyn PasswordBasedKdf>>::new("unused"),
"missing"
)
.unwrap_err(),
unknown("password-based kdf")
);
assert_eq!(
KeyEncapsulationManager::new(
Registry::<Box<dyn KeyEncapsulation>>::new("unused"),
"missing"
)
.unwrap_err(),
unknown("key encapsulation")
);
assert_eq!(
SignatureManager::new(Registry::<Box<dyn Signer>>::new("unused"), "missing")
.unwrap_err(),
unknown("signer")
);
assert_eq!(
KeyAgreementManager::new(Registry::<Box<dyn KeyAgreement>>::new("unused"), "missing")
.unwrap_err(),
unknown("key agreement")
);
}
}