1use crate::helpers::WindowsString;
9use crate::helpers::{AlgoHandle, Handle, KeyHandle};
10use crate::helpers::{Blob, BlobLayout};
11use crate::key_blob::{BlobType, ErasedKeyBlob, *};
12use crate::property::{AlgorithmName, EccCurveName};
13use crate::Result;
14use std::borrow::Borrow;
15use std::convert::TryFrom;
16use std::marker::PhantomData;
17use std::ptr::null_mut;
18use winapi::shared::bcrypt::*;
19
20use builder::KeyPair;
21use ecc::{Curve, NamedCurve};
22use ecc::{Curve25519, NistP256, NistP384, NistP521};
23
24pub mod agreement;
25pub mod builder;
26pub mod ecc;
27pub mod signature;
28
29#[derive(Debug, Clone, Copy, PartialEq)]
31pub enum AsymmetricAlgorithmId {
32 Dh,
36 Dsa,
44 Ecdh(NamedCurve),
48 Ecdsa(NamedCurve),
52 Rsa,
56}
57
58impl AsymmetricAlgorithmId {
59 pub fn to_str(&self) -> &str {
60 match self {
61 Self::Dh => BCRYPT_DH_ALGORITHM,
62 Self::Dsa => BCRYPT_DSA_ALGORITHM,
63 Self::Ecdh(NamedCurve::NistP256) => BCRYPT_ECDH_P256_ALGORITHM,
64 Self::Ecdh(NamedCurve::NistP384) => BCRYPT_ECDH_P384_ALGORITHM,
65 Self::Ecdh(NamedCurve::NistP521) => BCRYPT_ECDH_P521_ALGORITHM,
66 Self::Ecdh(..) => BCRYPT_ECDH_ALGORITHM,
67 Self::Ecdsa(NamedCurve::NistP256) => BCRYPT_ECDSA_P256_ALGORITHM,
68 Self::Ecdsa(NamedCurve::NistP384) => BCRYPT_ECDSA_P384_ALGORITHM,
69 Self::Ecdsa(NamedCurve::NistP521) => BCRYPT_ECDSA_P521_ALGORITHM,
70 Self::Ecdsa(..) => BCRYPT_ECDSA_ALGORITHM,
71 Self::Rsa => BCRYPT_RSA_ALGORITHM,
72 }
73 }
74
75 pub fn key_bits(self) -> Option<u32> {
76 match self {
77 Self::Ecdh(curve) | Self::Ecdsa(curve) => Some(curve.key_bits()),
78 _ => None,
79 }
80 }
81
82 pub fn is_key_bits_supported(self, key_bits: u32) -> bool {
83 match (self, key_bits) {
84 | (Self::Dh, 512..=4096)
85 | (Self::Rsa, 512..=16384)
86 | (Self::Dsa, 512..=3072) if key_bits % 64 == 0 => true,
90 | (Self::Ecdh(curve), bits)
91 | (Self::Ecdsa(curve), bits) if curve.key_bits() == bits => true,
92 _ => false,
93 }
94 }
95}
96
97impl<'a> TryFrom<&'a str> for AsymmetricAlgorithmId {
98 type Error = &'a str;
99
100 fn try_from(val: &'a str) -> Result<AsymmetricAlgorithmId, Self::Error> {
101 match val {
102 BCRYPT_DH_ALGORITHM => Ok(Self::Dh),
103 BCRYPT_DSA_ALGORITHM => Ok(Self::Dsa),
104 BCRYPT_ECDH_P256_ALGORITHM => Ok(Self::Ecdh(NamedCurve::NistP256)),
105 BCRYPT_ECDH_P384_ALGORITHM => Ok(Self::Ecdh(NamedCurve::NistP384)),
106 BCRYPT_ECDH_P521_ALGORITHM => Ok(Self::Ecdh(NamedCurve::NistP521)),
107 BCRYPT_ECDSA_P256_ALGORITHM => Ok(Self::Ecdsa(NamedCurve::NistP256)),
108 BCRYPT_ECDSA_P384_ALGORITHM => Ok(Self::Ecdsa(NamedCurve::NistP384)),
109 BCRYPT_ECDSA_P521_ALGORITHM => Ok(Self::Ecdsa(NamedCurve::NistP521)),
110 BCRYPT_RSA_ALGORITHM => Ok(Self::Rsa),
111 val => Err(val),
113 }
114 }
115}
116
117pub struct AsymmetricAlgorithm {
119 handle: AlgoHandle,
120}
121
122impl AsymmetricAlgorithm {
123 pub fn open(id: AsymmetricAlgorithmId) -> Result<Self> {
134 let handle = AlgoHandle::open(id.to_str())?;
135
136 match id {
140 AsymmetricAlgorithmId::Ecdh(NamedCurve::NistP256)
141 | AsymmetricAlgorithmId::Ecdh(NamedCurve::NistP384)
142 | AsymmetricAlgorithmId::Ecdh(NamedCurve::NistP521)
143 | AsymmetricAlgorithmId::Ecdsa(NamedCurve::NistP256)
144 | AsymmetricAlgorithmId::Ecdsa(NamedCurve::NistP384)
145 | AsymmetricAlgorithmId::Ecdsa(NamedCurve::NistP521) => {}
146 AsymmetricAlgorithmId::Ecdh(curve) | AsymmetricAlgorithmId::Ecdsa(curve) => {
147 let property = WindowsString::from(curve.to_str());
148
149 handle.set_property::<EccCurveName>(property.as_slice_with_nul())?;
150 }
151 _ => {}
152 }
153
154 Ok(Self { handle })
155 }
156
157 pub fn id(&self) -> Result<AsymmetricAlgorithmId> {
165 self.handle
166 .get_property_unsized::<AlgorithmName>()
167 .map(|name| {
168 WindowsString::from_bytes_with_nul(name.as_ref().into())
169 .expect("API to return 0-terminated wide string")
170 })
171 .and_then(|name| {
172 AsymmetricAlgorithmId::try_from(name.to_string().as_str())
173 .map_err(|_| crate::Error::InvalidHandle)
174 })
175 }
176}
177
178pub trait Algorithm {
180 fn id(&self) -> AsymmetricAlgorithmId;
181}
182
183pub struct Ecdsa<C: Curve>(pub C);
185impl<C: Curve> Algorithm for Ecdsa<C> {
186 #[inline(always)]
187 fn id(&self) -> AsymmetricAlgorithmId {
188 AsymmetricAlgorithmId::Ecdsa(self.0.as_curve())
189 }
190}
191
192pub struct Ecdh<C: Curve>(pub C);
194impl<C: Curve> Algorithm for Ecdh<C> {
195 #[inline(always)]
196 fn id(&self) -> AsymmetricAlgorithmId {
197 AsymmetricAlgorithmId::Ecdh(self.0.as_curve())
198 }
199}
200
201pub struct Dh;
203impl Algorithm for Dh {
204 #[inline(always)]
205 fn id(&self) -> AsymmetricAlgorithmId {
206 AsymmetricAlgorithmId::Dh
207 }
208}
209
210pub struct Dsa;
212impl Algorithm for Dsa {
213 #[inline(always)]
214 fn id(&self) -> AsymmetricAlgorithmId {
215 AsymmetricAlgorithmId::Dsa
216 }
217}
218
219pub struct Rsa;
221impl Algorithm for Rsa {
222 #[inline(always)]
223 fn id(&self) -> AsymmetricAlgorithmId {
224 AsymmetricAlgorithmId::Rsa
225 }
226}
227
228pub trait Parts {}
230pub struct Private {}
232impl Parts for Private {}
233pub struct Public {}
235impl Parts for Public {}
236
237impl Algorithm for AsymmetricAlgorithmId {
238 fn id(&self) -> AsymmetricAlgorithmId {
239 *self
240 }
241}
242
243pub struct AsymmetricKey<A: Algorithm = AsymmetricAlgorithmId, P: Parts = Public>(
283 KeyHandle,
284 A,
285 PhantomData<P>,
286);
287
288impl<A: Algorithm, P: Parts> AsymmetricKey<A, P> {
289 pub fn id(&self) -> AsymmetricAlgorithmId {
291 Algorithm::id(&self.1)
292 }
293}
294
295impl<A: Algorithm> AsymmetricKey<A, Private> {
296 pub fn as_public(&self) -> &AsymmetricKey<A, Public> {
298 unsafe { &*(self as *const _ as *const AsymmetricKey<A, Public>) }
300 }
301}
302
303impl AsymmetricKey<Rsa, Private> {
304 pub fn export_full(&self) -> Result<Box<Blob<RsaKeyFullPrivateBlob>>> {
307 KeyPair::export(self.0.handle, BlobType::RsaFullPrivate)?
308 .try_into()
309 .map_err(|_| crate::Error::BadData)
310 }
311}
312
313pub trait Import<'a, A: Algorithm, P: Parts> {
315 type Blob: AsRef<Blob<ErasedKeyBlob>> + 'a;
316 fn import(
317 algo: A,
318 provider: &AsymmetricAlgorithm,
319 blob: Self::Blob,
320 ) -> Result<AsymmetricKey<A, P>> {
321 KeyPair::import(provider, blob.as_ref(), true)
322 .map(|pair| AsymmetricKey(pair.0, algo, PhantomData))
323 }
324}
325
326macro_rules! import_blobs {
327 ($(($algorithm: ty, $parts: ident, $blob: ty)),*$(,)?) => {
328 $(
329 impl<'a> Import<'a, $algorithm, $parts> for AsymmetricKey<$algorithm, $parts> {
330 type Blob = $blob;
331 }
332 )*
333 };
334}
335
336import_blobs!(
337 (AsymmetricAlgorithmId, Public, &'a Blob<ErasedKeyBlob>),
338 (AsymmetricAlgorithmId, Private, &'a Blob<ErasedKeyBlob>),
339 (Dh, Public, &'a Blob<DhKeyPublicBlob>),
340 (Dh, Private, &'a Blob<DhKeyPrivateBlob>),
341 (Dsa, Public, DsaPublicBlob),
342 (Dsa, Private, DsaPrivateBlob),
343 (Ecdh<NistP256>, Public, &'a Blob<EccKeyPublicBlob>),
344 (Ecdh<NistP256>, Private, &'a Blob<EccKeyPrivateBlob>),
345 (Ecdh<NistP384>, Public, &'a Blob<EccKeyPublicBlob>),
346 (Ecdh<NistP384>, Private, &'a Blob<EccKeyPrivateBlob>),
347 (Ecdh<NistP521>, Public, &'a Blob<EccKeyPublicBlob>),
348 (Ecdh<NistP521>, Private, &'a Blob<EccKeyPrivateBlob>),
349 (Ecdh<Curve25519>, Public, &'a Blob<EccKeyPublicBlob>),
350 (Ecdh<Curve25519>, Private, &'a Blob<EccKeyPrivateBlob>),
351 (Ecdsa<NistP256>, Public, &'a Blob<EccKeyPublicBlob>),
352 (Ecdsa<NistP256>, Private, &'a Blob<EccKeyPrivateBlob>),
353 (Ecdsa<NistP384>, Public, &'a Blob<EccKeyPublicBlob>),
354 (Ecdsa<NistP384>, Private, &'a Blob<EccKeyPrivateBlob>),
355 (Ecdsa<NistP521>, Public, &'a Blob<EccKeyPublicBlob>),
356 (Ecdsa<NistP521>, Private, &'a Blob<EccKeyPrivateBlob>),
357 (Rsa, Public, &'a Blob<RsaKeyPublicBlob>),
358 (Rsa, Private, &'a Blob<RsaKeyPrivateBlob>),
359);
360
361impl AsymmetricKey<Rsa, Private> {
363 pub fn import_from_parts(
364 provider: &AsymmetricAlgorithm,
365 parts: &RsaKeyPrivatePayload,
366 ) -> Result<Self> {
367 let key_bits = parts.modulus.len() * 8;
368 if key_bits % 64 != 0 || !(512..=16384).contains(&key_bits) {
369 return Err(crate::Error::InvalidParameter);
370 }
371
372 let header = BCRYPT_RSAKEY_BLOB {
373 BitLength: key_bits as u32,
374 Magic: BCRYPT_RSAPRIVATE_MAGIC,
375 cbModulus: parts.modulus.len() as u32,
376 cbPublicExp: parts.pub_exp.len() as u32,
377 cbPrime1: parts.prime1.len() as u32,
378 cbPrime2: parts.prime2.len() as u32,
379 };
380 let blob = Blob::<RsaKeyPrivateBlob>::clone_from_parts(&header, parts);
381
382 <Self as Import<_, _>>::import(Rsa, provider, &blob)
383 }
384}
385
386impl AsymmetricKey<Rsa, Public> {
387 pub fn import_from_parts(
388 provider: &AsymmetricAlgorithm,
389 parts: &RsaKeyPublicPayload,
390 ) -> Result<Self> {
391 let key_bits = parts.modulus.len() * 8;
392 if key_bits % 64 != 0 || !(512..=16384).contains(&key_bits) {
393 return Err(crate::Error::InvalidParameter);
394 }
395
396 let header = BCRYPT_RSAKEY_BLOB {
397 BitLength: key_bits as u32,
398 Magic: BCRYPT_RSAPUBLIC_MAGIC,
399 cbModulus: parts.modulus.len() as u32,
400 cbPublicExp: parts.pub_exp.len() as u32,
401 cbPrime1: 0,
402 cbPrime2: 0,
403 };
404 let blob = Blob::<RsaKeyPublicBlob>::clone_from_parts(&header, parts);
405
406 <Self as Import<_, _>>::import(Rsa, provider, &blob)
407 }
408}
409
410impl AsymmetricKey<Ecdsa<NistP256>, Private> {
411 pub fn import_from_parts(
412 provider: &AsymmetricAlgorithm,
413 parts: &EccKeyPrivatePayload,
414 ) -> Result<Self> {
415 let key_len = NistP256.key_bits() / 8;
416 if [parts.x, parts.y, parts.d]
417 .iter()
418 .any(|v| v.len() != key_len as usize)
419 {
420 return Err(crate::Error::InvalidParameter);
421 }
422
423 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
424 &BCRYPT_ECCKEY_BLOB {
425 dwMagic: BCRYPT_ECDSA_PRIVATE_P256_MAGIC,
426 cbKey: key_len,
427 },
428 parts,
429 );
430
431 <Self as Import<_, _>>::import(Ecdsa(NistP256), provider, &blob)
432 }
433}
434
435impl AsymmetricKey<Ecdsa<NistP256>, Public> {
436 pub fn import_from_parts(
437 provider: &AsymmetricAlgorithm,
438 parts: &EccKeyPublicPayload,
439 ) -> Result<Self> {
440 let key_len = NistP256.key_bits() / 8;
441 if [parts.x, parts.y]
442 .iter()
443 .any(|v| v.len() != key_len as usize)
444 {
445 return Err(crate::Error::InvalidParameter);
446 }
447
448 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
449 &BCRYPT_ECCKEY_BLOB {
450 dwMagic: BCRYPT_ECDSA_PUBLIC_P256_MAGIC,
451 cbKey: key_len,
452 },
453 parts,
454 );
455
456 <Self as Import<_, _>>::import(Ecdsa(NistP256), provider, &blob)
457 }
458}
459
460impl AsymmetricKey<Ecdsa<NistP384>, Private> {
461 pub fn import_from_parts(
462 provider: &AsymmetricAlgorithm,
463 parts: &EccKeyPrivatePayload,
464 ) -> Result<Self> {
465 let key_len = NistP384.key_bits() / 8;
466 if [parts.x, parts.y, parts.d]
467 .iter()
468 .any(|v| v.len() != key_len as usize)
469 {
470 return Err(crate::Error::InvalidParameter);
471 }
472
473 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
474 &BCRYPT_ECCKEY_BLOB {
475 dwMagic: BCRYPT_ECDSA_PRIVATE_P384_MAGIC,
476 cbKey: key_len,
477 },
478 parts,
479 );
480
481 <Self as Import<_, _>>::import(Ecdsa(NistP384), provider, &blob)
482 }
483}
484
485impl AsymmetricKey<Ecdsa<NistP384>, Public> {
486 pub fn import_from_parts(
487 provider: &AsymmetricAlgorithm,
488 parts: &EccKeyPublicPayload,
489 ) -> Result<Self> {
490 let key_len = NistP384.key_bits() / 8;
491 if [parts.x, parts.y]
492 .iter()
493 .any(|v| v.len() != key_len as usize)
494 {
495 return Err(crate::Error::InvalidParameter);
496 }
497
498 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
499 &BCRYPT_ECCKEY_BLOB {
500 dwMagic: BCRYPT_ECDSA_PUBLIC_P384_MAGIC,
501 cbKey: key_len,
502 },
503 parts,
504 );
505
506 <Self as Import<_, _>>::import(Ecdsa(NistP384), provider, &blob)
507 }
508}
509
510impl AsymmetricKey<Ecdsa<NistP521>, Private> {
511 pub fn import_from_parts(
512 provider: &AsymmetricAlgorithm,
513 parts: &EccKeyPrivatePayload,
514 ) -> Result<Self> {
515 let key_len = (NistP521.key_bits() + 7) / 8;
516 if [parts.x, parts.y, parts.d]
517 .iter()
518 .any(|v| v.len() != key_len as usize)
519 {
520 return Err(crate::Error::InvalidParameter);
521 }
522
523 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
524 &BCRYPT_ECCKEY_BLOB {
525 dwMagic: BCRYPT_ECDSA_PRIVATE_P521_MAGIC,
526 cbKey: key_len,
527 },
528 parts,
529 );
530
531 <Self as Import<_, _>>::import(Ecdsa(NistP521), provider, &blob)
532 }
533}
534
535impl AsymmetricKey<Ecdsa<NistP521>, Public> {
536 pub fn import_from_parts(
537 provider: &AsymmetricAlgorithm,
538 parts: &EccKeyPublicPayload,
539 ) -> Result<Self> {
540 let key_len = (NistP521.key_bits() + 7) / 8;
541 if [parts.x, parts.y]
542 .iter()
543 .any(|v| v.len() != key_len as usize)
544 {
545 return Err(crate::Error::InvalidParameter);
546 }
547
548 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
549 &BCRYPT_ECCKEY_BLOB {
550 dwMagic: BCRYPT_ECDSA_PUBLIC_P521_MAGIC,
551 cbKey: key_len,
552 },
553 parts,
554 );
555
556 <Self as Import<_, _>>::import(Ecdsa(NistP521), provider, &blob)
557 }
558}
559
560impl AsymmetricKey<Ecdh<Curve25519>, Private> {
561 pub fn import_from_parts(provider: &AsymmetricAlgorithm, private: &[u8]) -> Result<Self> {
562 let key_len = (Curve25519.key_bits() + 7) / 8;
563 if private.len() != key_len as usize {
564 return Err(crate::Error::InvalidParameter);
565 }
566
567 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
568 &BCRYPT_ECCKEY_BLOB {
569 dwMagic: BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC,
570 cbKey: key_len,
571 },
572 &EccKeyPrivatePayload {
573 x: &[0u8; 32],
574 y: &[0u8; 32],
575 d: private,
576 },
577 );
578
579 <Self as Import<_, _>>::import(Ecdh(Curve25519), provider, &blob)
580 }
581}
582
583impl AsymmetricKey<Ecdh<Curve25519>, Public> {
584 pub fn import_from_parts(provider: &AsymmetricAlgorithm, public: &[u8]) -> Result<Self> {
585 let key_len = (Curve25519.key_bits() + 7) / 8;
586 if public.len() != key_len as usize {
587 return Err(crate::Error::InvalidParameter);
588 }
589
590 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
591 &BCRYPT_ECCKEY_BLOB {
592 dwMagic: BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC,
593 cbKey: key_len,
594 },
595 &EccKeyPublicPayload {
596 x: public,
597 y: &[0u8; 32],
598 },
599 );
600
601 <Self as Import<_, _>>::import(Ecdh(Curve25519), provider, &blob)
602 }
603}
604
605impl AsymmetricKey<Ecdh<NistP256>, Private> {
606 pub fn import_from_parts(
607 provider: &AsymmetricAlgorithm,
608 parts: &EccKeyPrivatePayload,
609 ) -> Result<Self> {
610 let key_len = NistP256.key_bits() / 8;
611 if [parts.x, parts.y, parts.d]
612 .iter()
613 .any(|v| v.len() != key_len as usize)
614 {
615 return Err(crate::Error::InvalidParameter);
616 }
617
618 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
619 &BCRYPT_ECCKEY_BLOB {
620 dwMagic: BCRYPT_ECDH_PRIVATE_P256_MAGIC,
621 cbKey: key_len,
622 },
623 parts,
624 );
625
626 <Self as Import<_, _>>::import(Ecdh(NistP256), provider, &blob)
627 }
628}
629
630impl AsymmetricKey<Ecdh<NistP256>, Public> {
631 pub fn import_from_parts(
632 provider: &AsymmetricAlgorithm,
633 parts: &EccKeyPublicPayload,
634 ) -> Result<Self> {
635 let key_len = NistP256.key_bits() / 8;
636 if [parts.x, parts.y]
637 .iter()
638 .any(|v| v.len() != key_len as usize)
639 {
640 return Err(crate::Error::InvalidParameter);
641 }
642
643 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
644 &BCRYPT_ECCKEY_BLOB {
645 dwMagic: BCRYPT_ECDH_PUBLIC_P256_MAGIC,
646 cbKey: key_len,
647 },
648 parts,
649 );
650
651 <Self as Import<_, _>>::import(Ecdh(NistP256), provider, &blob)
652 }
653}
654
655impl AsymmetricKey<Ecdh<NistP384>, Private> {
656 pub fn import_from_parts(
657 provider: &AsymmetricAlgorithm,
658 parts: &EccKeyPrivatePayload,
659 ) -> Result<Self> {
660 let key_len = NistP384.key_bits() / 8;
661 if [parts.x, parts.y, parts.d]
662 .iter()
663 .any(|v| v.len() != key_len as usize)
664 {
665 return Err(crate::Error::InvalidParameter);
666 }
667
668 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
669 &BCRYPT_ECCKEY_BLOB {
670 dwMagic: BCRYPT_ECDH_PRIVATE_P384_MAGIC,
671 cbKey: key_len,
672 },
673 parts,
674 );
675
676 <Self as Import<_, _>>::import(Ecdh(NistP384), provider, &blob)
677 }
678}
679
680impl AsymmetricKey<Ecdh<NistP384>, Public> {
681 pub fn import_from_parts(
682 provider: &AsymmetricAlgorithm,
683 parts: &EccKeyPublicPayload,
684 ) -> Result<Self> {
685 let key_len = NistP384.key_bits() / 8;
686 if [parts.x, parts.y]
687 .iter()
688 .any(|v| v.len() != key_len as usize)
689 {
690 return Err(crate::Error::InvalidParameter);
691 }
692
693 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
694 &BCRYPT_ECCKEY_BLOB {
695 dwMagic: BCRYPT_ECDH_PUBLIC_P384_MAGIC,
696 cbKey: key_len,
697 },
698 parts,
699 );
700
701 <Self as Import<_, _>>::import(Ecdh(NistP384), provider, &blob)
702 }
703}
704
705impl AsymmetricKey<Ecdh<NistP521>, Private> {
706 pub fn import_from_parts(
707 provider: &AsymmetricAlgorithm,
708 parts: &EccKeyPrivatePayload,
709 ) -> Result<Self> {
710 let key_len = (NistP521.key_bits() + 7) / 8;
711 if [parts.x, parts.y, parts.d]
712 .iter()
713 .any(|v| v.len() != key_len as usize)
714 {
715 return Err(crate::Error::InvalidParameter);
716 }
717
718 let blob = Blob::<EccKeyPrivateBlob>::clone_from_parts(
719 &BCRYPT_ECCKEY_BLOB {
720 dwMagic: BCRYPT_ECDH_PRIVATE_P521_MAGIC,
721 cbKey: key_len,
722 },
723 parts,
724 );
725
726 <Self as Import<_, _>>::import(Ecdh(NistP521), provider, &blob)
727 }
728}
729
730impl AsymmetricKey<Ecdh<NistP521>, Public> {
731 pub fn import_from_parts(
732 provider: &AsymmetricAlgorithm,
733 parts: &EccKeyPublicPayload,
734 ) -> Result<Self> {
735 let key_len = (NistP521.key_bits() + 7) / 8;
736 if [parts.x, parts.y]
737 .iter()
738 .any(|v| v.len() != key_len as usize)
739 {
740 return Err(crate::Error::InvalidParameter);
741 }
742
743 let blob = Blob::<EccKeyPublicBlob>::clone_from_parts(
744 &BCRYPT_ECCKEY_BLOB {
745 dwMagic: BCRYPT_ECDH_PUBLIC_P521_MAGIC,
746 cbKey: key_len,
747 },
748 parts,
749 );
750
751 <Self as Import<_, _>>::import(Ecdh(NistP521), provider, &blob)
752 }
753}
754
755pub trait Export<A: Algorithm, P: Parts>: Borrow<AsymmetricKey<A, P>> {
776 type Blob: KeyBlob + BlobLayout;
777
778 #[doc(hidden)]
779 fn blob_type(&self) -> BlobType;
780
781 fn export(&self) -> Result<Box<Blob<Self::Blob>>> {
782 let key = self.borrow();
783 let blob_type = self.blob_type();
784
785 let blob = KeyPair::export(key.0.handle, blob_type)?;
786 blob.try_into().map_err(|_| crate::Error::BadData)
787 }
788}
789
790macro_rules! export_blobs {
791 ($(($type: ty, $parts: ty, $blob: ty, $blob_type: expr)),*$(,)?) => {
792 $(
793 impl<'a> Export<$type, $parts> for AsymmetricKey<$type, $parts> {
794 type Blob = $blob;
795
796 fn blob_type(&self) -> BlobType {
797 $blob_type
798 }
799 }
800 )*
801 };
802}
803
804#[rustfmt::skip]
805export_blobs!(
806 (AsymmetricAlgorithmId, Public, ErasedKeyBlob, BlobType::PublicKey),
807 (AsymmetricAlgorithmId, Private, ErasedKeyBlob, BlobType::PrivateKey),
808 (Dh, Public, DhKeyPublicBlob, BlobType::DhPublic),
809 (Dh, Private, DhKeyPrivateBlob, BlobType::DhPrivate),
810 (Dsa, Public, DsaKeyPublicBlob, BlobType::DsaPublic),
811 (Dsa, Private, DsaKeyPrivateBlob, BlobType::DsaPrivate),
812 (Ecdh<NistP256>, Public, EccKeyPublicBlob, BlobType::EccPublic),
813 (Ecdh<NistP256>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
814 (Ecdh<NistP384>, Public, EccKeyPublicBlob, BlobType::EccPublic),
815 (Ecdh<NistP384>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
816 (Ecdh<NistP521>, Public, EccKeyPublicBlob, BlobType::EccPublic),
817 (Ecdh<NistP521>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
818 (Ecdsa<NistP256>, Public, EccKeyPublicBlob, BlobType::EccPublic),
819 (Ecdsa<NistP256>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
820 (Ecdsa<NistP384>, Public, EccKeyPublicBlob, BlobType::EccPublic),
821 (Ecdsa<NistP384>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
822 (Ecdsa<NistP521>, Public, EccKeyPublicBlob, BlobType::EccPublic),
823 (Ecdsa<NistP521>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
824 (Ecdh<Curve25519>, Public, EccKeyPublicBlob, BlobType::EccPublic),
825 (Ecdh<Curve25519>, Private, EccKeyPrivateBlob, BlobType::EccPrivate),
826 (Rsa, Public, RsaKeyPublicBlob, BlobType::RsaPublic),
827 (Rsa, Private, RsaKeyPrivateBlob, BlobType::RsaPrivate),
828);
829
830pub enum DsaPublicBlob {
832 V1(Box<Blob<DsaKeyPublicBlob>>),
834 V2(Box<Blob<DsaKeyPublicV2Blob>>),
836}
837
838impl AsRef<Blob<ErasedKeyBlob>> for DsaPublicBlob {
839 fn as_ref(&self) -> &Blob<ErasedKeyBlob> {
840 match self {
841 DsaPublicBlob::V1(v1) => v1.as_erased(),
842 DsaPublicBlob::V2(v2) => v2.as_erased(),
843 }
844 }
845}
846
847pub enum DsaPrivateBlob {
851 V1(Box<Blob<DsaKeyPrivateBlob>>),
852 V2(Box<Blob<DsaKeyPrivateV2Blob>>),
853}
854
855impl AsRef<Blob<ErasedKeyBlob>> for DsaPrivateBlob {
856 fn as_ref(&self) -> &Blob<ErasedKeyBlob> {
857 match self {
858 DsaPrivateBlob::V1(v1) => v1.as_erased(),
859 DsaPrivateBlob::V2(v2) => v2.as_erased(),
860 }
861 }
862}
863
864#[derive(Clone, Debug)]
866pub struct OaepPadding {
867 pub algorithm: crate::hash::HashAlgorithmId,
868 pub label: Vec<u8>,
869}
870
871#[derive(Clone, Debug)]
873pub enum EncryptionPadding {
874 Oaep(OaepPadding),
876 Pkcs1,
878}
879
880struct OaepPaddingInfo<'a> {
881 _borrowed: &'a OaepPadding,
882 value: BCRYPT_OAEP_PADDING_INFO,
885}
886
887impl OaepPadding {
888 fn to_ffi_args(&self, out: &mut WindowsString) -> OaepPaddingInfo {
889 *out = WindowsString::from(self.algorithm.to_str());
890 OaepPaddingInfo {
891 _borrowed: self,
892 value: BCRYPT_OAEP_PADDING_INFO {
893 pszAlgId: out.as_ptr(),
894 pbLabel: self.label.as_ptr() as *mut _,
895 cbLabel: self.label.len() as u32,
896 },
897 }
898 }
899}
900
901impl EncryptionPadding {
902 fn to_ffi_args<'a>(&'a self, out: &'a mut WindowsString) -> (Option<OaepPaddingInfo<'a>>, u32) {
903 match self {
904 Self::Oaep(oaep_padding) => (Some(oaep_padding.to_ffi_args(out)), BCRYPT_PAD_OAEP),
905 Self::Pkcs1 => (None, BCRYPT_PAD_PKCS1),
906 }
907 }
908}
909
910impl<P: Parts> AsymmetricKey<Rsa, P> {
911 pub fn encrypt(&self, padding: Option<EncryptionPadding>, data: &[u8]) -> Result<Box<[u8]>> {
913 let mut out = WindowsString::new();
914 let padding = padding.as_ref().map(|x| x.to_ffi_args(&mut out));
915
916 let (pad_info, flags) = padding.as_ref().unwrap_or(&(None, 0));
917 let pad_info = pad_info
918 .as_ref()
919 .map(|pad| &pad.value as *const BCRYPT_OAEP_PADDING_INFO as *mut _);
920
921 let mut encrypted_len = 0;
922 unsafe {
923 crate::Error::check(BCryptEncrypt(
924 self.0.as_ptr(),
925 data.as_ptr() as _,
926 data.len() as _,
927 pad_info.unwrap_or_else(null_mut),
928 null_mut(),
929 0,
930 null_mut(),
931 0,
932 &mut encrypted_len,
933 *flags,
934 ))?;
935
936 let mut output = vec![0u8; encrypted_len as usize];
937
938 crate::Error::check(BCryptEncrypt(
939 self.0.as_ptr(),
940 data.as_ptr() as _,
941 data.len() as _,
942 pad_info.unwrap_or_else(null_mut),
943 null_mut(),
944 0,
945 output.as_mut_ptr(),
946 output.len() as u32,
947 &mut encrypted_len,
948 *flags,
949 ))
950 .map(|_| output.into_boxed_slice())
951 }
952 }
953}
954
955impl AsymmetricKey<Rsa, Private> {
956 pub fn decrypt(&self, padding: Option<EncryptionPadding>, data: &[u8]) -> Result<Box<[u8]>> {
958 let mut out = WindowsString::new();
959 let padding = padding.as_ref().map(|x| x.to_ffi_args(&mut out));
960
961 let (pad_info, flags) = padding.as_ref().unwrap_or(&(None, 0));
962 let pad_info = pad_info
963 .as_ref()
964 .map(|pad| &pad.value as *const BCRYPT_OAEP_PADDING_INFO as *mut _);
965
966 let mut encrypted_len = 0;
967 unsafe {
968 crate::Error::check(BCryptDecrypt(
969 self.0.as_ptr(),
970 data.as_ptr() as _,
971 data.len() as _,
972 pad_info.unwrap_or_else(null_mut),
973 null_mut(),
974 0,
975 null_mut(),
976 0,
977 &mut encrypted_len,
978 *flags,
979 ))?;
980
981 let mut output = vec![0u8; encrypted_len as usize];
982
983 crate::Error::check(BCryptDecrypt(
984 self.0.as_ptr(),
985 data.as_ptr() as _,
986 data.len() as _,
987 pad_info.unwrap_or_else(null_mut),
988 null_mut(),
989 0,
990 output.as_mut_ptr(),
991 output.len() as u32,
992 &mut encrypted_len,
993 *flags,
994 ))
995 .map(|_| output.into_boxed_slice())
996 }
997 }
998}
999
1000#[cfg(test)]
1001mod tests {
1002 use super::*;
1003
1004 #[test]
1005 fn import_export() -> Result<()> {
1006 let dynamic = AsymmetricKey::builder(AsymmetricAlgorithmId::Rsa)
1007 .key_bits(1024)
1008 .build()?;
1009 let blob = dynamic.export()?;
1010 let blob = blob.try_into().unwrap_or_else(|_| panic!());
1011
1012 let provider = AsymmetricAlgorithm::open(AsymmetricAlgorithmId::Rsa)?;
1013 let imported = AsymmetricKey::<_, Private>::import(Rsa, &provider, &blob)?;
1014 let imported_blob = imported.export()?;
1015
1016 assert_eq!(blob.modulus(), imported_blob.modulus());
1017 assert_eq!(blob.pub_exp(), imported_blob.pub_exp());
1018 assert_eq!(blob.prime1(), imported_blob.prime1());
1019
1020 AsymmetricKey::<Rsa, Private>::import_from_parts(
1021 &provider,
1022 &RsaKeyPrivatePayload {
1023 pub_exp: blob.pub_exp(),
1024 modulus: blob.modulus(),
1025 prime1: blob.prime1(),
1026 prime2: blob.prime2(),
1027 },
1028 )?;
1029
1030 let key = AsymmetricKey::builder(Ecdsa(NistP521)).build()?;
1031 let blob = key.export()?;
1032 dbg!(blob.x().len());
1033 dbg!(blob.y().len());
1034 dbg!(blob.d().len());
1035
1036 let key = AsymmetricKey::builder(Ecdh(Curve25519)).build()?;
1037 let blob = key.export()?;
1038 dbg!(blob.x().len());
1039 dbg!(blob.y().len());
1040 dbg!(blob.d().len());
1041 Ok(())
1042 }
1043
1044 #[test]
1045 fn encrypt_decrypt() {
1046 let key = AsymmetricKey::builder(Rsa).key_bits(1024).build().unwrap();
1047
1048 let plaintext = b"This is an important message.";
1049
1050 let ciphertext = key.encrypt(None, &*plaintext);
1051 assert!(ciphertext.is_err());
1053
1054 let padding = Some(EncryptionPadding::Pkcs1);
1055 let ciphertext = key.encrypt(padding.clone(), &*plaintext).unwrap();
1056 assert_eq!(ciphertext.len(), 1024 / 8);
1057 let decoded = key.decrypt(padding, ciphertext.as_ref()).unwrap();
1058 assert_eq!(plaintext, decoded.as_ref());
1059
1060 let padding = Some(EncryptionPadding::Oaep(OaepPadding {
1061 algorithm: crate::hash::HashAlgorithmId::Sha256,
1062 label: Vec::from(b"some data" as &[_]),
1063 }));
1064 let ciphertext = key.encrypt(padding.clone(), &*plaintext).unwrap();
1065 assert_eq!(ciphertext.len(), 1024 / 8);
1066 let decoded = key.decrypt(padding.clone(), ciphertext.as_ref()).unwrap();
1067 assert_eq!(plaintext, decoded.as_ref());
1068
1069 let blob = key.as_public().export().unwrap();
1071 let provider = AsymmetricAlgorithm::open(AsymmetricAlgorithmId::Rsa).unwrap();
1072 let public_key = AsymmetricKey::<Rsa, Public>::import(Rsa, &provider, &blob).unwrap();
1073
1074 let padding = Some(EncryptionPadding::Pkcs1);
1075 let ciphertext = public_key.encrypt(padding.clone(), &*plaintext).unwrap();
1076 assert_eq!(ciphertext.len(), 1024 / 8);
1077 let decoded = key.decrypt(padding, ciphertext.as_ref()).unwrap();
1078 assert_eq!(plaintext, decoded.as_ref());
1079 }
1080
1081 #[test]
1082 fn send() {
1083 use crate::helpers::assert_send;
1084 assert_send::<AsymmetricAlgorithm>();
1085 assert_send::<AsymmetricKey>();
1086 assert_send::<AsymmetricKey<Rsa, Private>>();
1087 assert_send::<AsymmetricKey<Ecdh<Curve25519>, Private>>();
1088 }
1089}