extern crate alloc;
use alloc::format;
use alloc::vec::Vec;
use cipher::block_padding::Pkcs7;
use cipher::{BlockModeDecrypt, KeyIvInit};
use hmac::Hmac;
use pbkdf2::pbkdf2;
use sm3::Sm3;
use crate::crypto::gmssl_pkcs8_parse::parse_gmssl_encrypted_pkcs8_der;
use crate::crypto::CryptoError;
type Sm4CbcDec = cbc::Decryptor<sm4::Sm4>;
type HmacSm3 = Hmac<Sm3>;
fn pbkdf2_hmac_sm3(
password: &[u8],
salt: &[u8],
iterations: usize,
dk_len: usize,
) -> Result<Vec<u8>, CryptoError> {
if iterations == 0 || dk_len == 0 {
return Err(CryptoError::InvalidInput);
}
let iterations: u32 = iterations
.try_into()
.map_err(|_| CryptoError::InvalidInput)?;
let mut dk = vec![0u8; dk_len];
pbkdf2::<HmacSm3>(password, salt, iterations, &mut dk)
.map_err(|_| CryptoError::InvalidInput)?;
Ok(dk)
}
fn sm4_cbc_decrypt(key: &[u8], iv: &[u8], enc_data: &[u8]) -> Result<Vec<u8>, CryptoError> {
let mut buf = enc_data.to_vec();
let cipher = Sm4CbcDec::new_from_slices(key, iv)
.map_err(|_| CryptoError::InvalidInput)?;
let plain = cipher
.decrypt_padded::<Pkcs7>(&mut buf)
.map_err(|_| CryptoError::InvalidInput)?;
let plain_len = plain.len();
Ok(buf[..plain_len].to_vec())
}
pub fn decrypt_gmssl_encrypted_pkcs8_der(enc_der: &[u8], pass: &str) -> Result<Vec<u8>, CryptoError> {
let params = parse_gmssl_encrypted_pkcs8_der(enc_der)?;
let dk = pbkdf2_hmac_sm3(
pass.as_bytes(),
params.salt,
params.iterations,
params.dk_len,
)?;
let plain = sm4_cbc_decrypt(&dk, params.iv, params.enc_data)?;
pkcs8::PrivateKeyInfoRef::try_from(plain.as_slice())
.map_err(|e| CryptoError::Message(format!("pkcs8: {e}")))?;
Ok(plain)
}