Skip to main content

Key

Struct Key 

Source
pub struct Key<'d> { /* private fields */ }
Expand description

A loaded TPM key. Its handle is unloaded from the TPM when dropped.

Borrows the Device it lives on, so it cannot outlive the connection.

Implementations§

Source§

impl<'d> Key<'d>

Source

pub fn ecdh_gen(&self) -> Result<EcdhResult>

One-shot ephemeral ECDH: the TPM generates an ephemeral key pair, derives Z against this key’s private part, and returns the ephemeral public point plus Z. A peer holding this key’s private part can recover the same Z from the point via ecdh_z.

Source

pub fn ecdh_z(&self, point: &[u8]) -> Result<Secret>

Recompute the shared secret Z from a peer’s public point (x || y, the output of ecdh_gen) and this key’s private part.

Source§

impl<'d> Key<'d>

Source

pub fn hmac(&self, data: &[u8], hash: HashAlg) -> Result<Vec<u8>>

Compute HMAC over data using this loaded keyed-hash key, whose secret stays inside the TPM. hash must match the algorithm the key was created with (see Template::hmac).

This is the one-shot TPM2_HMAC, so data must fit the TPM’s max command buffer; larger inputs are rejected rather than truncated.

Source§

impl<'d> Key<'d>

Source

pub fn handle(&self) -> u32

The TPM handle value for this key.

Examples found in repository?
examples/create_primary.rs (line 25)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    let dev = Device::open()?;
18    println!("wolfTPM initialized");
19
20    let mut r = [0u8; 16];
21    dev.get_random(&mut r)?;
22    println!("GetRandom: {}", hex(&r));
23
24    let ecc = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?;
25    println!("ECC SRK handle: 0x{:08x}", ecc.handle());
26
27    let rsa = dev.create_primary(Hierarchy::Owner, KeyAlg::Rsa, None)?;
28    println!("RSA SRK handle: 0x{:08x}", rsa.handle());
29
30    Ok(())
31}
More examples
Hide additional examples
examples/full_flow.rs (line 29)
20fn main() -> Result<(), wolftpm::TpmError> {
21    let dev = Device::open()?;
22    println!("device            connected to TPM");
23
24    let mut nonce = [0u8; 16];
25    dev.get_random(&mut nonce)?;
26    println!("get_random        {}", hex(&nonce));
27
28    let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?;
29    println!("create_primary    ECC SRK handle 0x{:08x}", srk.handle());
30
31    let signer = dev.create_and_load(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
32    println!(
33        "create_and_load   signing key handle 0x{:08x}",
34        signer.handle()
35    );
36
37    let digest = [0x11u8; 32];
38    let sig = signer.sign_hash(&digest)?;
39    signer.verify_hash(&digest, &sig)?;
40    println!("sign/verify       {} byte signature, verified", sig.len());
41
42    let sealed = dev.seal(&srk, b"my secret", None)?;
43    let secret = dev.unseal(sealed, &srk, None)?;
44    println!(
45        "seal/unseal       recovered \"{}\"",
46        core::str::from_utf8(&secret).unwrap_or("<bytes>")
47    );
48
49    // Scope the reloaded key so its handle is freed before the attestation
50    // step below. A TPM only holds a few transient objects at once (often 3),
51    // so keep the number of simultaneously-loaded keys small.
52    {
53        let blob = dev.create_key(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
54        let bytes = blob.to_bytes()?;
55        let restored = KeyBlob::from_bytes(&dev, &bytes)?;
56        let loaded = restored.load(&srk, None)?;
57        println!(
58            "key blob          {} bytes, reloaded as handle 0x{:08x}",
59            bytes.len(),
60            loaded.handle()
61        );
62    }
63
64    let before = dev.pcr_read(16, HashAlg::Sha256)?;
65    dev.pcr_extend(16, HashAlg::Sha256, &[0xAB; 32])?;
66    let after = dev.pcr_read(16, HashAlg::Sha256)?;
67    println!(
68        "pcr read/extend   PCR16 {}.. -> {}..",
69        hex(&before[..6]),
70        hex(&after[..6])
71    );
72
73    let index = 0x0150_0100;
74    let _ = dev.nv_delete(index);
75    let mut slot = dev.nv_create(index, 32, None)?;
76    dev.nv_write(&mut slot, b"metadata", 0)?;
77    let mut buf = [0u8; 32];
78    let n = dev.nv_read(&mut slot, &mut buf, 0)?;
79    dev.nv_delete(index)?;
80    println!("nv define/rw      {} bytes at index 0x{:08x}", n, index);
81
82    let aik = dev.create_and_load(&srk, &Template::attestation(KeyAlg::EccP256)?, None)?;
83    let att = dev.certify(&signer, &aik, &nonce)?;
84    println!("certify           {} byte attestation", att.attest.len());
85
86    println!("done              all operations succeeded");
87    Ok(())
88}
Source

pub fn name(&self) -> Vec<u8> ⓘ

The object’s cryptographic Name (the hash of its public area), as computed by the TPM when the key was loaded. Needed to address the key in credential activation (see Device::make_credential).

Source

pub fn export_public(&self, pem: bool) -> Result<Vec<u8>>

Export this key’s public part. pem selects PEM, otherwise DER (ASN.1).

Source§

impl<'d> Key<'d>

Source

pub fn rsa_encrypt(&self, msg: &[u8]) -> Result<Vec<u8>>

Encrypt msg to this key’s public part with RSA-OAEP.

Source

pub fn rsa_decrypt(&self, ciphertext: &[u8]) -> Result<Secret>

Decrypt an RSA-OAEP ciphertext with this key’s private part.

Source

pub fn rsa_encrypt_with_hash( &self, msg: &[u8], hash: HashAlg, ) -> Result<Vec<u8>>

Encrypt msg with RSA-OAEP using an explicit label-hash algorithm.

The plain rsa_encrypt uses the TPM’s default OAEP hash (SHA-256). This variant issues the low-level command directly so any hash the TPM supports can be selected, including HashAlg::Sha1, which Microsoft device enrollment (MS-OAPXBC) requires for its session-key wrap. SHA-1 is legacy and cryptographically weak; select it only for that interop, not for new designs.

Source

pub fn rsa_decrypt_with_hash( &self, ciphertext: &[u8], hash: HashAlg, ) -> Result<Secret>

Decrypt an RSA-OAEP ciphertext using an explicit label-hash algorithm (see rsa_encrypt_with_hash). Supports HashAlg::Sha1 for Microsoft enrollment interop.

Source§

impl<'d> Key<'d>

Source

pub fn sign_hash(&self, digest: &[u8]) -> Result<Vec<u8>>

Sign a pre-computed digest with this key, returning the raw signature.

The scheme/hash come from the key’s template (e.g. ECDSA-SHA256 for a P-256 signing key), so digest must be the matching hash length.

Examples found in repository?
examples/full_flow.rs (line 38)
20fn main() -> Result<(), wolftpm::TpmError> {
21    let dev = Device::open()?;
22    println!("device            connected to TPM");
23
24    let mut nonce = [0u8; 16];
25    dev.get_random(&mut nonce)?;
26    println!("get_random        {}", hex(&nonce));
27
28    let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?;
29    println!("create_primary    ECC SRK handle 0x{:08x}", srk.handle());
30
31    let signer = dev.create_and_load(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
32    println!(
33        "create_and_load   signing key handle 0x{:08x}",
34        signer.handle()
35    );
36
37    let digest = [0x11u8; 32];
38    let sig = signer.sign_hash(&digest)?;
39    signer.verify_hash(&digest, &sig)?;
40    println!("sign/verify       {} byte signature, verified", sig.len());
41
42    let sealed = dev.seal(&srk, b"my secret", None)?;
43    let secret = dev.unseal(sealed, &srk, None)?;
44    println!(
45        "seal/unseal       recovered \"{}\"",
46        core::str::from_utf8(&secret).unwrap_or("<bytes>")
47    );
48
49    // Scope the reloaded key so its handle is freed before the attestation
50    // step below. A TPM only holds a few transient objects at once (often 3),
51    // so keep the number of simultaneously-loaded keys small.
52    {
53        let blob = dev.create_key(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
54        let bytes = blob.to_bytes()?;
55        let restored = KeyBlob::from_bytes(&dev, &bytes)?;
56        let loaded = restored.load(&srk, None)?;
57        println!(
58            "key blob          {} bytes, reloaded as handle 0x{:08x}",
59            bytes.len(),
60            loaded.handle()
61        );
62    }
63
64    let before = dev.pcr_read(16, HashAlg::Sha256)?;
65    dev.pcr_extend(16, HashAlg::Sha256, &[0xAB; 32])?;
66    let after = dev.pcr_read(16, HashAlg::Sha256)?;
67    println!(
68        "pcr read/extend   PCR16 {}.. -> {}..",
69        hex(&before[..6]),
70        hex(&after[..6])
71    );
72
73    let index = 0x0150_0100;
74    let _ = dev.nv_delete(index);
75    let mut slot = dev.nv_create(index, 32, None)?;
76    dev.nv_write(&mut slot, b"metadata", 0)?;
77    let mut buf = [0u8; 32];
78    let n = dev.nv_read(&mut slot, &mut buf, 0)?;
79    dev.nv_delete(index)?;
80    println!("nv define/rw      {} bytes at index 0x{:08x}", n, index);
81
82    let aik = dev.create_and_load(&srk, &Template::attestation(KeyAlg::EccP256)?, None)?;
83    let att = dev.certify(&signer, &aik, &nonce)?;
84    println!("certify           {} byte attestation", att.attest.len());
85
86    println!("done              all operations succeeded");
87    Ok(())
88}
Source

pub fn verify_hash(&self, digest: &[u8], sig: &[u8]) -> Result<()>

Verify sig over digest with this key.

Examples found in repository?
examples/full_flow.rs (line 39)
20fn main() -> Result<(), wolftpm::TpmError> {
21    let dev = Device::open()?;
22    println!("device            connected to TPM");
23
24    let mut nonce = [0u8; 16];
25    dev.get_random(&mut nonce)?;
26    println!("get_random        {}", hex(&nonce));
27
28    let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?;
29    println!("create_primary    ECC SRK handle 0x{:08x}", srk.handle());
30
31    let signer = dev.create_and_load(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
32    println!(
33        "create_and_load   signing key handle 0x{:08x}",
34        signer.handle()
35    );
36
37    let digest = [0x11u8; 32];
38    let sig = signer.sign_hash(&digest)?;
39    signer.verify_hash(&digest, &sig)?;
40    println!("sign/verify       {} byte signature, verified", sig.len());
41
42    let sealed = dev.seal(&srk, b"my secret", None)?;
43    let secret = dev.unseal(sealed, &srk, None)?;
44    println!(
45        "seal/unseal       recovered \"{}\"",
46        core::str::from_utf8(&secret).unwrap_or("<bytes>")
47    );
48
49    // Scope the reloaded key so its handle is freed before the attestation
50    // step below. A TPM only holds a few transient objects at once (often 3),
51    // so keep the number of simultaneously-loaded keys small.
52    {
53        let blob = dev.create_key(&srk, &Template::signing(KeyAlg::EccP256)?, None)?;
54        let bytes = blob.to_bytes()?;
55        let restored = KeyBlob::from_bytes(&dev, &bytes)?;
56        let loaded = restored.load(&srk, None)?;
57        println!(
58            "key blob          {} bytes, reloaded as handle 0x{:08x}",
59            bytes.len(),
60            loaded.handle()
61        );
62    }
63
64    let before = dev.pcr_read(16, HashAlg::Sha256)?;
65    dev.pcr_extend(16, HashAlg::Sha256, &[0xAB; 32])?;
66    let after = dev.pcr_read(16, HashAlg::Sha256)?;
67    println!(
68        "pcr read/extend   PCR16 {}.. -> {}..",
69        hex(&before[..6]),
70        hex(&after[..6])
71    );
72
73    let index = 0x0150_0100;
74    let _ = dev.nv_delete(index);
75    let mut slot = dev.nv_create(index, 32, None)?;
76    dev.nv_write(&mut slot, b"metadata", 0)?;
77    let mut buf = [0u8; 32];
78    let n = dev.nv_read(&mut slot, &mut buf, 0)?;
79    dev.nv_delete(index)?;
80    println!("nv define/rw      {} bytes at index 0x{:08x}", n, index);
81
82    let aik = dev.create_and_load(&srk, &Template::attestation(KeyAlg::EccP256)?, None)?;
83    let att = dev.certify(&signer, &aik, &nonce)?;
84    println!("certify           {} byte attestation", att.attest.len());
85
86    println!("done              all operations succeeded");
87    Ok(())
88}
Source§

impl<'d> Key<'d>

Source

pub fn aes_encrypt(&self, data: &[u8], iv: &[u8]) -> Result<Vec<u8>>

Encrypt data with this loaded AES key (see Template::symmetric). iv is the CFB initialization vector (16 bytes for AES).

Source

pub fn aes_decrypt(&self, data: &[u8], iv: &[u8]) -> Result<Secret>

Decrypt data produced by aes_encrypt with the same key and iv. The recovered plaintext is returned in a zeroizing Secret.

Trait Implementations§

Source§

impl<'d> Drop for Key<'d>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<'d> !Freeze for Key<'d>

§

impl<'d> !RefUnwindSafe for Key<'d>

§

impl<'d> !Send for Key<'d>

§

impl<'d> !Sync for Key<'d>

§

impl<'d> !UnwindSafe for Key<'d>

§

impl<'d> Unpin for Key<'d>

§

impl<'d> UnsafeUnpin for Key<'d>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.