quantcrypt/asn1/
private_key.rs1use der::{Decode, Encode};
2use pem::EncodeConfig;
3use pkcs8::spki::{self, AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier};
4use pkcs8::ObjectIdentifier;
5use pkcs8::{spki::AlgorithmIdentifier, PrivateKeyInfo};
6
7use crate::asn1::asn_util::{is_composite_kem_or_dsa_oid, is_valid_kem_or_dsa_oid};
8use crate::asn1::signature::DsaSignature;
9use crate::dsa::common::dsa_trait::Dsa;
10use crate::dsa::dsa_manager::DsaManager;
11use crate::kem::common::kem_trait::Kem;
12use crate::kem::kem_manager::KemManager;
13use crate::{asn1::composite_private_key::CompositePrivateKey, errors};
14use crate::{keys::PublicKey, QuantCryptError};
15use signature::{Keypair, Signer};
16
17use crate::asn1::asn_util::is_dsa_oid;
18
19type Result<T> = std::result::Result<T, QuantCryptError>;
20pub struct PrivateKey {
22 oid: String,
24 private_key: Vec<u8>,
26 is_composite: bool,
28 public_key: Option<PublicKey>,
30}
31
32impl Signer<DsaSignature> for PrivateKey {
33 fn try_sign(&self, tbs: &[u8]) -> core::result::Result<DsaSignature, signature::Error> {
34 let sm = self.sign(tbs).map_err(|_| signature::Error::new())?;
35 Ok(DsaSignature(sm))
36 }
37}
38
39impl Keypair for PrivateKey {
40 type VerifyingKey = PublicKey;
41
42 fn verifying_key(&self) -> <Self as Keypair>::VerifyingKey {
43 self.public_key.clone().unwrap()
45 }
46}
47
48impl DynSignatureAlgorithmIdentifier for PrivateKey {
49 fn signature_algorithm_identifier(
50 &self,
51 ) -> core::result::Result<AlgorithmIdentifier<der::Any>, spki::Error> {
52 let oid: ObjectIdentifier = self.oid.parse().map_err(|_| spki::Error::KeyMalformed)?;
53 let spki_algorithm = AlgorithmIdentifierOwned {
54 oid,
55 parameters: None,
56 };
57 Ok(spki_algorithm)
58 }
59}
60
61impl PrivateKey {
62 pub(crate) fn new(oid: &str, key: &[u8], public_key: Option<PublicKey>) -> Result<Self> {
77 if !is_valid_kem_or_dsa_oid(&oid.to_string()) {
78 return Err(errors::QuantCryptError::InvalidPrivateKey);
79 }
80 let is_composite = is_composite_kem_or_dsa_oid(oid);
81 Ok(Self {
82 oid: oid.to_string(),
83 private_key: key.to_vec(),
84 is_composite,
85 public_key,
86 })
87 }
88
89 pub fn from_composite(
104 public_key: Option<PublicKey>,
105 composite_sk: &CompositePrivateKey,
106 ) -> Result<Self> {
107 Ok(Self {
108 oid: composite_sk.get_oid().to_string(),
109 private_key: composite_sk
110 .to_der()
111 .map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?,
112 is_composite: true,
113 public_key,
114 })
115 }
116
117 pub fn get_oid(&self) -> &str {
123 &self.oid
124 }
125
126 #[cfg(test)]
132 fn get_key(&self) -> &[u8] {
133 &self.private_key
134 }
135
136 pub fn get_public_key(&self) -> Option<&PublicKey> {
142 self.public_key.as_ref()
143 }
144
145 pub fn is_composite(&self) -> bool {
151 self.is_composite
152 }
153
154 pub fn to_der(&self) -> Result<Vec<u8>> {
164 let pub_key = self.public_key.as_ref().map(|pk| pk.get_key());
165
166 let oid: ObjectIdentifier = self
167 .oid
168 .parse()
169 .map_err(|_| QuantCryptError::InvalidPrivateKey)?;
170
171 let priv_key_info = PrivateKeyInfo {
172 algorithm: AlgorithmIdentifier {
173 oid,
174 parameters: None,
175 },
176 private_key: &self.private_key,
177 public_key: pub_key,
178 };
179 Ok(priv_key_info
180 .to_der()
181 .map_err(|_| errors::QuantCryptError::InvalidPrivateKey))?
182 }
183
184 pub fn to_pem(&self) -> Result<String> {
194 let der = self
195 .to_der()
196 .map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
197 let pem_obj = pem::Pem::new("PRIVATE KEY", der);
198 let encode_conf = EncodeConfig::default().set_line_ending(pem::LineEnding::LF);
199 Ok(pem::encode_config(&pem_obj, encode_conf))
200 }
201
202 pub fn from_pem(pem: &str) -> Result<Self> {
216 let pem = pem::parse(pem).map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
217 if pem.tag() != "PRIVATE KEY" {
219 return Err(errors::QuantCryptError::InvalidPrivateKey);
220 }
221
222 let der = pem.contents();
223 Self::from_der(der)
224 }
225
226 pub fn from_der(der: &[u8]) -> Result<Self> {
240 let priv_key_info = PrivateKeyInfo::from_der(der)
241 .map_err(|_| errors::QuantCryptError::InvalidPrivateKey)?;
242
243 let oid = priv_key_info.algorithm.oid.to_string();
244
245 if !is_valid_kem_or_dsa_oid(&oid) {
247 return Err(errors::QuantCryptError::InvalidPrivateKey);
248 }
249
250 let is_composite = is_composite_kem_or_dsa_oid(&oid);
252
253 let public_key = if let Some(pk) = priv_key_info.public_key {
255 Some(PublicKey::new(&oid, pk)?)
256 } else {
257 None
258 };
259
260 Ok(Self {
261 oid: oid.to_string(),
262 private_key: priv_key_info.private_key.to_vec(),
263 is_composite,
264 public_key,
265 })
266 }
267
268 pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
278 if !is_dsa_oid(&self.oid) {
280 return Err(errors::QuantCryptError::UnsupportedOperation);
281 }
282
283 let dsa = DsaManager::new_from_oid(&self.oid)?;
284
285 let sig = dsa.sign(&self.private_key, data)?;
286
287 Ok(sig)
288 }
289
290 pub(crate) fn decap(&self, ct: &[u8]) -> Result<Vec<u8>> {
304 if is_dsa_oid(&self.oid) {
305 return Err(errors::QuantCryptError::UnsupportedOperation);
306 }
307 let kem = KemManager::new_from_oid(&self.oid)?;
308 let ss = kem.decap(&self.private_key, ct)?;
309 Ok(ss)
310 }
311
312 pub fn from_file(path: &str) -> Result<Self> {
322 let contents = std::fs::read(path).map_err(|_| QuantCryptError::FileReadError)?;
324
325 let result = PrivateKey::from_der(&contents);
327
328 if let Ok(sk) = result {
329 Ok(sk)
330 } else {
331 let pem =
333 std::str::from_utf8(&contents).map_err(|_| QuantCryptError::InvalidCertificate)?;
334 if let Ok(sk) = PrivateKey::from_pem(pem) {
335 Ok(sk)
336 } else {
337 Err(QuantCryptError::InvalidPrivateKey)
338 }
339 }
340 }
341
342 pub fn to_pem_file(&self, path: &str) -> Result<()> {
352 let pem = self
353 .to_pem()
354 .map_err(|_| QuantCryptError::InvalidPrivateKey)?;
355 std::fs::write(path, pem).map_err(|_| QuantCryptError::FileWriteError)?;
356 Ok(())
357 }
358
359 pub fn to_der_file(&self, path: &str) -> Result<()> {
369 let der = self
370 .to_der()
371 .map_err(|_| QuantCryptError::InvalidPrivateKey)?;
372 std::fs::write(path, der).map_err(|_| QuantCryptError::FileWriteError)?;
373 Ok(())
374 }
375}
376
377#[cfg(test)]
378mod test {
379 use crate::dsa::common::config::oids::Oid;
380 use crate::dsa::common::dsa_type::DsaType;
381
382 use super::*;
383
384 #[test]
385 fn test_composite_private_key() {
386 let pem_bytes = include_bytes!("../../test/data/mldsa44_ecdsa_p256_sha256_sk.pem");
387 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
388 let pk = PrivateKey::from_pem(pem).unwrap();
389
390 assert!(pk.public_key.is_none());
392
393 assert!(pk.is_composite());
394 assert_eq!(pk.get_oid(), DsaType::MlDsa44EcdsaP256SHA256.get_oid());
395
396 let key_bytes = pk.get_key();
397 let pk2 = CompositePrivateKey::from_der(&pk.oid, &key_bytes).unwrap();
398
399 assert_eq!(pk.oid, pk2.get_oid());
400
401 let pk2 = PrivateKey::from_composite(pk.public_key, &pk2).unwrap();
402 let pem2 = pk2.to_pem().unwrap();
403 assert_eq!(pem, pem2.trim());
404
405 let oid = DsaType::MlDsa44EcdsaP256SHA256.get_oid();
406 assert_eq!(pk.oid, oid);
407 }
408
409 #[test]
410 fn test_pk_no_headers() {
411 let pem_bytes = include_bytes!("../../test/data/bad/no_headers.pem");
412 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
413 let pk = PrivateKey::from_pem(pem);
414
415 assert!(pk.is_err());
416 assert!(matches!(
417 pk.err().unwrap(),
418 errors::QuantCryptError::InvalidPrivateKey
419 ));
420 }
421
422 #[test]
423 fn test_pk_bad_base64() {
424 let pem_bytes = include_bytes!("../../test/data/bad/bad_base64.pem");
425 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
426 let pk = PrivateKey::from_pem(pem);
427
428 assert!(pk.is_err());
429 assert!(matches!(
430 pk.err().unwrap(),
431 errors::QuantCryptError::InvalidPrivateKey
432 ));
433 }
434
435 #[test]
436 fn test_pk_empty() {
437 let pem_bytes = include_bytes!("../../test/data/bad/empty.pem");
438 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
439 let pk = PrivateKey::from_pem(pem);
440
441 assert!(pk.is_err());
442 assert!(matches!(
443 pk.err().unwrap(),
444 errors::QuantCryptError::InvalidPrivateKey
445 ));
446 }
447
448 #[test]
449 fn test_pk_bad_tag() {
450 let pem_bytes = include_bytes!("../../test/data/bad/bad_tag.pem");
451 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
452 let pk = PrivateKey::from_pem(pem);
453
454 assert!(pk.is_err());
455 assert!(matches!(
456 pk.err().unwrap(),
457 errors::QuantCryptError::InvalidPrivateKey
458 ));
459 }
460
461 #[test]
462 fn test_pk_bad_algorithm() {
463 let pem_bytes = include_bytes!("../../test/data/bad/private_rsa_2048.pem");
464 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
465 let pk = PrivateKey::from_pem(pem);
466
467 assert!(pk.is_err());
468 assert!(matches!(
469 pk.err().unwrap(),
470 errors::QuantCryptError::InvalidPrivateKey
471 ));
472 }
473
474 #[test]
475 fn test_sk_serialization_deserialization() {
476 let pem_bytes = include_bytes!("../../test/data/mldsa44_ecdsa_p256_sha256_sk.pem");
477 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
478 let pk = PrivateKey::from_pem(pem).unwrap();
479
480 let der = pk.to_der().unwrap();
481 let pk2 = PrivateKey::from_der(&der).unwrap();
482 let pem2 = pk2.to_pem().unwrap();
483 assert_eq!(pem.trim(), pem2.trim());
484
485 let der2 = pk2.to_der().unwrap();
486 assert_eq!(der, der2);
487 }
488
489 #[test]
490 fn test_sk_containing_pk() {
491 let (pk, sk) = DsaManager::new(DsaType::MlDsa44)
492 .unwrap()
493 .key_gen()
494 .unwrap();
495 let pk = PublicKey::new(&DsaType::MlDsa44.get_oid(), &pk).unwrap();
496 let sk = PrivateKey::new(&DsaType::MlDsa44.get_oid(), &sk, Some(pk.clone())).unwrap();
497 let sk_der = sk.to_der().unwrap();
498 let sk2 = PrivateKey::from_der(&sk_der).unwrap();
499 let pk2 = sk2.get_public_key().unwrap();
500 assert_eq!(pk.get_key(), pk2.get_key());
501 assert_eq!(
502 sk.get_public_key().unwrap().get_key(),
503 sk2.get_public_key().unwrap().get_key()
504 );
505 }
506}