win_crypto_ng/
key_blob.rs

1//! Cryptographic key blobs
2
3use crate::blob;
4use crate::helpers::Pod;
5use crate::helpers::{Blob, BlobLayout};
6use std::convert::TryFrom;
7use winapi::shared::bcrypt::*;
8use winapi::shared::ntdef::ULONG;
9
10/// Type of a key blob.
11pub enum BlobType {
12    AesWrapKey,
13    DhPrivate,
14    DhPublic,
15    DsaPublic,
16    DsaPrivate,
17    EccPrivate,
18    EccPublic,
19    KeyData,
20    OpaqueKey,
21    PublicKey,
22    PrivateKey,
23    RsaFullPrivate,
24    RsaPrivate,
25    RsaPublic,
26    LegacyDhPrivate,
27    LegacyDhPublic,
28    LegacyDsaPrivate,
29    LegacyDsaPublic,
30    LegacyDsaV2Private,
31    LegacyRsaPrivate,
32    LegacyRsaPublic,
33}
34
35impl BlobType {
36    pub fn as_value(&self) -> &'static str {
37        match self {
38            BlobType::AesWrapKey => BCRYPT_AES_WRAP_KEY_BLOB,
39            BlobType::DhPrivate => BCRYPT_DH_PRIVATE_BLOB,
40            BlobType::DhPublic => BCRYPT_DH_PUBLIC_BLOB,
41            BlobType::DsaPublic => BCRYPT_DSA_PUBLIC_BLOB,
42            BlobType::DsaPrivate => BCRYPT_DSA_PRIVATE_BLOB,
43            BlobType::EccPrivate => BCRYPT_ECCPRIVATE_BLOB,
44            BlobType::EccPublic => BCRYPT_ECCPUBLIC_BLOB,
45            BlobType::KeyData => BCRYPT_KEY_DATA_BLOB,
46            BlobType::OpaqueKey => BCRYPT_OPAQUE_KEY_BLOB,
47            BlobType::PublicKey => BCRYPT_PUBLIC_KEY_BLOB,
48            BlobType::PrivateKey => BCRYPT_PRIVATE_KEY_BLOB,
49            BlobType::RsaFullPrivate => BCRYPT_RSAFULLPRIVATE_BLOB,
50            BlobType::RsaPrivate => BCRYPT_RSAPRIVATE_BLOB,
51            BlobType::RsaPublic => BCRYPT_RSAPUBLIC_BLOB,
52            BlobType::LegacyDhPrivate => LEGACY_DH_PRIVATE_BLOB,
53            BlobType::LegacyDhPublic => LEGACY_DH_PUBLIC_BLOB,
54            BlobType::LegacyDsaPrivate => LEGACY_DSA_PRIVATE_BLOB,
55            BlobType::LegacyDsaPublic => LEGACY_DSA_PUBLIC_BLOB,
56            BlobType::LegacyDsaV2Private => LEGACY_DSA_V2_PRIVATE_BLOB,
57            BlobType::LegacyRsaPrivate => LEGACY_RSAPRIVATE_BLOB,
58            BlobType::LegacyRsaPublic => LEGACY_RSAPUBLIC_BLOB,
59        }
60    }
61}
62
63impl<'a> TryFrom<&'a str> for BlobType {
64    type Error = &'a str;
65
66    fn try_from(val: &'a str) -> Result<BlobType, Self::Error> {
67        match val {
68            BCRYPT_AES_WRAP_KEY_BLOB => Ok(BlobType::AesWrapKey),
69            BCRYPT_DH_PRIVATE_BLOB => Ok(BlobType::DhPrivate),
70            BCRYPT_DH_PUBLIC_BLOB => Ok(BlobType::DhPublic),
71            BCRYPT_DSA_PUBLIC_BLOB => Ok(BlobType::DsaPublic),
72            BCRYPT_DSA_PRIVATE_BLOB => Ok(BlobType::DsaPrivate),
73            BCRYPT_ECCPRIVATE_BLOB => Ok(BlobType::EccPrivate),
74            BCRYPT_ECCPUBLIC_BLOB => Ok(BlobType::EccPublic),
75            BCRYPT_KEY_DATA_BLOB => Ok(BlobType::KeyData),
76            BCRYPT_OPAQUE_KEY_BLOB => Ok(BlobType::OpaqueKey),
77            BCRYPT_PUBLIC_KEY_BLOB => Ok(BlobType::PublicKey),
78            BCRYPT_PRIVATE_KEY_BLOB => Ok(BlobType::PrivateKey),
79            BCRYPT_RSAFULLPRIVATE_BLOB => Ok(BlobType::RsaFullPrivate),
80            BCRYPT_RSAPRIVATE_BLOB => Ok(BlobType::RsaPrivate),
81            BCRYPT_RSAPUBLIC_BLOB => Ok(BlobType::RsaPublic),
82            LEGACY_DH_PRIVATE_BLOB => Ok(BlobType::LegacyDhPrivate),
83            LEGACY_DH_PUBLIC_BLOB => Ok(BlobType::LegacyDhPublic),
84            LEGACY_DSA_PRIVATE_BLOB => Ok(BlobType::LegacyDsaPrivate),
85            LEGACY_DSA_PUBLIC_BLOB => Ok(BlobType::LegacyDsaPublic),
86            LEGACY_DSA_V2_PRIVATE_BLOB => Ok(BlobType::LegacyDsaV2Private),
87            LEGACY_RSAPRIVATE_BLOB => Ok(BlobType::LegacyRsaPrivate),
88            LEGACY_RSAPUBLIC_BLOB => Ok(BlobType::LegacyRsaPublic),
89            val => Err(val),
90        }
91    }
92}
93
94/// Marker trait for values containing CNG key blob types.
95pub unsafe trait KeyBlob: Sized {
96    // TODO: Require : BlobLayout + Self::Header: AsRef<BCRYPT_KEY_BLOB>
97    // This can be used to cheaply get the magic and to get rid of `unsafe`
98    // trait and make the as_erased call actually safe
99    const VALID_MAGIC: &'static [ULONG];
100
101    fn is_magic_valid(magic: ULONG) -> bool {
102        let accepts_all = Self::VALID_MAGIC.is_empty();
103        accepts_all || Self::VALID_MAGIC.iter().any(|&x| x == magic)
104    }
105}
106
107impl<T> AsRef<Blob<ErasedKeyBlob>> for Blob<T>
108where
109    T: BlobLayout + KeyBlob,
110{
111    fn as_ref(&self) -> &Blob<ErasedKeyBlob> {
112        self.as_erased()
113    }
114}
115
116impl<T> Blob<T>
117where
118    T: BlobLayout + KeyBlob,
119{
120    pub fn magic(&self) -> ULONG {
121        self.as_erased().header().Magic
122    }
123
124    pub fn blob_type(&self) -> Option<BlobType> {
125        magic_to_blob_type(self.magic())
126    }
127
128    pub fn as_erased(&self) -> &Blob<ErasedKeyBlob> {
129        // SAFETY: The `KeyBlob` trait is only implemented for types that also
130        // implement BlobLayout and whose header extends the basic
131        // BCRYPT_KEY_BLOB, which Blob<ErasedKeyBlob> wraps
132        unsafe { self.ref_cast() }
133    }
134
135    // NOTE: TryInto can't be implemented due to blanket generic TryFrom impl,
136    // i.e. U = T provides a blanket Into<T> for T impl.
137    pub fn try_into<U>(self: Box<Self>) -> Result<Box<Blob<U>>, Box<Self>>
138    where
139        U: BlobLayout + KeyBlob,
140    {
141        if !U::is_magic_valid(self.magic()) {
142            return Err(self);
143        }
144
145        Ok(Blob::<U>::from_boxed(self.into_bytes()))
146    }
147}
148
149macro_rules! key_blobs {
150    ($($name: ident, $blob: expr, magic: $([$($val: ident),*])?),*) => {
151        fn magic_to_blob_type(magic: ULONG) -> Option<BlobType> {
152            match magic {
153                $(
154                    $($(| $val)* => Some($blob),)?
155                )*
156                _ => None
157            }
158        }
159
160        $(
161            unsafe impl KeyBlob for $name {
162                const VALID_MAGIC: &'static [ULONG] = &[$($($val),*)?];
163            }
164
165        )*
166    };
167}
168
169key_blobs! {
170    ErasedKeyBlob, BlobType::PublicKey, magic:,
171    DhKeyPublicBlob, BlobType::DhPublic, magic: [BCRYPT_DH_PUBLIC_MAGIC],
172    DhKeyPrivateBlob, BlobType::DhPrivate, magic: [BCRYPT_DH_PRIVATE_MAGIC],
173    DsaKeyPublicBlob, BlobType::DsaPublic, magic: [BCRYPT_DSA_PUBLIC_MAGIC],
174    DsaKeyPrivateBlob, BlobType::DsaPrivate, magic: [BCRYPT_DSA_PRIVATE_MAGIC],
175    DsaKeyPublicV2Blob, BlobType::DsaPublic, magic: [BCRYPT_DSA_PUBLIC_MAGIC_V2],
176    DsaKeyPrivateV2Blob, BlobType::DsaPrivate, magic: [BCRYPT_DSA_PRIVATE_MAGIC_V2],
177    EccKeyPublicBlob, BlobType::EccPublic, magic: [
178        BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC, BCRYPT_ECDH_PUBLIC_P256_MAGIC,
179        BCRYPT_ECDH_PUBLIC_P384_MAGIC, BCRYPT_ECDH_PUBLIC_P521_MAGIC,
180        BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC, BCRYPT_ECDSA_PUBLIC_P256_MAGIC,
181        BCRYPT_ECDSA_PUBLIC_P384_MAGIC, BCRYPT_ECDSA_PUBLIC_P521_MAGIC
182    ],
183    EccKeyPrivateBlob, BlobType::EccPrivate, magic: [
184        BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC, BCRYPT_ECDH_PRIVATE_P256_MAGIC,
185        BCRYPT_ECDH_PRIVATE_P384_MAGIC, BCRYPT_ECDH_PRIVATE_P521_MAGIC,
186        BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC, BCRYPT_ECDSA_PRIVATE_P256_MAGIC,
187        BCRYPT_ECDSA_PRIVATE_P384_MAGIC, BCRYPT_ECDSA_PRIVATE_P521_MAGIC
188    ],
189    RsaKeyPublicBlob, BlobType::RsaPublic, magic: [BCRYPT_RSAPUBLIC_MAGIC],
190    RsaKeyPrivateBlob, BlobType::RsaPrivate, magic: [BCRYPT_RSAPRIVATE_MAGIC],
191    RsaKeyFullPrivateBlob, BlobType::RsaFullPrivate, magic: [BCRYPT_RSAFULLPRIVATE_MAGIC]
192}
193
194blob! {
195    /// Dynamic struct layout for dynamically determined key blob.
196    enum ErasedKeyBlob {},
197    header: BCRYPT_KEY_BLOB,
198    /// Phantom payload for dynamically determined key blob.
199    view: struct ref ErasedKeyPayload {
200        phantom[0],
201    }
202}
203
204unsafe impl Pod for BCRYPT_KEY_BLOB {}
205blob! {
206    /// Dynamic struct layout for [`BCRYPT_RSAPUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
207    enum RsaKeyPublicBlob {},
208    header: BCRYPT_RSAKEY_BLOB,
209    /// Trailing data for [`BCRYPT_RSAPUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
210    ///
211    /// All the fields are stored as a big-endian multiprecision integer.
212    view: struct ref RsaKeyPublicPayload {
213        pub_exp[cbPublicExp],
214        modulus[cbModulus],
215    }
216}
217
218unsafe impl Pod for BCRYPT_RSAKEY_BLOB {}
219blob! {
220    /// Dynamic struct layout for [`BCRYPT_RSAPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
221    enum RsaKeyPrivateBlob {},
222    header: BCRYPT_RSAKEY_BLOB,
223    /// Trailing data for [`BCRYPT_RSAPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
224    ///
225    /// All the fields are stored as a big-endian multiprecision integer.
226    view: struct ref RsaKeyPrivatePayload {
227        pub_exp[cbPublicExp],
228        modulus[cbModulus],
229        prime1[cbPrime1],
230        prime2[cbPrime2],
231    }
232}
233
234blob! {
235    /// Dynamic struct layout for [`BCRYPT_RSAFULLPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
236    enum RsaKeyFullPrivateBlob {},
237    header: BCRYPT_RSAKEY_BLOB,
238    /// Trailing data for [`BCRYPT_RSAFULLPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob).
239    ///
240    /// All the fields are stored as a big-endian multiprecision integer.
241    view: struct ref RsaKeyFullPrivatePayload {
242        pub_exp[cbPublicExp],
243        modulus[cbModulus],
244        prime1[cbPrime1],
245        prime2[cbPrime2],
246        exponent1[cbPrime1],
247        exponent2[cbPrime2],
248        coeff[cbPrime1],
249        priv_exp[cbModulus],
250    }
251}
252
253unsafe impl Pod for BCRYPT_DH_KEY_BLOB {}
254blob! {
255    /// Dynamic struct layout for [`BCRYPT_DH_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dh_key_blob).
256    enum DhKeyPublicBlob {},
257    header: BCRYPT_DH_KEY_BLOB,
258    /// Trailing data for [`BCRYPT_DH_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dh_key_blob).
259    ///
260    /// All the fields are stored as a big-endian multiprecision integer.
261    view: struct ref DhKeyPublicPayload {
262        modulus[cbKey],
263        generator[cbKey],
264        public[cbKey],
265    }
266}
267
268blob! {
269    /// Dynamic struct layout for [`BCRYPT_DH_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dh_key_blob).
270    enum DhKeyPrivateBlob {},
271    header: BCRYPT_DH_KEY_BLOB,
272    /// Trailing data for [`BCRYPT_DH_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dh_key_blob).
273    ///
274    /// All the fields are stored as a big-endian multiprecision integer.
275    view: struct ref DhKeyPrivatePayload {
276        modulus[cbKey],
277        generator[cbKey],
278        public[cbKey],
279        priv_exp[cbKey],
280    }
281}
282
283unsafe impl Pod for BCRYPT_DSA_KEY_BLOB {}
284blob! {
285    /// Dynamic struct layout for [`BCRYPT_DSA_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob).
286    enum DsaKeyPublicBlob {},
287    header: BCRYPT_DSA_KEY_BLOB,
288    /// Trailing data for [`BCRYPT_DSA_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob).
289    ///
290    /// All the fields are stored as a big-endian multiprecision integer.
291    view: struct ref DsaKeyPublicPayload {
292        modulus[cbKey],
293        generator[cbKey],
294        public[cbKey],
295    }
296}
297
298blob! {
299    /// Dynamic struct layout for [`BCRYPT_DSA_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob).
300    enum DsaKeyPrivateBlob {},
301    header: BCRYPT_DSA_KEY_BLOB,
302    /// Trailing data for [`BCRYPT_DSA_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob).
303    ///
304    /// All the fields are stored as a big-endian multiprecision integer.
305    view: struct ref DsaKeyPrivatePayload {
306        modulus[cbKey],
307        generator[cbKey],
308        public[cbKey],
309        priv_exp[20],
310    }
311}
312
313unsafe impl Pod for BCRYPT_DSA_KEY_BLOB_V2 {}
314blob! {
315    /// Dynamic struct layout for
316    /// [`BCRYPT_DSA_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob_v2)
317    /// (V2).
318    enum DsaKeyPublicV2Blob {},
319    header: BCRYPT_DSA_KEY_BLOB_V2,
320    /// Trailing data for
321    /// [`BCRYPT_DSA_PUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob_v2)
322    /// for DSA keys that exceed 1024 bits in length but are less than or equal
323    /// to 3072 bits.
324    ///
325    /// All the fields are stored as a big-endian multiprecision integer.
326    view: struct ref DsaKeyPublicV2Payload {
327        // docs.microsoft.com are incorrect and seems to have a copy/paste mistake.
328        // Refer to layout this layout instead:
329        // https://github.com/dotnet/runtime/blob/67d74fca70d4670ad503e23dba9d6bc8a1b5909e/src/libraries/Common/src/System/Security/Cryptography/DSACng.ImportExport.cs#L246-L254
330        seed[cbSeedLength],
331        group[cbGroupSize],
332        modulus[cbKey],
333        generator[cbKey],
334        public[cbKey],
335    }
336}
337
338blob! {
339    /// Dynamic struct layout for
340    /// [`BCRYPT_DSA_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob_v2)
341    /// (V2).
342    enum DsaKeyPrivateV2Blob {},
343    header: BCRYPT_DSA_KEY_BLOB_V2,
344    /// Trailing data for
345    /// [`BCRYPT_DSA_PRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_dsa_key_blob_v2)
346    /// for DSA keys that exceed 1024 bits in length but are less than or equal
347    /// to 3072 bits.
348    ///
349    /// All the fields are stored as a big-endian multiprecision integer.
350    view: struct ref DsaKeyPrivateV2Payload {
351        // docs.microsoft.com are incorrect and seems to have a copy/paste mistake.
352        // Refer to layout this layout instead:
353        // https://github.com/dotnet/runtime/blob/67d74fca70d4670ad503e23dba9d6bc8a1b5909e/src/libraries/Common/src/System/Security/Cryptography/DSACng.ImportExport.cs#L246-L254
354        seed[cbSeedLength],
355        group[cbGroupSize],
356        modulus[cbKey],
357        generator[cbKey],
358        public[cbKey],
359        priv_exp[cbGroupSize],
360    }
361}
362
363unsafe impl Pod for BCRYPT_ECCKEY_BLOB {}
364blob! {
365    /// Dynamic struct layout for [`BCRYPT_ECCPUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecc_key_blob).
366    enum EccKeyPublicBlob {},
367    header: BCRYPT_ECCKEY_BLOB,
368    /// Trailing data for [`BCRYPT_ECCPUBLIC_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecc_key_blob).
369    ///
370    /// All the fields are stored as a big-endian multiprecision integer.
371    view: struct ref EccKeyPublicPayload {
372        x[cbKey],
373        y[cbKey],
374    }
375}
376
377blob! {
378    /// Dynamic struct layout for [`BCRYPT_ECCPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecckey_blob).
379    enum EccKeyPrivateBlob {},
380    header: BCRYPT_ECCKEY_BLOB,
381    /// Trailing data for [`BCRYPT_ECCPRIVATE_BLOB`](https://docs.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_ecckey_blob).
382    ///
383    /// All the fields are stored as a big-endian multiprecision integer.
384    view: struct ref EccKeyPrivatePayload {
385        x[cbKey],
386        y[cbKey],
387        d[cbKey],
388    }
389}