aboutsummaryrefslogtreecommitdiffstats
path: root/src/cipherstring.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cipherstring.rs')
-rw-r--r--src/cipherstring.rs118
1 files changed, 80 insertions, 38 deletions
diff --git a/src/cipherstring.rs b/src/cipherstring.rs
index 39254c7..883cb34 100644
--- a/src/cipherstring.rs
+++ b/src/cipherstring.rs
@@ -1,10 +1,11 @@
use crate::prelude::*;
-use block_modes::BlockMode as _;
-use block_padding::Padding as _;
-use hmac::{Mac as _, NewMac as _};
+use aes::cipher::{
+ BlockDecryptMut as _, BlockEncryptMut as _, KeyIvInit as _,
+};
+use hmac::Mac as _;
+use pkcs8::DecodePrivateKey as _;
use rand::RngCore as _;
-use rsa::pkcs8::FromPrivateKey as _;
use zeroize::Zeroize as _;
pub enum CipherString {
@@ -51,15 +52,15 @@ impl CipherString {
});
}
- let iv = base64::decode(parts[0])
+ let iv = crate::base64::decode(parts[0])
.map_err(|source| Error::InvalidBase64 { source })?;
- let ciphertext = base64::decode(parts[1])
+ let ciphertext = crate::base64::decode(parts[1])
.map_err(|source| Error::InvalidBase64 { source })?;
let mac =
if parts.len() > 2 {
- Some(base64::decode(parts[2]).map_err(|source| {
- Error::InvalidBase64 { source }
- })?)
+ Some(crate::base64::decode(parts[2]).map_err(
+ |source| Error::InvalidBase64 { source },
+ )?)
} else {
None
};
@@ -76,7 +77,7 @@ impl CipherString {
// https://github.com/bitwarden/jslib/blob/785b681f61f81690de6df55159ab07ae710bcfad/src/enums/encryptionType.ts#L8
// format is: <cipher_text_b64>|<hmac_sig>
let contents = contents.split('|').next().unwrap();
- let ciphertext = base64::decode(contents)
+ let ciphertext = crate::base64::decode(contents)
.map_err(|source| Error::InvalidBase64 { source })?;
Ok(Self::Asymmetric { ciphertext })
}
@@ -98,12 +99,12 @@ impl CipherString {
) -> Result<Self> {
let iv = random_iv();
- let cipher = block_modes::Cbc::<
- aes::Aes256,
- block_modes::block_padding::Pkcs7,
- >::new_from_slices(keys.enc_key(), &iv)
- .map_err(|source| Error::CreateBlockMode { source })?;
- let ciphertext = cipher.encrypt_vec(plaintext);
+ let cipher = cbc::Encryptor::<aes::Aes256>::new(
+ keys.enc_key().into(),
+ iv.as_slice().into(),
+ );
+ let ciphertext =
+ cipher.encrypt_padded_vec_mut::<block_padding::Pkcs7>(plaintext);
let mut digest =
hmac::Hmac::<sha2::Sha256>::new_from_slice(keys.mac_key())
@@ -136,7 +137,7 @@ impl CipherString {
mac.as_deref(),
)?;
cipher
- .decrypt_vec(ciphertext)
+ .decrypt_padded_vec_mut::<block_padding::Pkcs7>(ciphertext)
.map_err(|source| Error::Decrypt { source })
} else {
Err(Error::InvalidCipherString {
@@ -166,7 +167,7 @@ impl CipherString {
mac.as_deref(),
)?;
cipher
- .decrypt(res.data_mut())
+ .decrypt_padded_mut::<block_padding::Pkcs7>(res.data_mut())
.map_err(|source| Error::Decrypt { source })?;
Ok(res)
} else {
@@ -184,15 +185,12 @@ impl CipherString {
) -> Result<crate::locked::Vec> {
if let Self::Asymmetric { ciphertext } = self {
let privkey_data = private_key.private_key();
- let privkey_data = block_padding::Pkcs7::unpad(privkey_data)
- .map_err(|_| Error::Padding)?;
+ let privkey_data =
+ pkcs7_unpad(privkey_data).ok_or(Error::Padding)?;
let pkey = rsa::RsaPrivateKey::from_pkcs8_der(privkey_data)
.map_err(|source| Error::RsaPkcs8 { source })?;
let mut bytes = pkey
- .decrypt(
- rsa::padding::PaddingScheme::new_oaep::<sha1::Sha1>(),
- ciphertext,
- )
+ .decrypt(rsa::Oaep::new::<sha1::Sha1>(), ciphertext)
.map_err(|source| Error::Rsa { source })?;
// XXX it'd be great if the rsa crate would let us decrypt
@@ -218,8 +216,7 @@ fn decrypt_common_symmetric(
iv: &[u8],
ciphertext: &[u8],
mac: Option<&[u8]>,
-) -> Result<block_modes::Cbc<aes::Aes256, block_modes::block_padding::Pkcs7>>
-{
+) -> Result<cbc::Decryptor<aes::Aes256>> {
if let Some(mac) = mac {
let mut key =
hmac::Hmac::<sha2::Sha256>::new_from_slice(keys.mac_key())
@@ -227,15 +224,12 @@ fn decrypt_common_symmetric(
key.update(iv);
key.update(ciphertext);
- if key.verify(mac).is_err() {
+ if key.verify(mac.into()).is_err() {
return Err(Error::InvalidMac);
}
}
- block_modes::Cbc::<
- aes::Aes256,
- block_modes::block_padding::Pkcs7,
- >::new_from_slices(keys.enc_key(), iv)
+ cbc::Decryptor::<aes::Aes256>::new_from_slices(keys.enc_key(), iv)
.map_err(|source| Error::CreateBlockMode { source })
}
@@ -247,18 +241,18 @@ impl std::fmt::Display for CipherString {
ciphertext,
mac,
} => {
- let iv = base64::encode(&iv);
- let ciphertext = base64::encode(&ciphertext);
+ let iv = crate::base64::encode(iv);
+ let ciphertext = crate::base64::encode(ciphertext);
if let Some(mac) = &mac {
- let mac = base64::encode(&mac);
- write!(f, "2.{}|{}|{}", iv, ciphertext, mac)
+ let mac = crate::base64::encode(mac);
+ write!(f, "2.{iv}|{ciphertext}|{mac}")
} else {
- write!(f, "2.{}|{}", iv, ciphertext)
+ write!(f, "2.{iv}|{ciphertext}")
}
}
Self::Asymmetric { ciphertext } => {
- let ciphertext = base64::encode(&ciphertext);
- write!(f, "4.{}", ciphertext)
+ let ciphertext = crate::base64::encode(ciphertext);
+ write!(f, "4.{ciphertext}")
}
}
}
@@ -270,3 +264,51 @@ fn random_iv() -> Vec<u8> {
rng.fill_bytes(&mut iv);
iv
}
+
+// XXX this should ideally just be block_padding::Pkcs7::unpad, but i can't
+// figure out how to get the generic types to work out
+fn pkcs7_unpad(b: &[u8]) -> Option<&[u8]> {
+ if b.is_empty() {
+ return None;
+ }
+
+ let padding_val = b[b.len() - 1];
+ if padding_val == 0 {
+ return None;
+ }
+
+ let padding_len = usize::from(padding_val);
+ if padding_len > b.len() {
+ return None;
+ }
+
+ for c in b.iter().copied().skip(b.len() - padding_len) {
+ if c != padding_val {
+ return None;
+ }
+ }
+
+ Some(&b[..b.len() - padding_len])
+}
+
+#[test]
+fn test_pkcs7_unpad() {
+ let tests = [
+ (&[][..], None),
+ (&[0x01][..], Some(&[][..])),
+ (&[0x02, 0x02][..], Some(&[][..])),
+ (&[0x03, 0x03, 0x03][..], Some(&[][..])),
+ (&[0x69, 0x01][..], Some(&[0x69][..])),
+ (&[0x69, 0x02, 0x02][..], Some(&[0x69][..])),
+ (&[0x69, 0x03, 0x03, 0x03][..], Some(&[0x69][..])),
+ (&[0x02][..], None),
+ (&[0x03][..], None),
+ (&[0x69, 0x69, 0x03, 0x03][..], None),
+ (&[0x00][..], None),
+ (&[0x02, 0x00][..], None),
+ ];
+ for (input, expected) in tests {
+ let got = pkcs7_unpad(input);
+ assert_eq!(got, expected);
+ }
+}