win_tpm/
lib.rs

1#![cfg(target_os = "windows")]
2use ncrypt::{Algorithm, ExportType, Key, ProviderName, RsaKeyBlob, StorageProvider};
3use rsa::RsaPublicKey;
4
5mod error;
6
7pub use error::Error;
8
9/// Handle to the Windows TPM Key Store Provider
10pub struct Tpm(StorageProvider);
11
12/// Handle to an RSA Key managed by the TPM
13pub struct RsaKey(Key);
14
15/// Iterator over all keys managed by the TPM
16pub struct KeyIterator<'a>(ncrypt::KeyIterator<'a>, &'a Tpm);
17
18pub struct KeyInfo<'a> {
19    pub name: String,
20    pub algorithm: String,
21    tpm: &'a Tpm,
22}
23
24impl Tpm {
25    /// Open a handle to the Windows TPM Key Store Provider
26    ///
27    /// Fails with [`Error::DeviceNotReady`] if no TPM is available
28    pub fn open() -> Result<Self, Error> {
29        let handle = StorageProvider::open(ProviderName::PlatformCrypto).map_err(|e| match e {
30            ncrypt::Error::DeviceNotReady => Error::NotReady(e),
31            _ => Error::Internal(e),
32        })?;
33
34        Ok(Self(handle))
35    }
36
37    pub fn create_rsa_key(&self, key_name: &str) -> Result<RsaKey, Error> {
38        let key = self
39            .0
40            .create_persisted_key(key_name, Algorithm::Rsa)
41            .map_err(|e| match e {
42                ncrypt::Error::ObjectExists => Error::KeyExists(e),
43                _ => Error::Internal(e),
44            })?
45            .finalize()
46            .map_err(Error::Internal)?;
47
48        Ok(RsaKey(key))
49    }
50
51    pub fn open_rsa_key(&self, key_name: &str) -> Result<RsaKey, Error> {
52        let key = self.0.open_key(key_name).map_err(|e| match e {
53            ncrypt::Error::BadKeyset => Error::KeyNotFound(e),
54            _ => Error::Internal(e),
55        })?;
56
57        Ok(RsaKey(key))
58    }
59
60    /// Obtain an iterator over all the keys currently stored on the tpm
61    pub fn enum_keys(&self) -> KeyIterator {
62        KeyIterator(self.0.enum_keys(), self)
63    }
64}
65
66impl RsaKey {
67    /// Exports the public component of the rsa key from the key store
68    ///
69    /// Note: The private key used for decryption never leaves the key store,
70    /// it can't be exported
71    pub fn public_key(&self) -> Result<Box<RsaPublicKey>, Error> {
72        let export = self
73            .0
74            .export(ExportType::RsaPublicKey)
75            .map_err(Error::Internal)?;
76
77        let RsaKeyBlob::PublicKey(key) = export else {
78            return Err(Error::UnexpectedKeyType);
79        };
80
81        Ok(key)
82    }
83
84    /// Encrypts the given data and applies PKCS1 padding
85    pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
86        self.0.encrypt(data).map_err(Error::Internal)
87    }
88
89    /// Decrypts the given data (data MUST have valid PKCS1 padding)
90    pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
91        self.0.decrypt(data).map_err(|e| match e {
92            ncrypt::Error::Other(inner) if inner as u32 == 0x80280095 => Error::DecryptionFailed,
93            _ => Error::Internal(e),
94        })
95    }
96
97    /// Permanently deletes the key from the keystore
98    ///
99    /// THIS CANNOT BE UNDONE
100    pub fn delete(self) {
101        self.0.delete()
102    }
103}
104
105impl<'a> Iterator for KeyIterator<'a> {
106    type Item = KeyInfo<'a>;
107
108    fn next(&mut self) -> Option<Self::Item> {
109        if let Some(item) = self.0.next() {
110            return Some(KeyInfo {
111                name: item.name,
112                algorithm: item.algorithm,
113                tpm: self.1,
114            });
115        }
116
117        None
118    }
119}
120
121impl<'a> KeyInfo<'a> {
122    /// Try to open the key. This will fail if the key is not an rsa key
123    pub fn open(&self) -> Result<RsaKey, Error> {
124        if self.algorithm != "RSA" {
125            return Err(Error::UnexpectedKeyType);
126        }
127
128        self.tpm.open_rsa_key(&self.name)
129    }
130}