How to encrypt bytes using the TPM (Trusted Platform Module) Ask Question

How to encrypt bytes using the TPM (Trusted Platform Module) Ask Question

How can I encrypt bytes using a machine's TPM module?

CryptProtectData

Windows provides a (relatively) simple API to encrypt a blob using the CryptProtectData API, which we can wrap an easy to use function:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //...
}

The details of ProtectBytes are less important than the idea that you can use it quite easily:

  • here are the bytes I want encrypted by a secret key held by the SYSTEM account
  • give me back the encrypted blob

The returned blob is an undocumented documentation structure that contains everything needed to decrypt and return the original data (hash algorithm, cipher algorithm, salt, HMAC signature, etc).

For completeness, here's the sample pseudocode implementation of ProtectBytes that uses the Crypt API to protect bytes:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //Setup our n-byte plaintext blob
   DATA_BLOB dataIn;
   dataIn.cbData = plaintext.Length;
   dataIn.pbData = Addr(plaintext[0]);

   DATA_BLOB dataOut;

   //dataOut = EncryptedFormOf(dataIn)
   BOOL bRes = CryptProtectData(
         dataIn,
         null,     //data description (optional PWideChar)
         null,     //optional entropy (PDATA_BLOB)
         null,     //reserved
         null,     //prompt struct
         CRYPTPROTECT_UI_FORBIDDEN || CRYPTPROTECT_LOCAL_MACHINE,
         ref dataOut);
   if (!bRes) then
   {
      DWORD le = GetLastError();
      throw new Win32Error(le, "Error calling CryptProtectData");
   }

   //Copy ciphertext from dataOut blob into an actual array
   bytes[] result;
   SetLength(result, dataOut.cbData);
   CopyMemory(dataOut.pbData, Addr(result[0]), dataOut.cbData);

   //When you have finished using the DATA_BLOB structure, free its pbData member by calling the LocalFree function
   LocalFree(HANDLE(dataOut.pbData)); //LocalFree takes a handle, not a pointer. But that's what the SDK says.
}

How to do the same with the TPM?

The above code is useful for encrypting data for the local machine only. The data is encrypted using the SYSTEM account as the key generator (details, while interesting, are unimportant). The end result is that I can encrypt data (e.g. a hard drive encryption master key) that can only be decrypted by the local machine.

Now it's time to take this one step further. I want to encrypt some data (e.g. a hard drive encryption master key) that can only be decrypted by the local TPM. In other words, I want to replace the Qualcomm Trusted Execution Environment (TEE) in the block diagram below for Android, with the TPM in Windows:

ここに画像の説明を入力してください

Note: I realize that the TPM doesn't do data-signing (or if it does, it does not guarantee that signing the same data will give the same binary output every time). Which is why I'd be willing to replace "RSA signing" with "encrypting a 256-bit blob with a hardware bound key".

So where's the code?

The problem is that TPM programming is completely undocumented on MSDN. There is no API available to perform any operations. Instead you have to find yourself a copy of the Trusted Computing Group's Software Stack (aka TSS), figure out what commands to send to the TPM, with payloads, in what order, and call Window's Tbsip_Submit_Command function to submit commands directly:

TBS_RESULT Tbsip_Submit_Command(
  _In_     TBS_HCONTEXT hContext,
  _In_     TBS_COMMAND_LOCALITY Locality,
  _In_     TBS_COMMAND_PRIORITY Priority,
  _In_     const PCBYTE *pabCommand,
  _In_     UINT32 cbCommand,
  _Out_    PBYTE *pabResult,
  _Inout_  UINT32 *pcbOutput
);

Windows has no higher level API to perform actions.

It's the moral equivalent of trying to create a text file by issuing SATA I/O commands to your hard drive.

Why not just use Trousers

The Trusted Computing Group (TCG) did define their own API: TCB Software Stack (TSS). An implementation of this API was created by some people, and is called TrouSerS. A guy then ported that project to Windows.

The problem with that code is that it is not portable into the Windows world. For example, you can't use it from Delphi, you cannot use it from C#. It requires:

  • OpenSSL
  • pThread

I just want the code to encrypt something with my TPM.

The above CryptProtectData requires nothing other than what's in the function body.

What is the equivalent code to encrypt data using the TPM? As others have noted, you probably have to consult the three TPM manuals, and construct the blobs yourself. It probably involves the TPM_seal command. Although I think I don't want to seal data, I think I want to bind it:

Binding – encrypts data using TPM bind key, a unique RSA key descended from a storage key. Sealing – encrypts data in a similar manner to binding, but in addition specifies a state in which TPM must be in order for the data to be decrypted (unsealed)

I try to read the three required volumes in order to find the 20 lines of code I need:

But I have no idea what I'm reading. If there was any kind of tutorial or examples, I might have a shot. But I'm completely lost.

So we ask Stackoverflow

In the same way I was able to provide:

Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
   //...
   CryptProtectData(...); 
   //...
}

can someone provide the corresponding equivalent:

Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
   //...
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   Tbsip_Submit_Command(...);
   //...snip...
   Tbsip_Submit_Command(...);
   //...
}

that does the same thing, except rather than a key locked away in System LSA, is locked away in the TPM?

Start of Research

I don't know exactly what bind means. But looking at TPM Main - Part 3 Commands - Specification Version 1.2, there is a mention of bind:

10.3 TPM_UnBind

TPM_UnBind takes the data blob that is the result of a Tspi_Data_Bind command and decrypts it for export to the User. The caller must authorize the use of the key that will decrypt the incoming blob. TPM_UnBind operates on a block-by-block basis, and has no notion of any relation between one block and another.

What's confusing is there is no Tspi_Data_Bind command.

Research Effort

It is horrifying how nobody has ever bothered to document the TPM or its operation. It's as if they spent all their time coming up with this cool thing to play with, but didn't want to deal with the painful step of making it usable for something.

Starting with the (now) free book A Practical Guide to TPM 2.0: Using the Trusted Platform Module in the New Age of Security:

Chapter 3 - Quick Tutorial on TPM 2.0

The TPM has access to a self-generated private key, so it can encrypt keys with a public key and then store the resulting blob on the hard disk. This way, the TPM can keep a virtually unlimited number of keys available for use but not waste valuable internal storage. Keys stored on the hard disk can be erased, but they can also be backed up, which seemed to the designers like an acceptable trade-off.

How can I encrypt a key with the TPM's public key?

Chapter 4 - Existing Applications That Use TPMs

Applications That Should Use the TPM but Don’t

In the past few years, the number of web-based applications has increased. Among them are web-based backup and storage. A large number of companies now offer such services, but as far as we are aware, none of the clients for these services let the user lock the key for the backup service to a TPM. If this were done, it would certainly be nice if the TPM key itself were backed up by duplicating it on multiple machines. This appears to be an opportunity for developers.

How does a developer lock a key to the TPM?

Chapter 9 - Heirarchies

USE CASE: STORING LOGIN PASSWORDS

A typical password file stores salted hashes of passwords. Verification consists of salting and hashing a supplied password and comparing it to the stored value. Because the calculation doesn’t include a secret, it’s subject to an offline attack on the password file.

This use case uses a TPM-generated HMAC key. The password file stores an HMAC of the salted password. Verification consists of salting and HMACing the supplied password and comparing it to the stored value. Because an offline attacker doesn’t have the HMAC key, the attacker can’t mount an attack by performing the calculation.

This could work. If the TPM has a secret HMAC key, and only my TPM knows the HMAC key, then I could replace "Sign (aka TPM encrypt with it's private key)" with "HMAC". But then in the very next line he reverses himself completely:

TPM2_Create, specifying an HMAC key

It's not a TPM secret if I have to specify the HMAC key. The fact that the HMAC key isn't secret makes sense when you realize this is the chapter about cryptographic utilities that the TPM provides. Rather than you having to write SHA2, AES, HMAC, or RSA yourself, you can re-use what the TPM already has laying around.

Chapter 10 - Keys

As a security device, the ability of an application to use keys while keeping them safe in a hardware device is the TPM’s greatest strength. The TPM can both generate and import externally generated keys. It supports both asymmetric and symmetric keys.

Excellent! How do you do it!?

Key Generator

Arguably, the TPM’s greatest strength is its ability to generate a cryptographic key and protect its secret within a hardware boundary. The key generator is based on the TPM’s own random number generator and doesn’t rely on external sources of randomness. It thus eliminates weaknesses based on weak softwaresoftware with an insufficient source of entropy.

Does the TPM have the ability to generate cryptographic keys and protect its secrets within a hardware boundary? Is so, how?

Chapter 12 - Platform Configuration Registers

PCRs for Authorization

USE CASE: SEALING A HARD DISK ENCRYPTION KEY TO PLATFORM STATE

Full-disk encryption applications are far more secure if a TPM protects theencryption key than if it’s stored on the same disk, protected only by a password. First, the TPM hardware has anti-hammering protection (see Chapter 8 for a detailed description of TPM dictionary attack protection), making a brute-force attack on the password impractical. A key protected only by software is far more vulnerable to a weak password. Second, a software key stored on disk is far easier to steal. Take the disk (or a backup of the disk), and you get the key. When a TPM holds the key, the entire platform, or at least the disk and the motherboard, must be stolen.

Sealing permits the key to be protected not only by a password but by a policy. A typical policy locks the key to PCR values (the software state) current at the time of sealing. This assumes that the state at first boot isn’t compromised. Any preinstalled malware present at first boot would be measured into the PCRs, and thus the key would be sealed to a compromised software state. A less trusting enterprise might have a standard disk image and seal to PCRs representing that image. These PCR values would be precalculated on a presumably more trusted platform. An even more sophisticated enterprise would use TPM2_PolicyAuthorize, and provide several tickets authorizing a set of trusted PCR values. See Chapter 14 for a detailed description of policy authorize and its application to solve the PCRbrittleness problem.

Although a password could also protect the key, there is a security gain even without a TPM key password. An attacker could boot the platform without supplying a TPMkey password but could not log in without the OS username and password. The OSsecurity protects the data. The attacker could boot an alternative OS, say from a live DVD or USB stick rather that from the hard drive, to bypass the OS login security. However, this different boot configuration and software would change the PCRvalues. Because these new PCRs would not match the sealed values, the TPM would not release the decryption key, and the hard drive could not be decrypted.

Excellent! This is exactly the use case I happen to want. It's also the use case the Microsoft uses the TPM for. How do I do it!?

So I read that entire book, and it provided nothing useful. Which is quite impressive because it's 375 pages. You wonder what the book contained - and looking back on it, I have no idea.

So we give up on the definitive guide to programming the TPM, and turn instead to some documentation from Microsoft:

From the Microsoft TPM Platform Crypto-Provider Toolkit. It mentions exactly what I want to do:

The Endorsement Key or EK

The EK is designed to provide a reliable cryptographic identifier for the platform. An enterprise might maintain a database of the Endorsement Keys belonging to the TPMs of all of the PCs in their enterprise, or a data center fabric controller might have a database of the TPMs in all of the blades. On Windows you can use the NCrypt provider described in the section “Platform Crypto Provider in Windows 8” to read the public part of the EK.

Somewhere inside the TPM is an RSA private key. That key is locked away in there - never to be seen by the outside world. I want the TPM to sign something with it's private key (i.e. encrypt it with it's private key).

So I want the most basic operation that can possibly exist:

ここに画像の説明を入力してください

Encrypt something with your private key. I'm not even (yet) asking for the more complicated stuff:

  • "sealing" it based on PCR state
  • creating a key and storing it in volatile or non-volatile memroy
  • creating a symmetric key and trying to load it into the TPM

I am asking for the most basic operation a TPM can do. Why is it impossible to get any information about how to do it?

I can get random data

I suppose I was being glib when I said RSA signing was the most basic thing the TPM can do. The most basic thing the TPM can be asked to do is give me random bytes. That I have figured out how to do:

public Byte[] GetRandomBytesTPM(int desiredBytes)
{
   //The maximum random number size is limited to 4,096 bytes per call
   Byte[] result = new Byte[desiredBytes];

   BCRYPT_ALG_HANDLE hAlgorithm;

   BCryptOpenAlgorithmProvider(
         out hAlgorithm,
         BCRYPT_RNG_ALGORITHM, //AlgorithmID: "RNG"
         MS_PLATFORM_CRYPTO_PROVIDER, //Implementation: "Microsoft Platform Crypto Provider" i.e. the TPM
         0 //Flags
   );
   try
   {                
      BCryptGenRandom(hAlgorithm, @result[0], desiredBytes, 0);
   }
   finally
   {
      BCryptCloseAlgorithmProvider(hAlgorithm);
   }

   return result;
}

The Fancy Thing

I realize the volume of people using the TPM is very low. That is why nobody on Stackoverflow has an answer. So I can't really get too greedy in getting a solution to my common problem. But the thing I'd really want to do is to "seal" some data:

ここに画像の説明を入力してください

  • present the TPM some data (e.g. 32 bytes of key material)
  • have the TPM encrypt the data, returning some opaque blob structure
  • later ask the TPM to decrypt the blob
  • the decryption will only work if the TPM's PCR registers are the same as they were during encryption.

In other words:

Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
{
   //...
}

Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
   //...
}

Cryptography Next Gen (Cng, aka BCrypt) supports TPM

The original Cryptography API in Windows was knows as the Crypto API.

Starting with Windows Vista, the Crypto API has been replaced with Cryptography API: Next Generation (internally known as BestCrypt, abbreviated as BCrypt, not to be confused with the password hashing algorithm).

Windows ships with two BCrypt providers:

The Platform Crypto provider is not documented on MSDN, but does have documentation from a 2012 Microsoft Research site:

TPM Platform Crypto-Provider Toolkit

The TPM Platform Crypto Provider and Toolkit contains sample code, utilities and documentation for using TPM-related functionality in Windows 8. Subsystems described include the TPM-backed Crypto-Next-Gen (CNG) platform crypto-provider, and how attestation-service providers can use the new Windows features. Both TPM1.2 and TPM2.0-based systems are supported.

It seems that Microsoft's intent is to surface TPM crypto functionality with the Microsoft Platform Crypto Provider of the Cryptography NG API.

Public key encryption using Microsoft BCrypt

Given that:

a way forward might be to figure out how to do digital signing using the Microsoft Cryptography Next Gen API.

My next step will be to come up with the code to do encryption in BCrypt, with an RSA public key, using the standard provider (MS_PRIMITIVE_PROVIDER). E.g.:

  • modulus: 0xDC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 8209 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 995D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55
  • publicExponent: 65537

With that code functioning, i may be able to switch to using the TPM Provider (MS_PLATFORM_CRYPTO_PROVIDER).

2/22/2016: And with Apple being compelled to help decrypt user data, there is renewed interest in how to make the TPM perform the most simplest task that it was invented for - encrypting something.

It's roughly equivalent to everyone owning a car, but nobody knows how to start one. It can do really useful and cool things, if only we could get past Step 1.

Microsoft Key Storage API

Microsoft's TPM Base Servicesarchive documentation homepage says we probably want to use the Key Storage API instead:

Note

The TPM can be used for key storage operations. However, developers are encouraged to use the Key Storage APIs for these scenarios instead. The Key Storage APIs provide the functionality to create, sign or encrypt with, and persist cryptographic keys, and they are higher-level and easier to use than the TBS for these targeted scenarios.

The introduction to the Key Storage APIarchive says:

Key Storage Architecture

CNG provides a model for private key storage that allows adapting to the current and future demands of creating applications that use cryptography features such as public or private key encryption, as well as the demands of the storage of key material. The key storage router is the central routine in this model and is implemented in Ncrypt.dll. An application accesses the key storage providers (KSPs) on the system through the key storage router, which conceals details, such as key isolation, from both the application and the storage provider itself. The following illustration shows the design and function of the CNG key isolation architecture.

ここに画像の説明を入力してください

And they note that hardware security modules (presumably the term for a TPM) are supported:

As described above, a wide range of hardware storage devices can be supported. In each case, the interface to all of these storage devices is identical. It includes functions to perform various private key operations as well as functions that pertain to key storage and management.

Only thing I don't know is if you have to ask to use a HSM, or does it happens automatically when available (and how to know when it isn't available - so you don't try to proceed anyway).

Bonus Reading

ベストアンサー1

Primer

All that follows is about TPM 1.2. Keep in mind that Microsoft requires a TPM 2.0 for all future Windows versions. The 2.0 generation is fundamentally different to the 1.2

There is no one-line solution because of TPM design principles. Think of the TPM as a microcontroller with limited resources. It main design goal was to be cheap, while still secure. So the TPM was ripped of all logic which was not necessary for a secure operation. Thus a TPM is only working when you have at least some more or less fat software, issuing a lot of commands in the correct order. And those sequences of commands may get very complex. That's why TCG specified the TSS with a well defined API. If you would like to go the Java way, there is even an high level Java API. I'm not aware of an similar project for C# / .net

Development

In your case I'd suggest you look at IBM's software TPM.

In the package you will find 3 very usefull components:

  • a software TPM emulator
  • a lightweight tpm lib
  • some basic command line utilities

You don't necessarily need the software TPM emulator, you can also connect to the machine's HW TPM. However, you can intercept the issued commands and look at the responses, thus learning how they are assembled and how they correspond to the command specification.

High level

Prerequisites:

  1. TPM is activated
  2. TPM driver is loaded
  3. you have taken ownership of the TPM

In order to seal a blob, you need to do the following:

  1. create a key
  2. store the key-blob somewhere
  3. ensure that the key is loaded in the TPM
  4. seal the blob

To unseal you need to:

  1. obtain the key-blob
  2. load the key to the TPM
  3. unseal the sealed blob

You can store the key-blob in your data structure you use to store the protected bytes.

Most of the TPM commands you need are authorized ones. Therefore you need to establish authorization sessions where needed. AFAIR those are mostly OSAP sessions.

TPM commands

Currently I can't run a debug version, so I can't provide you with the exact sequence. So consider this an unordered list of commands you will have to use:

  • TPM_OSAP
  • TPM_CreateWrapKey
  • TPM_LoadKey2
  • TPM_Seal

If you want to read the current PCR values, too:

  • TPM_PCRRead

おすすめ記事