Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions pkcs5/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Error types

use core::fmt;
use der::asn1::ObjectIdentifier;

/// Result type
pub type Result<T> = core::result::Result<T, Error>;

/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Given parameters are invalid for this algorithm
AlgorithmParametersInvalid {
/// OID for algorithm for which the parameters were invalid
oid: ObjectIdentifier,
},

/// Decryption Failed
DecryptFailed,

/// Encryption Failed
EncryptFailed,

/// Pbes1 support is limited to parsing; encryption/decryption is not supported (won't fix)
#[cfg(feature = "pbes2")]
NoPbes1CryptSupport,

/// Algorithm is not supported
///
/// This may be due to a disabled crate feature
/// Or the algorithm is not supported at all.
UnsupportedAlgorithm {
/// OID of unsupported algorithm
oid: ObjectIdentifier,
},
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::AlgorithmParametersInvalid { oid } => {
write!(f, "PKCS#5 parameters for algorithm {} are invalid", oid)
}
Error::DecryptFailed => f.write_str("PKCS#5 decryption failed"),
Error::EncryptFailed => f.write_str("PKCS#5 encryption failed"),
#[cfg(feature = "pbes2")]
Error::NoPbes1CryptSupport => {
f.write_str("PKCS#5 encryption/decryption unsupported for PBES1 (won't fix)")
}
Error::UnsupportedAlgorithm { oid } => {
write!(f, "PKCS#5 algorithm {} is unsupported", oid)
}
}
}
}
48 changes: 15 additions & 33 deletions pkcs5/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,21 @@
#[cfg(all(feature = "alloc", feature = "pbes2"))]
extern crate alloc;

mod error;

pub mod pbes1;
pub mod pbes2;

pub use der::{self, asn1::ObjectIdentifier, Error};
pub use crate::error::{Error, Result};
pub use der::{self, asn1::ObjectIdentifier};
pub use spki::AlgorithmIdentifier;

use core::{
convert::{TryFrom, TryInto},
fmt,
};
use core::convert::{TryFrom, TryInto};
use der::{Decodable, Decoder, Encodable, Encoder, Length};

#[cfg(all(feature = "alloc", feature = "pbes2"))]
use alloc::vec::Vec;

/// Cryptographic errors
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct CryptoError;

impl fmt::Display for CryptoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PKCS#5 cryptographic error")
}
}

/// Supported PKCS#5 password-based encryption schemes.
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
Expand All @@ -75,14 +65,10 @@ impl<'a> EncryptionScheme<'a> {
#[cfg(all(feature = "alloc", feature = "pbes2"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg_attr(docsrs, doc(cfg(feature = "pbes2")))]
pub fn decrypt(
&self,
password: impl AsRef<[u8]>,
ciphertext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
match self {
Self::Pbes2(params) => params.decrypt(password, ciphertext),
_ => Err(CryptoError),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}

Expand All @@ -98,10 +84,10 @@ impl<'a> EncryptionScheme<'a> {
&self,
password: impl AsRef<[u8]>,
buffer: &'b mut [u8],
) -> Result<&'b [u8], CryptoError> {
) -> Result<&'b [u8]> {
match self {
Self::Pbes2(params) => params.decrypt_in_place(password, buffer),
_ => Err(CryptoError),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}

Expand All @@ -110,14 +96,10 @@ impl<'a> EncryptionScheme<'a> {
#[cfg(all(feature = "alloc", feature = "pbes2"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg_attr(docsrs, doc(cfg(feature = "pbes2")))]
pub fn encrypt(
&self,
password: impl AsRef<[u8]>,
plaintext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
match self {
Self::Pbes2(params) => params.encrypt(password, plaintext),
_ => Err(CryptoError),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}

Expand All @@ -130,10 +112,10 @@ impl<'a> EncryptionScheme<'a> {
password: impl AsRef<[u8]>,
buffer: &'b mut [u8],
pos: usize,
) -> Result<&'b [u8], CryptoError> {
) -> Result<&'b [u8]> {
match self {
Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos),
_ => Err(CryptoError),
Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
}
}

Expand Down Expand Up @@ -199,7 +181,7 @@ impl<'a> From<pbes2::Parameters<'a>> for EncryptionScheme<'a> {
}

impl<'a> TryFrom<AlgorithmIdentifier<'a>> for EncryptionScheme<'a> {
type Error = Error;
type Error = der::Error;

fn try_from(alg: AlgorithmIdentifier<'a>) -> der::Result<EncryptionScheme<'_>> {
match alg.oid {
Expand All @@ -210,7 +192,7 @@ impl<'a> TryFrom<AlgorithmIdentifier<'a>> for EncryptionScheme<'a> {
}

impl<'a> TryFrom<&'a [u8]> for EncryptionScheme<'a> {
type Error = Error;
type Error = der::Error;

fn try_from(bytes: &'a [u8]) -> der::Result<EncryptionScheme<'a>> {
AlgorithmIdentifier::try_from(bytes).and_then(TryInto::try_into)
Expand Down
6 changes: 3 additions & 3 deletions pkcs5/src/pbes1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! [RFC 8018 Section 6.1]: https://tools.ietf.org/html/rfc8018#section-6.1

use crate::{AlgorithmIdentifier, Error};
use crate::AlgorithmIdentifier;
use core::convert::{TryFrom, TryInto};
use der::{
asn1::{ObjectIdentifier, OctetString},
Expand Down Expand Up @@ -105,7 +105,7 @@ impl Tagged for Parameters {
}

impl<'a> TryFrom<AlgorithmIdentifier<'a>> for Parameters {
type Error = Error;
type Error = der::Error;

fn try_from(alg: AlgorithmIdentifier<'a>) -> der::Result<Self> {
// Ensure that we have a supported PBES1 algorithm identifier
Expand Down Expand Up @@ -155,7 +155,7 @@ pub enum EncryptionScheme {
}

impl TryFrom<ObjectIdentifier> for EncryptionScheme {
type Error = Error;
type Error = der::Error;

fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
match oid {
Expand Down
45 changes: 22 additions & 23 deletions pkcs5/src/pbes2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ pub use self::kdf::{
PBKDF2_OID, SCRYPT_OID,
};

use crate::{AlgorithmIdentifier, CryptoError};
use crate::{AlgorithmIdentifier, Error, Result};
use core::convert::{TryFrom, TryInto};
use der::{
asn1::{Any, ObjectIdentifier, OctetString},
Decodable, Decoder, Encodable, Encoder, Error, ErrorKind, Length, Message,
Decodable, Decoder, Encodable, Encoder, ErrorKind, Length, Message,
};

#[cfg(all(feature = "alloc", feature = "pbes2"))]
Expand Down Expand Up @@ -78,10 +78,10 @@ impl<'a> Parameters<'a> {
/// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based
/// key derivation function and AES-128-CBC as the symmetric cipher.
pub fn pbkdf2_sha256_aes128cbc(
pbkdf2_iterations: u16,
pbkdf2_iterations: u32,
pbkdf2_salt: &'a [u8],
aes_iv: &'a [u8; AES_BLOCK_SIZE],
) -> Result<Self, CryptoError> {
) -> Result<Self> {
let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into();
let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv };
Ok(Self { kdf, encryption })
Expand All @@ -90,10 +90,10 @@ impl<'a> Parameters<'a> {
/// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based
/// key derivation function and AES-256-CBC as the symmetric cipher.
pub fn pbkdf2_sha256_aes256cbc(
pbkdf2_iterations: u16,
pbkdf2_iterations: u32,
pbkdf2_salt: &'a [u8],
aes_iv: &'a [u8; AES_BLOCK_SIZE],
) -> Result<Self, CryptoError> {
) -> Result<Self> {
let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into();
let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv };
Ok(Self { kdf, encryption })
Expand All @@ -110,7 +110,7 @@ impl<'a> Parameters<'a> {
params: scrypt::Params,
salt: &'a [u8],
aes_iv: &'a [u8; AES_BLOCK_SIZE],
) -> Result<Self, CryptoError> {
) -> Result<Self> {
let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv };
Ok(Self { kdf, encryption })
Expand All @@ -130,7 +130,7 @@ impl<'a> Parameters<'a> {
params: scrypt::Params,
salt: &'a [u8],
aes_iv: &'a [u8; AES_BLOCK_SIZE],
) -> Result<Self, CryptoError> {
) -> Result<Self> {
let kdf = ScryptParams::from_params_and_salt(params, salt)?.into();
let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv };
Ok(Self { kdf, encryption })
Expand All @@ -141,11 +141,7 @@ impl<'a> Parameters<'a> {
#[cfg(all(feature = "alloc", feature = "pbes2"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg_attr(docsrs, doc(cfg(feature = "pbes2")))]
pub fn decrypt(
&self,
password: impl AsRef<[u8]>,
ciphertext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
let mut buffer = ciphertext.to_vec();
let pt_len = self.decrypt_in_place(password, &mut buffer)?.len();
buffer.truncate(pt_len);
Expand All @@ -164,7 +160,7 @@ impl<'a> Parameters<'a> {
&self,
password: impl AsRef<[u8]>,
buffer: &'b mut [u8],
) -> Result<&'b [u8], CryptoError> {
) -> Result<&'b [u8]> {
encryption::decrypt_in_place(self, password, buffer)
}

Expand All @@ -173,11 +169,7 @@ impl<'a> Parameters<'a> {
#[cfg(all(feature = "alloc", feature = "pbes2"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg_attr(docsrs, doc(cfg(feature = "pbes2")))]
pub fn encrypt(
&self,
password: impl AsRef<[u8]>,
plaintext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
// TODO(tarcieri): support non-AES ciphers?
let mut buffer = Vec::with_capacity(plaintext.len() + AES_BLOCK_SIZE);
buffer.extend_from_slice(plaintext);
Expand All @@ -201,7 +193,7 @@ impl<'a> Parameters<'a> {
password: impl AsRef<[u8]>,
buffer: &'b mut [u8],
pos: usize,
) -> Result<&'b [u8], CryptoError> {
) -> Result<&'b [u8]> {
encryption::encrypt_in_place(self, password, buffer, pos)
}
}
Expand All @@ -222,7 +214,7 @@ impl<'a> Message<'a> for Parameters<'a> {
}

impl<'a> TryFrom<Any<'a>> for Parameters<'a> {
type Error = Error;
type Error = der::Error;

fn try_from(any: Any<'a>) -> der::Result<Self> {
any.sequence(|params| {
Expand Down Expand Up @@ -300,6 +292,13 @@ impl<'a> EncryptionScheme<'a> {
Self::DesEde3Cbc { .. } => DES_EDE3_CBC_OID,
}
}

/// Convenience function to turn the OID (see [`oid`](Self::oid))
/// of this [`EncryptionScheme`] into error case
/// [`Error::AlgorithmParametersInvalid`]
pub fn to_alg_params_invalid(&self) -> Error {
Error::AlgorithmParametersInvalid { oid: self.oid() }
}
}

impl<'a> Decodable<'a> for EncryptionScheme<'a> {
Expand All @@ -309,7 +308,7 @@ impl<'a> Decodable<'a> for EncryptionScheme<'a> {
}

impl<'a> TryFrom<AlgorithmIdentifier<'a>> for EncryptionScheme<'a> {
type Error = Error;
type Error = der::Error;

fn try_from(alg: AlgorithmIdentifier<'a>) -> der::Result<Self> {
// TODO(tarcieri): support for non-AES algorithms?
Expand Down Expand Up @@ -349,7 +348,7 @@ impl<'a> TryFrom<AlgorithmIdentifier<'a>> for EncryptionScheme<'a> {
}

impl<'a> TryFrom<EncryptionScheme<'a>> for AlgorithmIdentifier<'a> {
type Error = Error;
type Error = der::Error;

fn try_from(scheme: EncryptionScheme<'a>) -> der::Result<Self> {
let parameters = OctetString::new(match scheme {
Expand Down
Loading