#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![forbid(unsafe_code)]
#[cfg(all(feature = "alloc", feature = "pbes2"))]
extern crate alloc;
mod error;
pub mod pbes1;
pub mod pbes2;
pub use crate::error::{Error, Result};
pub use der::{self, asn1::ObjectIdentifier};
pub use spki::AlgorithmIdentifierRef;
use der::{
Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer,
};
#[cfg(feature = "pbes2")]
pub use scrypt;
#[cfg(all(feature = "alloc", feature = "pbes2"))]
use alloc::vec::Vec;
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[allow(clippy::large_enum_variant)]
pub enum EncryptionScheme {
Pbes1(pbes1::Algorithm),
Pbes2(pbes2::Parameters),
}
impl EncryptionScheme {
#[cfg(all(feature = "pbes2", feature = "getrandom"))]
#[must_use]
#[track_caller]
pub fn generate() -> Self {
Self::Pbes2(pbes2::Parameters::generate())
}
#[cfg(all(feature = "alloc", feature = "pbes2"))]
pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
match self {
Self::Pbes2(params) => params.decrypt(password, ciphertext),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}
#[cfg(feature = "pbes2")]
pub fn decrypt_in_place<'a>(
&self,
password: impl AsRef<[u8]>,
buffer: &'a mut [u8],
) -> Result<&'a [u8]> {
match self {
Self::Pbes2(params) => params.decrypt_in_place(password, buffer),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}
#[cfg(all(feature = "alloc", feature = "pbes2"))]
pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
match self {
Self::Pbes2(params) => params.encrypt(password, plaintext),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}
#[cfg(feature = "pbes2")]
pub fn encrypt_in_place<'a>(
&self,
password: impl AsRef<[u8]>,
buffer: &'a mut [u8],
pos: usize,
) -> Result<&'a [u8]> {
match self {
Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}
#[must_use]
pub fn oid(&self) -> ObjectIdentifier {
match self {
Self::Pbes1(params) => params.oid(),
Self::Pbes2(_) => pbes2::PBES2_OID,
}
}
#[must_use]
pub fn pbes1(&self) -> Option<&pbes1::Algorithm> {
match self {
Self::Pbes1(alg) => Some(alg),
_ => None,
}
}
#[must_use]
pub fn pbes2(&self) -> Option<&pbes2::Parameters> {
match self {
Self::Pbes2(params) => Some(params),
_ => None,
}
}
}
impl<'a> DecodeValue<'a> for EncryptionScheme {
type Error = der::Error;
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into()
}
}
impl EncodeValue for EncryptionScheme {
fn value_len(&self) -> der::Result<Length> {
match self {
Self::Pbes1(pbes1) => pbes1.oid().encoded_len()? + pbes1.parameters.encoded_len()?,
Self::Pbes2(pbes2) => pbes2::PBES2_OID.encoded_len()? + pbes2.encoded_len()?,
}
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
match self {
Self::Pbes1(pbes1) => {
pbes1.oid().encode(writer)?;
pbes1.parameters.encode(writer)?;
}
Self::Pbes2(pbes2) => {
pbes2::PBES2_OID.encode(writer)?;
pbes2.encode(writer)?;
}
}
Ok(())
}
}
impl Sequence<'_> for EncryptionScheme {}
impl From<pbes1::Algorithm> for EncryptionScheme {
fn from(alg: pbes1::Algorithm) -> EncryptionScheme {
Self::Pbes1(alg)
}
}
impl From<pbes2::Parameters> for EncryptionScheme {
fn from(params: pbes2::Parameters) -> EncryptionScheme {
Self::Pbes2(params)
}
}
impl TryFrom<AlgorithmIdentifierRef<'_>> for EncryptionScheme {
type Error = der::Error;
fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result<EncryptionScheme> {
if alg.oid == pbes2::PBES2_OID {
match alg.parameters {
Some(params) => pbes2::Parameters::try_from(params).map(Into::into),
None => Err(Tag::OctetString.value_error().into()),
}
} else {
pbes1::Algorithm::try_from(alg).map(Into::into)
}
}
}
impl TryFrom<&[u8]> for EncryptionScheme {
type Error = der::Error;
fn try_from(bytes: &[u8]) -> der::Result<EncryptionScheme> {
AlgorithmIdentifierRef::from_der(bytes)?.try_into()
}
}