Skip to content

Commit f198bcc

Browse files
Merge pull request #172 from bilelmoussaoui/bilelmoussaoui/crypto-fail
client: Don't panic if a cryptography operation fails
2 parents 1bba4ad + fbe1cb4 commit f198bcc

22 files changed

+337
-183
lines changed

client/src/crypto/error.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/// Cryptography specific errors.
2+
#[derive(Debug)]
3+
pub enum Error {
4+
#[cfg(feature = "openssl_crypto")]
5+
Openssl(openssl::error::ErrorStack),
6+
#[cfg(feature = "native_crypto")]
7+
PadError(cipher::inout::PadError),
8+
#[cfg(feature = "native_crypto")]
9+
UnpadError(cipher::block_padding::UnpadError),
10+
}
11+
12+
#[cfg(feature = "openssl_crypto")]
13+
impl From<openssl::error::ErrorStack> for Error {
14+
fn from(value: openssl::error::ErrorStack) -> Self {
15+
Self::Openssl(value)
16+
}
17+
}
18+
19+
#[cfg(feature = "native_crypto")]
20+
impl From<cipher::block_padding::UnpadError> for Error {
21+
fn from(value: cipher::block_padding::UnpadError) -> Self {
22+
Self::UnpadError(value)
23+
}
24+
}
25+
26+
#[cfg(feature = "native_crypto")]
27+
impl From<cipher::inout::PadError> for Error {
28+
fn from(value: cipher::inout::PadError) -> Self {
29+
Self::PadError(value)
30+
}
31+
}
32+
33+
impl std::error::Error for Error {
34+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
35+
match self {
36+
#[cfg(feature = "openssl_crypto")]
37+
Self::Openssl(e) => Some(e),
38+
#[cfg(feature = "native_crypto")]
39+
Self::UnpadError(_) | Self::PadError(_) => None,
40+
}
41+
}
42+
}
43+
44+
impl std::fmt::Display for Error {
45+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46+
match self {
47+
#[cfg(feature = "openssl_crypto")]
48+
Self::Openssl(e) => f.write_fmt(format_args!("Openssl error: {e}")),
49+
#[cfg(feature = "native_crypto")]
50+
Self::UnpadError(e) => f.write_fmt(format_args!("Wrong padding error: {e}")),
51+
#[cfg(feature = "native_crypto")]
52+
Self::PadError(e) => f.write_fmt(format_args!("Wrong padding error: {e}")),
53+
}
54+
}
55+
}

client/src/crypto/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ pub(crate) use native::*;
77
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
88
pub use native::*;
99

10+
mod error;
11+
pub use error::Error;
12+
1013
#[cfg(feature = "openssl_crypto")]
1114
mod openssl;
1215
#[cfg(all(feature = "openssl_crypto", not(feature = "unstable")))]
@@ -33,10 +36,10 @@ mod test {
3336
78, 82, 67, 158, 214, 102, 48, 109, 84, 107, 94, 54, 225, 29, 186, 246,
3437
];
3538

36-
let encrypted = encrypt(data, &aes_key, aes_iv);
39+
let encrypted = encrypt(data, &aes_key, aes_iv).unwrap();
3740
assert_eq!(encrypted, expected_encrypted);
3841

39-
let decrypted = decrypt(&encrypted, &aes_key, aes_iv);
42+
let decrypted = decrypt(&encrypted, &aes_key, aes_iv).unwrap();
4043
assert_eq!(decrypted.to_vec(), data);
4144
}
4245

@@ -53,7 +56,7 @@ mod test {
5356
let salt = &[0x92, 0xf4, 0xc0, 0x34, 0x0f, 0x5f, 0x36, 0xf9];
5457
let iteration_count = 1782;
5558
let password = b"test";
56-
let (key, iv) = legacy_derive_key_and_iv(password, Ok(()), salt, iteration_count);
59+
let (key, iv) = legacy_derive_key_and_iv(password, Ok(()), salt, iteration_count).unwrap();
5760
assert_eq!(key.as_ref(), &expected_key[..]);
5861
assert_eq!(iv, &expected_iv[..]);
5962
}

client/src/crypto/native.rs

+39-30
Original file line numberDiff line numberDiff line change
@@ -22,69 +22,74 @@ type EncAlg = cbc::Encryptor<aes::Aes128>;
2222
type DecAlg = cbc::Decryptor<aes::Aes128>;
2323
type MacAlg = hmac::Hmac<sha2::Sha256>;
2424

25-
pub fn encrypt(data: impl AsRef<[u8]>, key: &Key, iv: impl AsRef<[u8]>) -> Vec<u8> {
25+
pub fn encrypt(
26+
data: impl AsRef<[u8]>,
27+
key: &Key,
28+
iv: impl AsRef<[u8]>,
29+
) -> Result<Vec<u8>, super::Error> {
2630
let mut blob = vec![0; data.as_ref().len() + EncAlg::block_size()];
2731

2832
// Unwrapping since adding `CIPHER_BLOCK_SIZE` to array is enough space for
2933
// PKCS7
3034
let encrypted_len = EncAlg::new_from_slices(key.as_ref(), iv.as_ref())
3135
.expect("Invalid key length")
32-
.encrypt_padded_b2b_mut::<Pkcs7>(data.as_ref(), &mut blob)
33-
.unwrap()
36+
.encrypt_padded_b2b_mut::<Pkcs7>(data.as_ref(), &mut blob)?
3437
.len();
3538

3639
blob.truncate(encrypted_len);
3740

38-
blob
41+
Ok(blob)
3942
}
4043

41-
pub fn decrypt(blob: impl AsRef<[u8]>, key: &Key, iv: impl AsRef<[u8]>) -> Zeroizing<Vec<u8>> {
44+
pub fn decrypt(
45+
blob: impl AsRef<[u8]>,
46+
key: &Key,
47+
iv: impl AsRef<[u8]>,
48+
) -> Result<Zeroizing<Vec<u8>>, super::Error> {
4249
let mut data = blob.as_ref().to_vec();
4350

44-
DecAlg::new_from_slices(key.as_ref(), iv.as_ref())
51+
Ok(DecAlg::new_from_slices(key.as_ref(), iv.as_ref())
4552
.expect("Invalid key length")
46-
.decrypt_padded_mut::<Pkcs7>(&mut data)
47-
.unwrap()
53+
.decrypt_padded_mut::<Pkcs7>(&mut data)?
4854
.to_vec()
49-
.into()
55+
.into())
5056
}
5157

5258
pub(crate) fn decrypt_no_padding(
5359
blob: impl AsRef<[u8]>,
5460
key: &Key,
5561
iv: impl AsRef<[u8]>,
56-
) -> Zeroizing<Vec<u8>> {
62+
) -> Result<Zeroizing<Vec<u8>>, super::Error> {
5763
let mut data = blob.as_ref().to_vec();
5864

59-
DecAlg::new_from_slices(key.as_ref(), iv.as_ref())
65+
Ok(DecAlg::new_from_slices(key.as_ref(), iv.as_ref())
6066
.expect("Invalid key length")
61-
.decrypt_padded_mut::<NoPadding>(&mut data)
62-
.unwrap()
67+
.decrypt_padded_mut::<NoPadding>(&mut data)?
6368
.to_vec()
64-
.into()
69+
.into())
6570
}
6671

6772
pub(crate) fn iv_len() -> usize {
6873
DecAlg::iv_size()
6974
}
7075

71-
pub(crate) fn generate_private_key() -> Zeroizing<Vec<u8>> {
76+
pub(crate) fn generate_private_key() -> Result<Zeroizing<Vec<u8>>, super::Error> {
7277
let generic_array = EncAlg::generate_key(cipher::rand_core::OsRng);
73-
Zeroizing::new(generic_array.to_vec())
78+
Ok(Zeroizing::new(generic_array.to_vec()))
7479
}
7580

76-
pub(crate) fn generate_public_key(private_key: impl AsRef<[u8]>) -> Vec<u8> {
81+
pub(crate) fn generate_public_key(private_key: impl AsRef<[u8]>) -> Result<Vec<u8>, super::Error> {
7782
let private_key_uint = BigUint::from_bytes_be(private_key.as_ref());
7883
static DH_GENERATOR: LazyLock<BigUint> = LazyLock::new(|| BigUint::from_u64(0x2).unwrap());
7984
let public_key_uint = powm(&DH_GENERATOR, private_key_uint);
8085

81-
public_key_uint.to_bytes_be()
86+
Ok(public_key_uint.to_bytes_be())
8287
}
8388

8489
pub(crate) fn generate_aes_key(
8590
private_key: impl AsRef<[u8]>,
8691
server_public_key: impl AsRef<[u8]>,
87-
) -> Zeroizing<Vec<u8>> {
92+
) -> Result<Zeroizing<Vec<u8>>, super::Error> {
8893
let server_public_key_uint = BigUint::from_bytes_be(server_public_key.as_ref());
8994
let private_key_uint = BigUint::from_bytes_be(private_key.as_ref());
9095
let common_secret = powm(&server_public_key_uint, private_key_uint);
@@ -107,27 +112,31 @@ pub(crate) fn generate_aes_key(
107112
hk.expand(&info, okm.as_mut())
108113
.expect("hkdf expand should never fail");
109114

110-
okm
115+
Ok(okm)
111116
}
112117

113-
pub fn generate_iv() -> Vec<u8> {
114-
EncAlg::generate_iv(cipher::rand_core::OsRng).to_vec()
118+
pub fn generate_iv() -> Result<Vec<u8>, super::Error> {
119+
Ok(EncAlg::generate_iv(cipher::rand_core::OsRng).to_vec())
115120
}
116121

117122
pub(crate) fn mac_len() -> usize {
118123
MacAlg::output_size()
119124
}
120125

121-
pub(crate) fn compute_mac(data: impl AsRef<[u8]>, key: &Key) -> Vec<u8> {
126+
pub(crate) fn compute_mac(data: impl AsRef<[u8]>, key: &Key) -> Result<Vec<u8>, super::Error> {
122127
let mut mac = MacAlg::new_from_slice(key.as_ref()).unwrap();
123128
mac.update(data.as_ref());
124-
mac.finalize().into_bytes().to_vec()
129+
Ok(mac.finalize().into_bytes().to_vec())
125130
}
126131

127-
pub(crate) fn verify_mac(data: impl AsRef<[u8]>, key: &Key, expected: impl AsRef<[u8]>) -> bool {
132+
pub(crate) fn verify_mac(
133+
data: impl AsRef<[u8]>,
134+
key: &Key,
135+
expected: impl AsRef<[u8]>,
136+
) -> Result<bool, super::Error> {
128137
let mut mac = MacAlg::new_from_slice(key.as_ref()).unwrap();
129138
mac.update(data.as_ref());
130-
mac.verify_slice(expected.as_ref()).is_ok()
139+
Ok(mac.verify_slice(expected.as_ref()).is_ok())
131140
}
132141

133142
pub(crate) fn verify_checksum_md5(digest: impl AsRef<[u8]>, content: impl AsRef<[u8]>) -> bool {
@@ -141,7 +150,7 @@ pub(crate) fn derive_key(
141150
key_strength: Result<(), file::WeakKeyError>,
142151
salt: impl AsRef<[u8]>,
143152
iteration_count: usize,
144-
) -> Key {
153+
) -> Result<Key, super::Error> {
145154
let mut key = Key::new_with_strength(vec![0; EncAlg::block_size()], key_strength);
146155

147156
pbkdf2::pbkdf2::<hmac::Hmac<sha2::Sha256>>(
@@ -152,15 +161,15 @@ pub(crate) fn derive_key(
152161
)
153162
.expect("HMAC can be initialized with any key length");
154163

155-
key
164+
Ok(key)
156165
}
157166

158167
pub(crate) fn legacy_derive_key_and_iv(
159168
secret: impl AsRef<[u8]>,
160169
key_strength: Result<(), file::WeakKeyError>,
161170
salt: impl AsRef<[u8]>,
162171
iteration_count: usize,
163-
) -> (Key, Vec<u8>) {
172+
) -> Result<(Key, Vec<u8>), super::Error> {
164173
let mut buffer = vec![0; EncAlg::key_size() + EncAlg::iv_size()];
165174
let mut hasher = Sha256::new();
166175
let mut digest_buffer = vec![0; <Sha256 as Digest>::output_size()];
@@ -198,7 +207,7 @@ pub(crate) fn legacy_derive_key_and_iv(
198207
}
199208

200209
let iv = buffer.split_off(EncAlg::key_size());
201-
(Key::new_with_strength(buffer, key_strength), iv)
210+
Ok((Key::new_with_strength(buffer, key_strength), iv))
202211
}
203212

204213
/// from https://github.com/plietar/librespot/blob/master/core/src/util/mod.rs#L53

0 commit comments

Comments
 (0)