quantcrypt/asn1/
private_key.rsuse der::{Decode, Encode};
use pem::EncodeConfig;
use pkcs8::spki::{self, AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier};
use pkcs8::ObjectIdentifier;
use pkcs8::{spki::AlgorithmIdentifier, PrivateKeyInfo};
use crate::asn1::asn_util::{is_composite_kem_or_dsa_oid, is_valid_kem_or_dsa_oid};
use crate::asn1::signature::DsaSignature;
use crate::dsa::common::dsa_trait::Dsa;
use crate::dsa::dsa_manager::DsaManager;
use crate::kem::common::kem_trait::Kem;
use crate::kem::kem_manager::KemManager;
use crate::oid_mapper::map_to_new_oid;
use crate::{asn1::composite_private_key::CompositePrivateKey, errors};
use crate::{keys::PublicKey, QuantCryptError};
use signature::{Keypair, Signer};
use crate::asn1::asn_util::is_dsa_oid;
type Result<T> = std::result::Result<T, QuantCryptError>;
pub struct PrivateKey {
oid: String,
private_key: Vec<u8>,
is_composite: bool,
public_key: Option<PublicKey>,
}
impl Signer<DsaSignature> for PrivateKey {
fn try_sign(&self, tbs: &[u8]) -> core::result::Result<DsaSignature, signature::Error> {
let sm = self.sign(tbs).map_err(|_| signature::Error::new())?;
Ok(DsaSignature(sm))
}
}
impl Keypair for PrivateKey {
type VerifyingKey = PublicKey;
fn verifying_key(&self) -> <Self as Keypair>::VerifyingKey {
self.public_key.clone().unwrap()
}
}
impl DynSignatureAlgorithmIdentifier for PrivateKey {
fn signature_algorithm_identifier(
&self,
) -> core::result::Result<AlgorithmIdentifier<der::Any>, spki::Error> {
let oid: ObjectIdentifier = self.oid.parse().map_err(|_| spki::Error::KeyMalformed)?;
let spki_algorithm = AlgorithmIdentifierOwned {
oid,
parameters: None,
};
Ok(spki_algorithm)
}
}
impl PrivateKey {
pub(crate) fn new(oid: &str, key: &[u8], public_key: Option<PublicKey>) -> Result<Self> {
if !is_valid_kem_or_dsa_oid(&oid.to_string()) {
return Err(errors::QuantCryptError::InvalidPrivateKey);
}
let is_composite = is_composite_kem_or_dsa_oid(oid);
Ok(Self {
oid: oid.to_string(),
private_key: key.to_vec(),
is_composite,
public_key,
})
}
pub fn from_composite(
public_key: Option<PublicKey>,
composite_sk: &CompositePrivateKey,
) -> Result<Self> {
Ok(Self {
oid: composite_sk.get_oid().to_string(),
private_key: composite_sk
.to_der()
.map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?,
is_composite: true,
public_key,
})
}
pub fn get_oid(&self) -> &str {
&self.oid
}
#[cfg(test)]
fn get_key(&self) -> &[u8] {
&self.private_key
}
pub fn get_public_key(&self) -> Option<&PublicKey> {
self.public_key.as_ref()
}
pub fn is_composite(&self) -> bool {
self.is_composite
}
pub fn to_der(&self) -> Result<Vec<u8>> {
let pub_key = self.public_key.as_ref().map(|pk| pk.get_key());
let oid: ObjectIdentifier = self
.oid
.parse()
.map_err(|_| QuantCryptError::InvalidPrivateKey)?;
let priv_key_info = PrivateKeyInfo {
algorithm: AlgorithmIdentifier {
oid,
parameters: None,
},
private_key: &self.private_key,
public_key: pub_key,
};
Ok(priv_key_info
.to_der()
.map_err(|_| errors::QuantCryptError::InvalidPrivateKey))?
}
pub fn to_pem(&self) -> Result<String> {
let der = self
.to_der()
.map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
let pem_obj = pem::Pem::new("PRIVATE KEY", der);
let encode_conf = EncodeConfig::default().set_line_ending(pem::LineEnding::LF);
Ok(pem::encode_config(&pem_obj, encode_conf))
}
pub fn from_pem(pem: &str) -> Result<Self> {
let pem = pem::parse(pem).map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
if pem.tag() != "PRIVATE KEY" {
return Err(errors::QuantCryptError::InvalidPrivateKey);
}
let der = pem.contents();
Self::from_der(der)
}
pub fn from_der(der: &[u8]) -> Result<Self> {
let priv_key_info = PrivateKeyInfo::from_der(der)
.map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
let oid = map_to_new_oid(&priv_key_info.algorithm.oid.to_string());
if !is_valid_kem_or_dsa_oid(&oid) {
return Err(errors::QuantCryptError::InvalidPrivateKey);
}
let is_composite = is_composite_kem_or_dsa_oid(&oid);
let public_key = if let Some(pk) = priv_key_info.public_key {
Some(PublicKey::new(&oid, pk)?)
} else {
None
};
Ok(Self {
oid: oid.to_string(),
private_key: priv_key_info.private_key.to_vec(),
is_composite,
public_key,
})
}
pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
if !is_dsa_oid(&self.oid) {
return Err(errors::QuantCryptError::UnsupportedOperation);
}
let dsa = DsaManager::new_from_oid(&self.oid)?;
let sig = dsa.sign(&self.private_key, data)?;
Ok(sig)
}
pub(crate) fn decap(&self, ct: &[u8]) -> Result<Vec<u8>> {
if is_dsa_oid(&self.oid) {
return Err(errors::QuantCryptError::UnsupportedOperation);
}
let kem = KemManager::new_from_oid(&self.oid)?;
let ss = kem.decap(&self.private_key, ct)?;
Ok(ss)
}
pub fn from_file(path: &str) -> Result<Self> {
let contents = std::fs::read(path).map_err(|_| QuantCryptError::FileReadError)?;
let result = PrivateKey::from_der(&contents);
if let Ok(sk) = result {
Ok(sk)
} else {
let pem =
std::str::from_utf8(&contents).map_err(|_| QuantCryptError::InvalidCertificate)?;
if let Ok(sk) = PrivateKey::from_pem(pem) {
Ok(sk)
} else {
Err(QuantCryptError::InvalidPrivateKey)
}
}
}
}
#[cfg(test)]
mod test {
use crate::dsa::common::config::oids::Oid;
use crate::dsa::common::dsa_type::DsaType;
use super::*;
#[test]
fn test_composite_private_key() {
let pem_bytes = include_bytes!("../../test/data/mldsa44_ecdsa_p256_sha256_sk.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem).unwrap();
assert!(pk.public_key.is_none());
assert!(pk.is_composite());
assert_eq!(pk.get_oid(), DsaType::MlDsa44EcdsaP256SHA256.get_oid());
let key_bytes = pk.get_key();
let pk2 = CompositePrivateKey::from_der(&pk.oid, &key_bytes).unwrap();
assert_eq!(pk.oid, pk2.get_oid());
let pk2 = PrivateKey::from_composite(pk.public_key, &pk2).unwrap();
let pem2 = pk2.to_pem().unwrap();
assert_eq!(pem, pem2.trim());
let oid = DsaType::MlDsa44EcdsaP256SHA256.get_oid();
assert_eq!(pk.oid, oid);
}
#[test]
fn test_pk_no_headers() {
let pem_bytes = include_bytes!("../../test/data/bad/no_headers.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem);
assert!(pk.is_err());
assert!(matches!(
pk.err().unwrap(),
errors::QuantCryptError::InvalidPrivateKey
));
}
#[test]
fn test_pk_bad_base64() {
let pem_bytes = include_bytes!("../../test/data/bad/bad_base64.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem);
assert!(pk.is_err());
assert!(matches!(
pk.err().unwrap(),
errors::QuantCryptError::InvalidPrivateKey
));
}
#[test]
fn test_pk_empty() {
let pem_bytes = include_bytes!("../../test/data/bad/empty.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem);
assert!(pk.is_err());
assert!(matches!(
pk.err().unwrap(),
errors::QuantCryptError::InvalidPrivateKey
));
}
#[test]
fn test_pk_bad_tag() {
let pem_bytes = include_bytes!("../../test/data/bad/bad_tag.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem);
assert!(pk.is_err());
assert!(matches!(
pk.err().unwrap(),
errors::QuantCryptError::InvalidPrivateKey
));
}
#[test]
fn test_pk_bad_algorithm() {
let pem_bytes = include_bytes!("../../test/data/bad/private_rsa_2048.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem);
assert!(pk.is_err());
assert!(matches!(
pk.err().unwrap(),
errors::QuantCryptError::InvalidPrivateKey
));
}
#[test]
fn test_sk_serialization_deserialization() {
let pem_bytes = include_bytes!("../../test/data/mldsa44_ecdsa_p256_sha256_sk.pem");
let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
let pk = PrivateKey::from_pem(pem).unwrap();
let der = pk.to_der().unwrap();
let pk2 = PrivateKey::from_der(&der).unwrap();
let pem2 = pk2.to_pem().unwrap();
assert_eq!(pem.trim(), pem2.trim());
let der2 = pk2.to_der().unwrap();
assert_eq!(der, der2);
}
#[test]
fn test_sk_containing_pk() {
let (pk, sk) = DsaManager::new(DsaType::MlDsa44)
.unwrap()
.key_gen()
.unwrap();
let pk = PublicKey::new(&DsaType::MlDsa44.get_oid(), &pk).unwrap();
let sk = PrivateKey::new(&DsaType::MlDsa44.get_oid(), &sk, Some(pk.clone())).unwrap();
let sk_der = sk.to_der().unwrap();
let sk2 = PrivateKey::from_der(&sk_der).unwrap();
let pk2 = sk2.get_public_key().unwrap();
assert_eq!(pk.get_key(), pk2.get_key());
assert_eq!(
sk.get_public_key().unwrap().get_key(),
sk2.get_public_key().unwrap().get_key()
);
}
}