extern crate alloc;
use alloc::string::ToString;
use alloc::vec::Vec;
use num_bigint::BigUint;
use pkcs8::{EncryptedPrivateKeyInfoRef, PrivateKeyInfoRef};
use sec1::der::Decode;
use sec1::EcPrivateKey;
use crate::crypto::CryptoError;
pub fn sm2_pkcs8_clear_der_from_pem_with_pass(pem: &str, pass: &str) -> Result<Vec<u8>, CryptoError> {
for p in pem::parse_many(pem).map_err(|e| CryptoError::Message(e.to_string()))? {
match p.tag() {
"PRIVATE KEY" => return Ok(p.contents().to_vec()),
"ENCRYPTED PRIVATE KEY" => {
let der = p.contents();
return decrypt_encrypted_pkcs8_der(der, pass);
}
_ => {}
}
}
Err(CryptoError::Message(
"no PRIVATE KEY or ENCRYPTED PRIVATE KEY block in PEM".into(),
))
}
fn decrypt_encrypted_pkcs8_der(der: &[u8], pass: &str) -> Result<Vec<u8>, CryptoError> {
#[cfg(all(feature = "backend-mbedtls", not(feature = "backend-rustcrypto")))]
{
if let Ok(plain) =
crate::crypto::backend_mbedtls::gmssl_pkcs8::decrypt_gmssl_encrypted_pkcs8_der(der, pass)
{
return Ok(plain);
}
}
#[cfg(all(feature = "backend-rustcrypto", not(feature = "backend-mbedtls")))]
{
if let Ok(plain) =
crate::crypto::backend_rustcrypto::gmssl_pkcs8::decrypt_gmssl_encrypted_pkcs8_der(der, pass)
{
return Ok(plain);
}
}
let enc = EncryptedPrivateKeyInfoRef::try_from(der)
.map_err(|e| CryptoError::Message(alloc::format!("encrypted pkcs8: {e}")))?;
let doc = enc
.decrypt(pass.as_bytes())
.map_err(|e| CryptoError::Message(alloc::format!("pkcs8 decrypt: {e}")))?;
Ok(doc.as_bytes().to_vec())
}
pub fn sm2_scalar_from_pkcs8_der(der: &[u8]) -> Result<[u8; 32], CryptoError> {
let pk = PrivateKeyInfoRef::try_from(der)
.map_err(|e| CryptoError::Message(alloc::format!("pkcs8: {e}")))?;
scalar_from_sec1_ec_private_key(pk.private_key.as_bytes())
}
pub fn sm2_secret_from_pkcs8_pem_with_pass(pem: &str, pass: &str) -> Result<BigUint, CryptoError> {
let der = sm2_pkcs8_clear_der_from_pem_with_pass(pem, pass)?;
let scalar = sm2_scalar_from_pkcs8_der(&der)?;
Ok(BigUint::from_bytes_be(&scalar))
}
fn scalar_from_sec1_ec_private_key(sec1: &[u8]) -> Result<[u8; 32], CryptoError> {
let ec = EcPrivateKey::from_der(sec1)
.map_err(|e| CryptoError::Message(alloc::format!("sec1: {e}")))?;
if ec.private_key.len() != 32 {
return Err(CryptoError::Message(alloc::format!(
"expected 32-byte SM2 private OCTET STRING, got {}",
ec.private_key.len()
)));
}
let mut out = [0u8; 32];
out.copy_from_slice(ec.private_key);
Ok(out)
}
pub fn sm2_scalar_fixed32_be(n: &BigUint) -> Result<[u8; 32], CryptoError> {
let b = n.to_bytes_be();
if b.len() > 32 {
return Err(CryptoError::InvalidKey);
}
let mut out = [0u8; 32];
out[32 - b.len()..].copy_from_slice(&b);
Ok(out)
}