use crate::{constants::SCHEME_MARKER_SIZE, error::Error, Encoding, MasterKey};
#[cfg(feature = "aags")]
use crate::{constants::AAGS_MARKER, decrypt_aags};
#[cfg(feature = "aasv")]
use crate::{constants::AASV_MARKER, decrypt_aasv};
#[cfg(feature = "apgs")]
use crate::{constants::APGS_MARKER, decrypt_apgs};
#[cfg(feature = "apsv")]
use crate::{constants::APSV_MARKER, decrypt_apsv};
#[cfg(feature = "upbc")]
use crate::{constants::UPBC_MARKER, decrypt_upbc};
#[cfg(feature = "mock")]
use crate::{constants::MOCK1_MARKER, decrypt_mock1};
#[cfg(feature = "mock")]
use crate::{constants::MOCK2_MARKER, decrypt_mock2};
pub fn dec_any_scheme(
masterkey: &MasterKey,
encoding: Encoding,
obtext: &str,
) -> Result<String, Error> {
let mut buffer = crate::dec::decode_obtext_to_payload(obtext, encoding)?;
if buffer.len() < SCHEME_MARKER_SIZE {
return Err(Error::PayloadTooShort);
}
let len = buffer.len();
buffer[len - 1] ^= buffer[0];
buffer[len - 2] ^= buffer[0];
let scheme_marker = [buffer[len - 2], buffer[len - 1]];
buffer.truncate(len - SCHEME_MARKER_SIZE);
let plaintext_bytes = match scheme_marker {
#[cfg(feature = "upbc")]
UPBC_MARKER => decrypt_upbc(masterkey.key(), &mut buffer)?,
#[cfg(feature = "aags")]
AAGS_MARKER => decrypt_aags(masterkey.key(), &buffer)?,
#[cfg(feature = "apgs")]
APGS_MARKER => decrypt_apgs(masterkey.key(), &buffer)?,
#[cfg(feature = "aasv")]
AASV_MARKER => decrypt_aasv(masterkey.key(), &buffer)?,
#[cfg(feature = "apsv")]
APSV_MARKER => decrypt_apsv(masterkey.key(), &buffer)?,
#[cfg(feature = "mock")]
MOCK1_MARKER => decrypt_mock1(masterkey.key(), &buffer)?,
#[cfg(feature = "mock")]
MOCK2_MARKER => decrypt_mock2(masterkey.key(), &buffer)?,
_ => {
return Err(Error::UnknownScheme);
}
};
#[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)
}
}
pub(crate) fn dec_any_scheme_c32(masterkey: &MasterKey, obtext: &str) -> Result<String, Error> {
dec_any_scheme(masterkey, Encoding::C32, obtext)
}
pub(crate) fn dec_any_scheme_b32(masterkey: &MasterKey, obtext: &str) -> Result<String, Error> {
dec_any_scheme(masterkey, Encoding::B32, obtext)
}
pub(crate) fn dec_any_scheme_b64(masterkey: &MasterKey, obtext: &str) -> Result<String, Error> {
dec_any_scheme(masterkey, Encoding::B64, obtext)
}
pub(crate) fn dec_any_scheme_hex(masterkey: &MasterKey, obtext: &str) -> Result<String, Error> {
dec_any_scheme(masterkey, Encoding::Hex, obtext)
}
pub fn dec_any_format(masterkey: &MasterKey, obtext: &str) -> Result<String, Error> {
let mut has_dash = false;
let mut has_underscore = false;
let mut has_upper = false;
let mut has_lower = false;
let mut has_non_hex_lower = false;
for b in obtext.bytes() {
match b {
b'-' => has_dash = true,
b'_' => has_underscore = true,
b'A'..=b'Z' => has_upper = true,
b'a'..=b'f' => has_lower = true,
b'g'..=b'z' => {
has_lower = true;
has_non_hex_lower = true;
}
_ => {}
}
}
if has_dash || has_underscore || (has_lower && has_upper) {
if let Ok(result) = dec_any_scheme_b64(masterkey, obtext) {
return Ok(result);
}
}
if has_upper {
if let Ok(result) = dec_any_scheme_b32(masterkey, obtext) {
return Ok(result);
}
if let Ok(result) = dec_any_scheme_b64(masterkey, obtext) {
return Ok(result);
}
}
if has_non_hex_lower {
if let Ok(result) = dec_any_scheme_c32(masterkey, obtext) {
return Ok(result);
}
if let Ok(result) = dec_any_scheme_b64(masterkey, obtext) {
return Ok(result);
}
}
if let Ok(result) = dec_any_scheme_hex(masterkey, obtext) {
return Ok(result);
}
if let Ok(result) = dec_any_scheme_c32(masterkey, obtext) {
return Ok(result);
}
dec_any_scheme_b64(masterkey, obtext)
}