#[cfg(feature = "keyless")]
use crate::constants::HARDCODED_KEY_BYTES;
use crate::{error::Error, Encoding, Format, MasterKey, Scheme};
pub trait ObtextCodec {
fn enc(&self, plaintext: &str) -> Result<String, Error>;
fn dec(&self, obtext: &str) -> Result<String, Error>;
fn format(&self) -> Format;
fn scheme(&self) -> Scheme;
fn encoding(&self) -> Encoding;
}
macro_rules! impl_codec_32 {
(
$name: ident,
$scheme: expr,
$encoding:expr,
$format_str:expr,
$encrypt_fn:path,
$decrypt_fn: path,
$key_extract: ident
) => {
#[doc = concat!("ObtextCodec implementation for ", $format_str, " format.\n\n")]
#[doc = concat!("Corresponds to format string: `\"", $format_str, "\"`")]
#[allow(non_camel_case_types)]
pub struct $name {
masterkey: MasterKey,
}
impl $name {
#[inline]
pub fn new(key: &str) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_base64(key)?,
})
}
#[inline]
#[cfg(any(feature = "keyless", feature = "bytes-keys"))]
fn from_bytes_internal(key_bytes: &[u8; 64]) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(key_bytes)?,
})
}
#[inline]
#[cfg(feature = "keyless")]
pub fn new_keyless() -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
})
}
#[inline]
#[cfg(feature = "hex-keys")]
pub fn from_hex_key(key_hex: &str) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_hex(key_hex)?,
})
}
#[inline]
#[cfg(feature = "bytes-keys")]
pub fn from_bytes(key_bytes: &[u8; 64]) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(key_bytes)?,
})
}
#[inline]
pub fn key(&self) -> String {
self.masterkey.key_base64()
}
#[inline]
#[cfg(feature = "hex-keys")]
pub fn key_hex(&self) -> String {
self.masterkey.key_hex()
}
#[inline]
#[cfg(feature = "bytes-keys")]
pub fn key_bytes(&self) -> &[u8; 64] {
self.masterkey.key_bytes()
}
}
impl ObtextCodec for $name {
#[inline(always)]
fn enc(&self, plaintext: &str) -> Result<String, Error> {
if plaintext.is_empty() {
return Err(Error::EmptyPlaintext);
}
let mut ciphertext = $encrypt_fn(self.masterkey.key(), plaintext.as_bytes())?;
let marker = $scheme.marker();
let first_byte = ciphertext[0];
ciphertext.push(marker[0] ^ first_byte);
ciphertext.push(marker[1] ^ first_byte);
Ok(encode_bytes(&ciphertext, $encoding))
}
#[inline(always)]
fn dec(&self, obtext: &str) -> Result<String, Error> {
let mut buffer = decode_bytes(obtext, $encoding)?;
if buffer.len() < 2 {
return Err(Error::PayloadTooShort);
}
let len = buffer.len();
let first_byte = buffer[0];
let scheme_marker = [buffer[len - 2] ^ first_byte, buffer[len - 1] ^ first_byte];
if scheme_marker != $scheme.marker() {
return Err(Error::SchemeMarkerMismatch);
}
buffer.truncate(len - 2);
let plaintext_bytes = $decrypt_fn(self.masterkey.key(), &mut buffer)?;
#[cfg(feature = "unchecked-utf8")]
{
Ok(unsafe { String::from_utf8_unchecked(plaintext_bytes) })
}
#[cfg(not(feature = "unchecked-utf8"))]
{
String::from_utf8(plaintext_bytes).map_err(|_| Error::InvalidUtf8)
}
}
#[inline(always)]
fn format(&self) -> Format {
Format::new($scheme, $encoding)
}
#[inline(always)]
fn scheme(&self) -> Scheme {
$scheme
}
#[inline(always)]
fn encoding(&self) -> Encoding {
$encoding
}
}
impl $name {
#[inline(always)]
pub fn enc(&self, plaintext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::enc(self, plaintext)
}
#[inline(always)]
pub fn dec(&self, obtext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::dec(self, obtext)
}
#[inline(always)]
pub fn format(&self) -> Format {
<Self as ObtextCodec>::format(self)
}
#[inline(always)]
pub fn scheme(&self) -> Scheme {
<Self as ObtextCodec>::scheme(self)
}
#[inline(always)]
pub fn encoding(&self) -> Encoding {
<Self as ObtextCodec>::encoding(self)
}
}
};
}
macro_rules! impl_codec_64 {
(
$name:ident,
$scheme:expr,
$encoding:expr,
$format_str:expr,
$encrypt_fn:path,
$decrypt_fn:path,
$key_extract: ident
) => {
#[doc = concat!("ObtextCodec implementation for ", $format_str, " format.\n\n")]
#[doc = concat!("Corresponds to format string: `\"", $format_str, "\"`")]
#[allow(non_camel_case_types)]
pub struct $name {
masterkey: MasterKey,
}
impl $name {
#[inline]
pub fn new(key: &str) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_base64(key)?,
})
}
#[inline]
#[cfg(any(feature = "keyless", feature = "bytes-keys"))]
fn from_bytes_internal(key_bytes: &[u8; 64]) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(key_bytes)?,
})
}
#[inline]
#[cfg(feature = "keyless")]
pub fn new_keyless() -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
})
}
#[inline]
#[cfg(feature = "hex-keys")]
pub fn from_hex_key(key_hex: &str) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_hex(key_hex)?,
})
}
#[inline]
#[cfg(feature = "bytes-keys")]
pub fn from_bytes(key_bytes: &[u8; 64]) -> Result<Self, Error> {
Ok(Self {
masterkey: MasterKey::from_bytes(key_bytes)?,
})
}
#[inline]
pub fn key(&self) -> String {
self.masterkey.key_base64()
}
#[inline]
#[cfg(feature = "hex-keys")]
pub fn key_hex(&self) -> String {
self.masterkey.key_hex()
}
#[inline]
#[cfg(feature = "bytes-keys")]
pub fn key_bytes(&self) -> &[u8; 64] {
self.masterkey.key_bytes()
}
}
impl ObtextCodec for $name {
#[inline(always)]
fn enc(&self, plaintext: &str) -> Result<String, Error> {
if plaintext.is_empty() {
return Err(Error::EmptyPlaintext);
}
let mut ciphertext = $encrypt_fn(self.masterkey.key(), plaintext.as_bytes())?;
let marker = $scheme.marker();
let first_byte = ciphertext[0];
ciphertext.push(marker[0] ^ first_byte);
ciphertext.push(marker[1] ^ first_byte);
Ok(encode_bytes(&ciphertext, $encoding))
}
#[inline(always)]
fn dec(&self, obtext: &str) -> Result<String, Error> {
let mut buffer = decode_bytes(obtext, $encoding)?;
if buffer.len() < 2 {
return Err(Error::PayloadTooShort);
}
let len = buffer.len();
let first_byte = buffer[0];
let scheme_marker = [buffer[len - 2] ^ first_byte, buffer[len - 1] ^ first_byte];
if scheme_marker != $scheme.marker() {
return Err(Error::SchemeMarkerMismatch);
}
buffer.truncate(len - 2);
let plaintext_bytes = $decrypt_fn(self.masterkey.key(), &mut buffer)?;
#[cfg(feature = "unchecked-utf8")]
{
Ok(unsafe { String::from_utf8_unchecked(plaintext_bytes) })
}
#[cfg(not(feature = "unchecked-utf8"))]
{
String::from_utf8(plaintext_bytes).map_err(|_| Error::InvalidUtf8)
}
}
#[inline(always)]
fn format(&self) -> Format {
Format::new($scheme, $encoding)
}
#[inline(always)]
fn scheme(&self) -> Scheme {
$scheme
}
#[inline(always)]
fn encoding(&self) -> Encoding {
$encoding
}
}
impl $name {
#[inline(always)]
pub fn enc(&self, plaintext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::enc(self, plaintext)
}
#[inline(always)]
pub fn dec(&self, obtext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::dec(self, obtext)
}
#[inline(always)]
pub fn format(&self) -> Format {
<Self as ObtextCodec>::format(self)
}
#[inline(always)]
pub fn scheme(&self) -> Scheme {
<Self as ObtextCodec>::scheme(self)
}
#[inline(always)]
pub fn encoding(&self) -> Encoding {
<Self as ObtextCodec>::encoding(self)
}
}
};
}
#[inline(always)]
fn encode_bytes(bytes: &[u8], encoding: Encoding) -> String {
match encoding {
Encoding::C32 => crate::base32::BASE32_CROCKFORD.encode(bytes),
Encoding::B32 => crate::base32::BASE32_RFC.encode(bytes),
Encoding::B64 => data_encoding::BASE64URL_NOPAD.encode(bytes),
Encoding::Hex => data_encoding::HEXLOWER.encode(bytes),
}
}
#[inline(always)]
fn decode_bytes(text: &str, encoding: Encoding) -> Result<Vec<u8>, Error> {
match encoding {
Encoding::C32 => crate::base32::BASE32_CROCKFORD
.decode(text.as_bytes())
.map_err(|_| Error::InvalidC32),
Encoding::B32 => crate::base32::BASE32_RFC
.decode(text.as_bytes())
.map_err(|_| Error::InvalidB32),
Encoding::B64 => data_encoding::BASE64URL_NOPAD
.decode(text.as_bytes())
.map_err(|_| Error::InvalidB64),
Encoding::Hex => data_encoding::HEXLOWER
.decode(text.as_bytes())
.map_err(|_| Error::InvalidHex),
}
}
#[cfg(feature = "aags")]
impl_codec_32!(
AagsC32,
Scheme::Aags,
Encoding::C32,
"aags. c32",
crate::encrypt_aags,
crate::decrypt_aags,
aags
);
#[cfg(feature = "aags")]
impl_codec_32!(
AagsB32,
Scheme::Aags,
Encoding::B32,
"aags. b32",
crate::encrypt_aags,
crate::decrypt_aags,
aags
);
#[cfg(feature = "aags")]
impl_codec_32!(
AagsB64,
Scheme::Aags,
Encoding::B64,
"aags.b64",
crate::encrypt_aags,
crate::decrypt_aags,
aags
);
#[cfg(feature = "aags")]
impl_codec_32!(
AagsHex,
Scheme::Aags,
Encoding::Hex,
"aags.hex",
crate::encrypt_aags,
crate::decrypt_aags,
aags
);
#[cfg(feature = "aasv")]
impl_codec_64!(
AasvC32,
Scheme::Aasv,
Encoding::C32,
"aasv.c32",
crate::encrypt_aasv,
crate::decrypt_aasv,
aasv
);
#[cfg(feature = "aasv")]
impl_codec_64!(
AasvB32,
Scheme::Aasv,
Encoding::B32,
"aasv.b32",
crate::encrypt_aasv,
crate::decrypt_aasv,
aasv
);
#[cfg(feature = "aasv")]
impl_codec_64!(
AasvB64,
Scheme::Aasv,
Encoding::B64,
"aasv.b64",
crate::encrypt_aasv,
crate::decrypt_aasv,
aasv
);
#[cfg(feature = "aasv")]
impl_codec_64!(
AasvHex,
Scheme::Aasv,
Encoding::Hex,
"aasv.hex",
crate::encrypt_aasv,
crate::decrypt_aasv,
aasv
);
#[cfg(feature = "apgs")]
impl_codec_32!(
ApgsC32,
Scheme::Apgs,
Encoding::C32,
"apgs.c32",
crate::encrypt_apgs,
crate::decrypt_apgs,
apgs
);
#[cfg(feature = "apgs")]
impl_codec_32!(
ApgsB32,
Scheme::Apgs,
Encoding::B32,
"apgs.b32",
crate::encrypt_apgs,
crate::decrypt_apgs,
apgs
);
#[cfg(feature = "apgs")]
impl_codec_32!(
ApgsB64,
Scheme::Apgs,
Encoding::B64,
"apgs.b64",
crate::encrypt_apgs,
crate::decrypt_apgs,
apgs
);
#[cfg(feature = "apgs")]
impl_codec_32!(
ApgsHex,
Scheme::Apgs,
Encoding::Hex,
"apgs.hex",
crate::encrypt_apgs,
crate::decrypt_apgs,
apgs
);
#[cfg(feature = "apsv")]
impl_codec_64!(
ApsvC32,
Scheme::Apsv,
Encoding::C32,
"apsv.c32",
crate::encrypt_apsv,
crate::decrypt_apsv,
apsv
);
#[cfg(feature = "apsv")]
impl_codec_64!(
ApsvB32,
Scheme::Apsv,
Encoding::B32,
"apsv.b32",
crate::encrypt_apsv,
crate::decrypt_apsv,
apsv
);
#[cfg(feature = "apsv")]
impl_codec_64!(
ApsvB64,
Scheme::Apsv,
Encoding::B64,
"apsv.b64",
crate::encrypt_apsv,
crate::decrypt_apsv,
apsv
);
#[cfg(feature = "apsv")]
impl_codec_64!(
ApsvHex,
Scheme::Apsv,
Encoding::Hex,
"apsv.hex",
crate::encrypt_apsv,
crate::decrypt_apsv,
apsv
);
#[cfg(feature = "upbc")]
impl_codec_32!(
UpbcC32,
Scheme::Upbc,
Encoding::C32,
"upbc.c32",
crate::encrypt_upbc,
crate::decrypt_upbc,
upbc
);
#[cfg(feature = "upbc")]
impl_codec_32!(
UpbcB32,
Scheme::Upbc,
Encoding::B32,
"upbc.b32",
crate::encrypt_upbc,
crate::decrypt_upbc,
upbc
);
#[cfg(feature = "upbc")]
impl_codec_32!(
UpbcB64,
Scheme::Upbc,
Encoding::B64,
"upbc.b64",
crate::encrypt_upbc,
crate::decrypt_upbc,
upbc
);
#[cfg(feature = "upbc")]
impl_codec_32!(
UpbcHex,
Scheme::Upbc,
Encoding::Hex,
"upbc.hex",
crate::encrypt_upbc,
crate::decrypt_upbc,
upbc
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock1C32,
Scheme::Mock1,
Encoding::C32,
"mock1.c32",
crate::encrypt_mock1,
crate::decrypt_mock1,
mock1
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock1B32,
Scheme::Mock1,
Encoding::B32,
"mock1.b32",
crate::encrypt_mock1,
crate::decrypt_mock1,
mock1
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock1B64,
Scheme::Mock1,
Encoding::B64,
"mock1.b64",
crate::encrypt_mock1,
crate::decrypt_mock1,
mock1
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock1Hex,
Scheme::Mock1,
Encoding::Hex,
"mock1.hex",
crate::encrypt_mock1,
crate::decrypt_mock1,
mock1
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock2C32,
Scheme::Mock2,
Encoding::C32,
"mock2.c32",
crate::encrypt_mock2,
crate::decrypt_mock2,
mock2
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock2B32,
Scheme::Mock2,
Encoding::B32,
"mock2.b32",
crate::encrypt_mock2,
crate::decrypt_mock2,
mock2
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock2B64,
Scheme::Mock2,
Encoding::B64,
"mock2.b64",
crate::encrypt_mock2,
crate::decrypt_mock2,
mock2
);
#[cfg(feature = "mock")]
impl_codec_32!(
Mock2Hex,
Scheme::Mock2,
Encoding::Hex,
"mock2.hex",
crate::encrypt_mock2,
crate::decrypt_mock2,
mock2
);
#[allow(non_camel_case_types)]
pub enum ObAny {
#[cfg(feature = "aags")]
AagsC32(AagsC32),
#[cfg(feature = "aags")]
AagsB32(AagsB32),
#[cfg(feature = "aags")]
AagsB64(AagsB64),
#[cfg(feature = "aags")]
AagsHex(AagsHex),
#[cfg(feature = "apgs")]
ApgsC32(ApgsC32),
#[cfg(feature = "apgs")]
ApgsB32(ApgsB32),
#[cfg(feature = "apgs")]
ApgsB64(ApgsB64),
#[cfg(feature = "apgs")]
ApgsHex(ApgsHex),
#[cfg(feature = "aasv")]
AasvC32(AasvC32),
#[cfg(feature = "aasv")]
AasvB32(AasvB32),
#[cfg(feature = "aasv")]
AasvB64(AasvB64),
#[cfg(feature = "aasv")]
AasvHex(AasvHex),
#[cfg(feature = "apsv")]
ApsvC32(ApsvC32),
#[cfg(feature = "apsv")]
ApsvB32(ApsvB32),
#[cfg(feature = "apsv")]
ApsvB64(ApsvB64),
#[cfg(feature = "apsv")]
ApsvHex(ApsvHex),
#[cfg(feature = "upbc")]
UpbcC32(UpbcC32),
#[cfg(feature = "upbc")]
UpbcB32(UpbcB32),
#[cfg(feature = "upbc")]
UpbcB64(UpbcB64),
#[cfg(feature = "upbc")]
UpbcHex(UpbcHex),
#[cfg(feature = "mock")]
Mock1C32(Mock1C32),
#[cfg(feature = "mock")]
Mock1B32(Mock1B32),
#[cfg(feature = "mock")]
Mock1Hex(Mock1Hex),
#[cfg(feature = "mock")]
Mock1B64(Mock1B64),
#[cfg(feature = "mock")]
Mock2C32(Mock2C32),
#[cfg(feature = "mock")]
Mock2B32(Mock2B32),
#[cfg(feature = "mock")]
Mock2Hex(Mock2Hex),
#[cfg(feature = "mock")]
Mock2B64(Mock2B64),
}
macro_rules! delegate_to_inner {
(fn $method:ident(&self $(, $arg:ident: $argty:ty)*) -> $ret:ty) => {
fn $method(&self $(, $arg: $argty)*) -> $ret {
match self {
#[cfg(feature = "aags")]
ObAny::AagsC32(ob) => ob.$method($($arg),*),
#[cfg(feature = "aags")]
ObAny::AagsB32(ob) => ob.$method($($arg),*),
#[cfg(feature = "aags")]
ObAny::AagsB64(ob) => ob.$method($($arg),*),
#[cfg(feature = "aags")]
ObAny::AagsHex(ob) => ob.$method($($arg),*),
#[cfg(feature = "apgs")]
ObAny::ApgsC32(ob) => ob.$method($($arg),*),
#[cfg(feature = "apgs")]
ObAny::ApgsB32(ob) => ob.$method($($arg),*),
#[cfg(feature = "apgs")]
ObAny::ApgsB64(ob) => ob.$method($($arg),*),
#[cfg(feature = "apgs")]
ObAny::ApgsHex(ob) => ob.$method($($arg),*),
#[cfg(feature = "aasv")]
ObAny::AasvC32(ob) => ob.$method($($arg),*),
#[cfg(feature = "aasv")]
ObAny::AasvB32(ob) => ob.$method($($arg),*),
#[cfg(feature = "aasv")]
ObAny::AasvB64(ob) => ob.$method($($arg),*),
#[cfg(feature = "aasv")]
ObAny::AasvHex(ob) => ob.$method($($arg),*),
#[cfg(feature = "apsv")]
ObAny::ApsvC32(ob) => ob.$method($($arg),*),
#[cfg(feature = "apsv")]
ObAny::ApsvB32(ob) => ob.$method($($arg),*),
#[cfg(feature = "apsv")]
ObAny::ApsvB64(ob) => ob.$method($($arg),*),
#[cfg(feature = "apsv")]
ObAny::ApsvHex(ob) => ob.$method($($arg),*),
#[cfg(feature = "upbc")]
ObAny::UpbcC32(ob) => ob.$method($($arg),*),
#[cfg(feature = "upbc")]
ObAny::UpbcB32(ob) => ob.$method($($arg),*),
#[cfg(feature = "upbc")]
ObAny::UpbcB64(ob) => ob.$method($($arg),*),
#[cfg(feature = "upbc")]
ObAny::UpbcHex(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock1C32(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock1B32(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock1B64(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock1Hex(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock2C32(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock2B32(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock2B64(ob) => ob.$method($($arg),*),
#[cfg(feature = "mock")]
ObAny::Mock2Hex(ob) => ob.$method($($arg),*),
}
}
};
}
impl ObtextCodec for ObAny {
delegate_to_inner!(fn enc(&self, plaintext: &str) -> Result<String, Error>);
delegate_to_inner!(fn dec(&self, obtext: &str) -> Result<String, Error>);
delegate_to_inner!(fn format(&self) -> Format);
delegate_to_inner!(fn scheme(&self) -> Scheme);
delegate_to_inner!(fn encoding(&self) -> Encoding);
}
impl ObAny {
pub fn new(key: &str) -> Result<Self, Error> {
#[cfg(feature = "mock")]
return Ok(ObAny::Mock1C32(Mock1C32::new(key)?));
#[cfg(feature = "upbc")]
#[cfg(not(any(feature = "mock")))]
return Ok(ObAny::UpbcC32(UpbcC32::new(key)?));
#[cfg(feature = "aags")]
#[cfg(not(any(feature = "mock", feature = "upbc")))]
return Ok(ObAny::AagsC32(AagsC32::new(key)?));
#[cfg(feature = "apgs")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags")))]
return Ok(ObAny::ApgsC32(ApgsC32::new(key)?));
#[cfg(feature = "aasv")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags", feature = "apgs")))]
return Ok(ObAny::AasvC32(AasvC32::new(key)?));
#[cfg(feature = "apsv")]
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv"
)))]
return Ok(ObAny::ApsvC32(ApsvC32::new(key)?));
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv",
feature = "apsv",
)))]
compile_error!("At least one oboron scheme must be enabled");
}
#[inline]
#[cfg(feature = "bytes-keys")]
pub fn from_bytes(key_bytes: &[u8; 64]) -> Result<Self, Error> {
#[cfg(feature = "mock")]
return Ok(ObAny::Mock1C32(Mock1C32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(feature = "upbc")]
#[cfg(not(any(feature = "mock")))]
return Ok(ObAny::UpbcC32(UpbcC32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(feature = "aags")]
#[cfg(not(any(feature = "mock", feature = "upbc")))]
return Ok(ObAny::AagsC32(AagsC32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(feature = "apgs")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags")))]
return Ok(ObAny::ApgsC32(ApgsC32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(feature = "aasv")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags", feature = "apgs")))]
return Ok(ObAny::AasvC32(AasvC32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(feature = "apsv")]
#[cfg(not(any(
feature = "aags",
feature = "aasv",
feature = "apgs",
feature = "mock",
feature = "upbc",
)))]
return Ok(ObAny::ApsvC32(ApsvC32 {
masterkey: MasterKey::from_bytes(key_bytes)?,
}));
#[cfg(not(any(
feature = "aags",
feature = "aasv",
feature = "apgs",
feature = "apsv",
feature = "mock",
feature = "upbc",
)))]
compile_error!("At least one oboron scheme must be enabled");
}
#[cfg(feature = "hex-keys")]
pub fn from_hex_key(key_hex: &str) -> Result<Self, Error> {
#[cfg(feature = "mock")]
return Ok(ObAny::Mock1C32(Mock1C32::from_hex_key(key_hex)?));
#[cfg(feature = "upbc")]
#[cfg(not(any(feature = "mock")))]
return Ok(ObAny::UpbcC32(UpbcC32::from_hex_key(key_hex)?));
#[cfg(feature = "aags")]
#[cfg(not(any(feature = "mock", feature = "upbc")))]
return Ok(ObAny::AagsC32(AagsC32::from_hex_key(key_hex)?));
#[cfg(feature = "apgs")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags")))]
return Ok(ObAny::ApgsC32(ApgsC32::from_hex_key(key_hex)?));
#[cfg(feature = "aasv")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags", feature = "apgs")))]
return Ok(ObAny::AasvC32(AasvC32::from_hex_key(key_hex)?));
#[cfg(feature = "apsv")]
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv"
)))]
return Ok(ObAny::ApsvC32(ApsvC32::from_hex_key(key_hex)?));
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv",
feature = "apsv",
)))]
compile_error!("At least one oboron scheme must be enabled");
}
#[cfg(feature = "keyless")]
pub fn new_keyless() -> Result<Self, Error> {
#[cfg(feature = "mock")]
return Ok(ObAny::Mock1C32(Mock1C32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(feature = "upbc")]
#[cfg(not(any(feature = "mock")))]
return Ok(ObAny::UpbcC32(UpbcC32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(feature = "aags")]
#[cfg(not(any(feature = "mock", feature = "upbc")))]
return Ok(ObAny::AagsC32(AagsC32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(feature = "apgs")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags")))]
return Ok(ObAny::ApgsC32(ApgsC32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(feature = "aasv")]
#[cfg(not(any(feature = "mock", feature = "upbc", feature = "aags", feature = "apgs")))]
return Ok(ObAny::AasvC32(AasvC32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(feature = "apsv")]
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv"
)))]
return Ok(ObAny::ApsvC32(ApsvC32 {
masterkey: MasterKey::from_bytes(&HARDCODED_KEY_BYTES)?,
}));
#[cfg(not(any(
feature = "mock",
feature = "upbc",
feature = "aags",
feature = "apgs",
feature = "aasv",
feature = "apsv",
)))]
compile_error!("At least one oboron scheme must be enabled");
}
}
impl ObAny {
#[inline]
pub fn enc(&self, plaintext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::enc(self, plaintext)
}
#[inline]
pub fn dec(&self, obtext: &str) -> Result<String, Error> {
<Self as ObtextCodec>::dec(self, obtext)
}
#[inline]
pub fn format(&self) -> Format {
<Self as ObtextCodec>::format(self)
}
#[inline]
pub fn scheme(&self) -> Scheme {
<Self as ObtextCodec>::scheme(self)
}
#[inline]
pub fn encoding(&self) -> Encoding {
<Self as ObtextCodec>::encoding(self)
}
}
pub fn new(fmt: &str, key: &str) -> Result<ObAny, Error> {
let format = Format::from_str(fmt)?;
new_with_format(format, key)
}
pub fn new_with_format(format: Format, key: &str) -> Result<ObAny, Error> {
match (format.scheme(), format.encoding()) {
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::C32) => Ok(ObAny::UpbcC32(UpbcC32::new(key)?)),
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::B32) => Ok(ObAny::UpbcB32(UpbcB32::new(key)?)),
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::B64) => Ok(ObAny::UpbcB64(UpbcB64::new(key)?)),
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::Hex) => Ok(ObAny::UpbcHex(UpbcHex::new(key)?)),
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::C32) => Ok(ObAny::AagsC32(AagsC32::new(key)?)),
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::B32) => Ok(ObAny::AagsB32(AagsB32::new(key)?)),
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::B64) => Ok(ObAny::AagsB64(AagsB64::new(key)?)),
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::Hex) => Ok(ObAny::AagsHex(AagsHex::new(key)?)),
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::C32) => Ok(ObAny::ApgsC32(ApgsC32::new(key)?)),
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::B32) => Ok(ObAny::ApgsB32(ApgsB32::new(key)?)),
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::B64) => Ok(ObAny::ApgsB64(ApgsB64::new(key)?)),
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::Hex) => Ok(ObAny::ApgsHex(ApgsHex::new(key)?)),
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::C32) => Ok(ObAny::AasvC32(AasvC32::new(key)?)),
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::B32) => Ok(ObAny::AasvB32(AasvB32::new(key)?)),
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::B64) => Ok(ObAny::AasvB64(AasvB64::new(key)?)),
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::Hex) => Ok(ObAny::AasvHex(AasvHex::new(key)?)),
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::C32) => Ok(ObAny::ApsvC32(ApsvC32::new(key)?)),
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::B32) => Ok(ObAny::ApsvB32(ApsvB32::new(key)?)),
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::B64) => Ok(ObAny::ApsvB64(ApsvB64::new(key)?)),
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::Hex) => Ok(ObAny::ApsvHex(ApsvHex::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::C32) => Ok(ObAny::Mock1C32(Mock1C32::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::B32) => Ok(ObAny::Mock1B32(Mock1B32::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::B64) => Ok(ObAny::Mock1B64(Mock1B64::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::Hex) => Ok(ObAny::Mock1Hex(Mock1Hex::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::C32) => Ok(ObAny::Mock2C32(Mock2C32::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::B32) => Ok(ObAny::Mock2B32(Mock2B32::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::B64) => Ok(ObAny::Mock2B64(Mock2B64::new(key)?)),
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::Hex) => Ok(ObAny::Mock2Hex(Mock2Hex::new(key)?)),
#[allow(unreachable_patterns)]
_ => Err(Error::UnknownScheme),
}
}
#[cfg(any(feature = "keyless", feature = "bytes-keys", feature = "hex-keys"))]
fn from_bytes_with_format_internal(format: Format, key_bytes: &[u8; 64]) -> Result<ObAny, Error> {
match (format.scheme(), format.encoding()) {
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::C32) => {
Ok(ObAny::UpbcC32(UpbcC32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::B32) => {
Ok(ObAny::UpbcB32(UpbcB32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::B64) => {
Ok(ObAny::UpbcB64(UpbcB64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "upbc")]
(Scheme::Upbc, Encoding::Hex) => {
Ok(ObAny::UpbcHex(UpbcHex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::C32) => {
Ok(ObAny::AagsC32(AagsC32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::B32) => {
Ok(ObAny::AagsB32(AagsB32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::B64) => {
Ok(ObAny::AagsB64(AagsB64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aags")]
(Scheme::Aags, Encoding::Hex) => {
Ok(ObAny::AagsHex(AagsHex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::C32) => {
Ok(ObAny::ApgsC32(ApgsC32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::B32) => {
Ok(ObAny::ApgsB32(ApgsB32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::B64) => {
Ok(ObAny::ApgsB64(ApgsB64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apgs")]
(Scheme::Apgs, Encoding::Hex) => {
Ok(ObAny::ApgsHex(ApgsHex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::C32) => {
Ok(ObAny::AasvC32(AasvC32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::B32) => {
Ok(ObAny::AasvB32(AasvB32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::B64) => {
Ok(ObAny::AasvB64(AasvB64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "aasv")]
(Scheme::Aasv, Encoding::Hex) => {
Ok(ObAny::AasvHex(AasvHex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::C32) => {
Ok(ObAny::ApsvC32(ApsvC32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::B32) => {
Ok(ObAny::ApsvB32(ApsvB32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::B64) => {
Ok(ObAny::ApsvB64(ApsvB64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "apsv")]
(Scheme::Apsv, Encoding::Hex) => {
Ok(ObAny::ApsvHex(ApsvHex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::C32) => {
Ok(ObAny::Mock1C32(Mock1C32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::B32) => {
Ok(ObAny::Mock1B32(Mock1B32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::B64) => {
Ok(ObAny::Mock1B64(Mock1B64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock1, Encoding::Hex) => {
Ok(ObAny::Mock1Hex(Mock1Hex::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::C32) => {
Ok(ObAny::Mock2C32(Mock2C32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::B32) => {
Ok(ObAny::Mock2B32(Mock2B32::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::B64) => {
Ok(ObAny::Mock2B64(Mock2B64::from_bytes_internal(key_bytes)?))
}
#[cfg(feature = "mock")]
(Scheme::Mock2, Encoding::Hex) => {
Ok(ObAny::Mock2Hex(Mock2Hex::from_bytes_internal(key_bytes)?))
}
#[allow(unreachable_patterns)]
_ => Err(Error::UnknownScheme),
}
}
#[cfg(feature = "hex-keys")]
fn from_hex_key_with_format_internal(format: Format, key_hex: &str) -> Result<ObAny, Error> {
let key_vec = hex::decode(key_hex)?;
let key_arr: [u8; 64] = key_vec.try_into().map_err(|_| Error::InvalidKeyLength)?;
from_bytes_with_format_internal(format, &key_arr)
}
#[cfg(feature = "hex-keys")]
pub fn from_hex_key(fmt: &str, key_hex: &str) -> Result<ObAny, Error> {
let format = Format::from_str(fmt)?;
from_hex_key_with_format_internal(format, key_hex)
}
#[cfg(feature = "hex-keys")]
pub fn from_hex_key_with_format(format: Format, key_hex: &str) -> Result<ObAny, Error> {
from_hex_key_with_format_internal(format, key_hex)
}
#[cfg(feature = "bytes-keys")]
pub fn from_bytes(fmt: &str, key_bytes: &[u8; 64]) -> Result<ObAny, Error> {
let format = Format::from_str(fmt)?;
from_bytes_with_format_internal(format, &key_bytes)
}
#[cfg(feature = "bytes-keys")]
pub fn from_bytes_with_format(format: Format, key_bytes: &[u8; 64]) -> Result<ObAny, Error> {
from_bytes_with_format_internal(format, key_bytes)
}
#[cfg(feature = "keyless")]
pub fn new_keyless(fmt: &str) -> Result<ObAny, Error> {
let format = Format::from_str(fmt)?;
from_bytes_with_format_internal(format, &HARDCODED_KEY_BYTES)
}
#[cfg(feature = "keyless")]
pub fn new_keyless_with_format(format: Format) -> Result<ObAny, Error> {
from_bytes_with_format_internal(format, &HARDCODED_KEY_BYTES)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_with_format_all_combinations() {
let key = crate::generate_key();
let schemes = vec![
#[cfg(feature = "upbc")]
Scheme::Upbc,
#[cfg(feature = "aags")]
Scheme::Aags,
#[cfg(feature = "apgs")]
Scheme::Apgs,
#[cfg(feature = "aasv")]
Scheme::Aasv,
#[cfg(feature = "apsv")]
Scheme::Apsv,
#[cfg(feature = "mock")]
Scheme::Mock1,
#[cfg(feature = "mock")]
Scheme::Mock2,
];
let encodings = vec![Encoding::C32, Encoding::B32, Encoding::B64, Encoding::Hex];
for scheme in &schemes {
for encoding in &encodings {
let format = Format::new(*scheme, *encoding);
let result = new_with_format(format, &key);
assert!(
result.is_ok(),
"Failed to create ObtextCodec implementation for {:?}:{:?}",
scheme,
encoding
);
let ob = result.unwrap();
assert_eq!(
ob.scheme(),
*scheme,
"Scheme mismatch for {:?}:{:?}",
scheme,
encoding
);
assert_eq!(
ob.encoding(),
*encoding,
"Encoding mismatch for {:?}:{:?}",
scheme,
encoding
);
}
}
}
#[test]
fn test_new_from_format_string_all_combinations() {
let key = crate::generate_key();
let schemes = vec![
Scheme::Mock2,
Scheme::Mock1,
#[cfg(feature = "upbc")]
Scheme::Upbc,
#[cfg(feature = "aags")]
Scheme::Aags,
#[cfg(feature = "apgs")]
Scheme::Apgs,
#[cfg(feature = "aasv")]
Scheme::Aasv,
#[cfg(feature = "apsv")]
Scheme::Apsv,
];
let encodings = vec![Encoding::C32, Encoding::B32, Encoding::B64, Encoding::Hex];
for scheme in schemes {
for encoding in &encodings {
let format_str = format!("{}.{}", scheme.as_str(), encoding.as_str());
let result = new(format_str.as_str(), &key);
assert!(
result.is_ok(),
"Failed to create ObtextCodec implementation from format string: {}",
format_str
);
let ob = result.unwrap();
assert_eq!(
ob.scheme(),
scheme,
"Scheme mismatch for format string: {}",
format_str
);
assert_eq!(
ob.encoding(),
*encoding,
"Encoding mismatch for format string: {}",
format_str
);
}
}
}
#[test]
fn test_roundtrip_all_combinations() {
let key = crate::generate_key();
let plaintext = "hello world";
let schemes = vec![
Scheme::Mock2,
Scheme::Mock1,
#[cfg(feature = "aags")]
Scheme::Aags,
#[cfg(feature = "aasv")]
Scheme::Aasv,
];
let encodings = vec![Encoding::C32, Encoding::B32, Encoding::B64, Encoding::Hex];
for scheme in &schemes {
if scheme.is_probabilistic() {
continue;
}
for encoding in &encodings {
let format = Format::new(*scheme, *encoding);
let ob = new_with_format(format, &key).unwrap();
let ot = ob.enc(&plaintext).unwrap();
let pt2 = ob.dec(&ot).unwrap();
assert_eq!(
pt2, plaintext,
"Roundtrip failed for {:?}:{:?}",
scheme, encoding
);
}
}
}
#[test]
fn test_key_methods() {
let key = crate::generate_key();
let aasv = AasvC32::new(&key).unwrap();
let retrieved_key = aasv.key();
assert_eq!(retrieved_key, key);
assert_eq!(retrieved_key.len(), 86);
#[cfg(feature = "hex-keys")]
{
let key_hex = aasv.key_hex();
assert_eq!(key_hex.len(), 128);
}
#[cfg(feature = "bytes-keys")]
{
let key_bytes = aasv.key_bytes();
assert_eq!(key_bytes.len(), 64);
}
}
}