extern crate alloc;
use alloc::format;
use alloc::vec;
use alloc::vec::Vec;
use mbedtls::cipher::raw::{CipherId, CipherMode};
use mbedtls::cipher::{Cipher, Decryption, Traditional};
use mbedtls::hash::pbkdf2_hmac;
use mbedtls::hash::Type as MdType;
use pkcs8::PrivateKeyInfoRef;
use crate::crypto::gmssl_pkcs8_parse::parse_gmssl_encrypted_pkcs8_der;
use crate::crypto::CryptoError;
fn map_cipher_err(e: mbedtls::Error) -> CryptoError {
CryptoError::Message(alloc::format!("mbedtls cipher: {e:?}"))
}
fn pbkdf2_hmac_sm3(
password: &[u8],
salt: &[u8],
iterations: usize,
out_len: usize,
) -> Result<Vec<u8>, CryptoError> {
if iterations > u32::MAX as usize {
return Err(CryptoError::InvalidInput);
}
let mut out = vec![0u8; out_len];
pbkdf2_hmac(MdType::SM3, password, salt, iterations as u32, &mut out)
.map_err(map_cipher_err)?;
Ok(out)
}
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 cipher = Cipher::<Decryption, Traditional, _>::new(CipherId::SM4, CipherMode::CBC, 128)
.map_err(map_cipher_err)?;
let c = cipher
.set_key_iv(&dk, params.iv)
.map_err(map_cipher_err)?;
let mut plain = vec![0u8; params.enc_data.len() + c.block_size()];
let (len, _) = c
.decrypt(params.enc_data, &mut plain)
.map_err(map_cipher_err)?;
plain.truncate(len);
PrivateKeyInfoRef::try_from(plain.as_slice())
.map_err(|e| CryptoError::Message(format!("pkcs8: {e}")))?;
Ok(plain)
}