quantcrypt/asn1/
public_key.rs1use crate::asn1::asn_util::{is_composite_kem_or_dsa_oid, is_valid_kem_or_dsa_oid};
2use crate::dsa::common::dsa_trait::Dsa;
3use crate::dsa::dsa_manager::DsaManager;
4use crate::errors;
5use crate::kem::common::kem_trait::Kem;
6use crate::kem::kem_manager::KemManager;
7use der::{asn1::BitString, Document};
8use der::{Decode, Encode};
9use pem::EncodeConfig;
10use pkcs8::ObjectIdentifier;
11use pkcs8::{spki::AlgorithmIdentifierWithOid, EncodePublicKey};
12
13use crate::asn1::composite_public_key::CompositePublicKey;
14
15use crate::asn1::public_key_info::PublicKeyInfo;
16
17use super::asn_util::{is_dsa_oid, is_kem_oid};
18use errors::QuantCryptError;
19
20type Result<T> = std::result::Result<T, QuantCryptError>;
21
22#[derive(Clone)]
23pub struct PublicKey {
25 oid: String,
27 key: Vec<u8>,
29 is_composite: bool,
31}
32
33impl PublicKey {
34 pub fn new(oid: &str, key: &[u8]) -> Result<Self> {
50 if !is_valid_kem_or_dsa_oid(&oid.to_string()) {
51 return Err(errors::QuantCryptError::InvalidPublicKey);
52 }
53 let is_composite = is_composite_kem_or_dsa_oid(oid);
54 Ok(Self {
55 oid: oid.to_string(),
56 key: key.to_vec(),
57 is_composite,
58 })
59 }
60
61 pub fn from_composite(composite_pk: &CompositePublicKey) -> Result<Self> {
75 Ok(Self {
76 oid: composite_pk.get_oid().to_string(),
77 key: composite_pk
78 .to_der()
79 .map_err(|_| errors::QuantCryptError::InvalidPublicKey)?,
80 is_composite: true,
81 })
82 }
83
84 pub fn get_oid(&self) -> &str {
90 &self.oid
91 }
92
93 pub fn get_key(&self) -> &[u8] {
99 &self.key
100 }
101
102 pub fn is_composite(&self) -> bool {
108 self.is_composite
109 }
110
111 pub fn to_pem(&self) -> Result<String> {
121 let der = self
122 .to_der()
123 .map_err(|_| errors::QuantCryptError::InvalidPublicKey)?;
124 let pem_obj = pem::Pem::new("PUBLIC KEY", der);
125 let encode_conf = EncodeConfig::default().set_line_ending(pem::LineEnding::LF);
126 Ok(pem::encode_config(&pem_obj, encode_conf))
127 }
128
129 pub(crate) fn to_bitstring(&self) -> Result<BitString> {
135 let pk_bs = BitString::from_bytes(&self.key)
136 .map_err(|_| errors::QuantCryptError::InvalidPublicKey)?;
137 Ok(pk_bs)
138 }
139
140 pub fn to_der(&self) -> Result<Vec<u8>> {
151 let pk_bs = self.to_bitstring()?;
152
153 let oid: ObjectIdentifier = self
154 .oid
155 .parse()
156 .map_err(|_| QuantCryptError::InvalidPublicKey)?;
157
158 let pub_key_info = PublicKeyInfo {
159 algorithm: AlgorithmIdentifierWithOid {
160 oid,
161 parameters: None,
162 },
163 public_key: pk_bs,
164 };
165 let der = pub_key_info
166 .to_der()
167 .map_err(|_| errors::QuantCryptError::InvalidPublicKey)?;
168 Ok(der)
169 }
170
171 pub fn from_pem(pem: &str) -> Result<Self> {
185 let pem = pem::parse(pem).map_err(|_| errors::QuantCryptError::InvalidPublicKey)?;
186 if pem.tag() != "PUBLIC KEY" {
188 return Err(errors::QuantCryptError::InvalidPublicKey);
189 }
190
191 let der = pem.contents();
192 Self::from_der(der)
193 }
194
195 pub fn from_der(der: &[u8]) -> Result<Self> {
209 let pub_key_info =
210 PublicKeyInfo::from_der(der).map_err(|_| errors::QuantCryptError::InvalidPublicKey)?;
211 let pk_bytes = if let Some(pk_bytes) = pub_key_info.public_key.as_bytes() {
212 pk_bytes
213 } else {
214 return Err(errors::QuantCryptError::InvalidPublicKey);
215 };
216
217 let oid = pub_key_info.algorithm.oid.to_string();
218
219 if !is_valid_kem_or_dsa_oid(&oid) {
221 return Err(errors::QuantCryptError::InvalidPublicKey);
222 }
223
224 let is_composite = is_composite_kem_or_dsa_oid(&oid);
225
226 Ok(Self {
227 oid,
228 key: pk_bytes.to_vec(),
229 is_composite,
230 })
231 }
232
233 pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<bool> {
248 if !is_dsa_oid(&self.oid) {
250 return Err(errors::QuantCryptError::UnsupportedOperation);
251 }
252
253 let dsa =
254 DsaManager::new_from_oid(&self.oid).map_err(|_| errors::QuantCryptError::InvalidOid)?;
255
256 let verified = dsa
257 .verify(self.get_key(), message, signature)
258 .unwrap_or(false);
259
260 Ok(verified)
261 }
262
263 pub fn encap(&self) -> Result<(Vec<u8>, Vec<u8>)> {
269 if !is_kem_oid(&self.oid) {
271 return Err(errors::QuantCryptError::UnsupportedOperation);
272 }
273
274 let mut kem =
275 KemManager::new_from_oid(&self.oid).map_err(|_| errors::QuantCryptError::InvalidOid)?;
276
277 let (ct, ss) = kem.encap(self.get_key())?;
278
279 Ok((ct, ss))
280 }
281}
282
283impl EncodePublicKey for PublicKey {
284 fn to_public_key_der(&self) -> std::result::Result<Document, pkcs8::spki::Error> {
285 let der = self
286 .to_der()
287 .map_err(|_| pkcs8::spki::Error::KeyMalformed)?;
288 let doc = Document::try_from(der)?;
289 Ok(doc)
290 }
291}
292
293#[cfg(test)]
294mod test {
295 use crate::dsa::common::config::oids::Oid;
296 use crate::dsa::common::dsa_type::DsaType;
297
298 use super::*;
299
300 #[test]
301 fn test_composite_public_key() {
302 let pem_bytes = include_bytes!("../../test/data/mldsa44_ecdsa_p256_sha256_pk.pem");
303 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
304 let pk = PublicKey::from_pem(pem).unwrap();
305
306 assert!(pk.is_composite());
307 assert_eq!(pk.get_oid(), DsaType::MlDsa44EcdsaP256SHA256.get_oid());
308
309 let key_bytes = pk.get_key();
310 let pk2 = CompositePublicKey::from_der(&pk.oid, &key_bytes).unwrap();
311
312 assert_eq!(pk.oid, pk2.get_oid());
313
314 let pk2 = PublicKey::from_composite(&pk2).unwrap();
315 let pem2 = pk2.to_pem().unwrap();
316 assert_eq!(pem, pem2.trim());
317
318 let oid = DsaType::MlDsa44EcdsaP256SHA256.get_oid();
319 assert_eq!(pk.oid, oid);
320 }
321
322 #[test]
323 fn test_pk_no_headers() {
324 let pem_bytes = include_bytes!("../../test/data/bad/no_headers.pem");
325 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
326 let pk = PublicKey::from_pem(pem);
327
328 assert!(pk.is_err());
329 assert!(matches!(
330 pk.err().unwrap(),
331 errors::QuantCryptError::InvalidPublicKey
332 ));
333 }
334
335 #[test]
336 fn test_pk_bad_base64() {
337 let pem_bytes = include_bytes!("../../test/data/bad/bad_base64.pem");
338 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
339 let pk = PublicKey::from_pem(pem);
340
341 assert!(pk.is_err());
342 assert!(matches!(
343 pk.err().unwrap(),
344 errors::QuantCryptError::InvalidPublicKey
345 ));
346 }
347
348 #[test]
349 fn test_pk_empty() {
350 let pem_bytes = include_bytes!("../../test/data/bad/empty.pem");
351 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
352 let pk = PublicKey::from_pem(pem);
353
354 assert!(pk.is_err());
355 assert!(matches!(
356 pk.err().unwrap(),
357 errors::QuantCryptError::InvalidPublicKey
358 ));
359 }
360
361 #[test]
362 fn test_pk_bad_tag() {
363 let pem_bytes = include_bytes!("../../test/data/bad/bad_tag.pem");
364 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
365 let pk = PublicKey::from_pem(pem);
366
367 assert!(pk.is_err());
368 assert!(matches!(
369 pk.err().unwrap(),
370 errors::QuantCryptError::InvalidPublicKey
371 ));
372 }
373
374 #[test]
375 fn test_pk_bad_algorithm() {
376 let pem_bytes = include_bytes!("../../test/data/bad/public_rsa_2048.pem");
377 let pem = std::str::from_utf8(pem_bytes).unwrap().trim();
378 let pk = PublicKey::from_pem(pem);
379
380 assert!(pk.is_err());
381 assert!(matches!(
382 pk.err().unwrap(),
383 errors::QuantCryptError::InvalidPublicKey
384 ));
385 }
386}