use crate::AlgorithmIdentifierRef;
use der::{
asn1::{AnyRef, ObjectIdentifier, OctetStringRef},
Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Writer,
};
pub const PBE_WITH_MD2_AND_DES_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.1");
pub const PBE_WITH_MD2_AND_RC2_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.4");
pub const PBE_WITH_MD5_AND_DES_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.3");
pub const PBE_WITH_MD5_AND_RC2_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.6");
pub const PBE_WITH_SHA1_AND_DES_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.10");
pub const PBE_WITH_SHA1_AND_RC2_CBC_OID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.11");
pub const SALT_LENGTH: usize = 8;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Algorithm {
pub encryption: EncryptionScheme,
pub parameters: Parameters,
}
impl Algorithm {
pub fn oid(&self) -> ObjectIdentifier {
self.encryption.oid()
}
}
impl<'a> DecodeValue<'a> for Algorithm {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
AlgorithmIdentifierRef::decode_value(reader, header)?.try_into()
}
}
impl EncodeValue for Algorithm {
fn value_len(&self) -> der::Result<Length> {
self.encryption.encoded_len()? + self.parameters.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.encryption.encode(writer)?;
self.parameters.encode(writer)?;
Ok(())
}
}
impl Sequence<'_> for Algorithm {}
impl<'a> TryFrom<AlgorithmIdentifierRef<'a>> for Algorithm {
type Error = der::Error;
fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result<Self> {
let encryption = EncryptionScheme::try_from(alg.oid)
.map_err(|_| der::Tag::ObjectIdentifier.value_error())?;
let parameters = alg
.parameters
.ok_or_else(|| Tag::OctetString.value_error())?
.try_into()?;
Ok(Self {
encryption,
parameters,
})
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Parameters {
pub salt: [u8; SALT_LENGTH],
pub iteration_count: u16,
}
impl<'a> DecodeValue<'a> for Parameters {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
AnyRef::decode_value(reader, header)?.try_into()
}
}
impl EncodeValue for Parameters {
fn value_len(&self) -> der::Result<Length> {
OctetStringRef::new(&self.salt)?.encoded_len()? + self.iteration_count.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
OctetStringRef::new(&self.salt)?.encode(writer)?;
self.iteration_count.encode(writer)?;
Ok(())
}
}
impl Sequence<'_> for Parameters {}
impl TryFrom<AnyRef<'_>> for Parameters {
type Error = der::Error;
fn try_from(any: AnyRef<'_>) -> der::Result<Parameters> {
any.sequence(|reader| {
Ok(Parameters {
salt: OctetStringRef::decode(reader)?
.as_bytes()
.try_into()
.map_err(|_| der::Tag::OctetString.value_error())?,
iteration_count: reader.decode()?,
})
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum EncryptionScheme {
PbeWithMd2AndDesCbc,
PbeWithMd2AndRc2Cbc,
PbeWithMd5AndDesCbc,
PbeWithMd5AndRc2Cbc,
PbeWithSha1AndDesCbc,
PbeWithSha1AndRc2Cbc,
}
impl TryFrom<ObjectIdentifier> for EncryptionScheme {
type Error = der::Error;
fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
match oid {
PBE_WITH_MD2_AND_DES_CBC_OID => Ok(Self::PbeWithMd2AndDesCbc),
PBE_WITH_MD2_AND_RC2_CBC_OID => Ok(Self::PbeWithMd2AndRc2Cbc),
PBE_WITH_MD5_AND_DES_CBC_OID => Ok(Self::PbeWithMd5AndDesCbc),
PBE_WITH_MD5_AND_RC2_CBC_OID => Ok(Self::PbeWithMd5AndRc2Cbc),
PBE_WITH_SHA1_AND_DES_CBC_OID => Ok(Self::PbeWithSha1AndDesCbc),
PBE_WITH_SHA1_AND_RC2_CBC_OID => Ok(Self::PbeWithSha1AndRc2Cbc),
_ => Err(ErrorKind::OidUnknown { oid }.into()),
}
}
}
impl EncryptionScheme {
pub fn cipher(self) -> SymmetricCipher {
match self {
Self::PbeWithMd2AndDesCbc => SymmetricCipher::DesCbc,
Self::PbeWithMd2AndRc2Cbc => SymmetricCipher::Rc2Cbc,
Self::PbeWithMd5AndDesCbc => SymmetricCipher::DesCbc,
Self::PbeWithMd5AndRc2Cbc => SymmetricCipher::Rc2Cbc,
Self::PbeWithSha1AndDesCbc => SymmetricCipher::DesCbc,
Self::PbeWithSha1AndRc2Cbc => SymmetricCipher::Rc2Cbc,
}
}
pub fn digest(self) -> DigestAlgorithm {
match self {
Self::PbeWithMd2AndDesCbc => DigestAlgorithm::Md2,
Self::PbeWithMd2AndRc2Cbc => DigestAlgorithm::Md2,
Self::PbeWithMd5AndDesCbc => DigestAlgorithm::Md5,
Self::PbeWithMd5AndRc2Cbc => DigestAlgorithm::Md5,
Self::PbeWithSha1AndDesCbc => DigestAlgorithm::Sha1,
Self::PbeWithSha1AndRc2Cbc => DigestAlgorithm::Sha1,
}
}
pub fn oid(self) -> ObjectIdentifier {
match self {
Self::PbeWithMd2AndDesCbc => PBE_WITH_MD2_AND_DES_CBC_OID,
Self::PbeWithMd2AndRc2Cbc => PBE_WITH_MD2_AND_RC2_CBC_OID,
Self::PbeWithMd5AndDesCbc => PBE_WITH_MD5_AND_DES_CBC_OID,
Self::PbeWithMd5AndRc2Cbc => PBE_WITH_MD5_AND_RC2_CBC_OID,
Self::PbeWithSha1AndDesCbc => PBE_WITH_SHA1_AND_DES_CBC_OID,
Self::PbeWithSha1AndRc2Cbc => PBE_WITH_SHA1_AND_RC2_CBC_OID,
}
}
}
impl Encode for EncryptionScheme {
fn encoded_len(&self) -> der::Result<Length> {
self.oid().encoded_len()
}
fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
self.oid().encode(writer)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum DigestAlgorithm {
Md2,
Md5,
Sha1,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SymmetricCipher {
DesCbc,
Rc2Cbc,
}