如何使用机器的TPM模块加密字节?

加密数据

Windows提供了一个(相对)简单的API使用CryptProtectData API加密blob,我们可以包装一个易于使用的函数:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //...
}
ProtectBytes的详细信息远不如您可以轻松使用它的思想重要:
  • 这是我想要通过System
  • 中保存的 key 加密的字节
  • 还给我加密的blob

  • 返回的Blob是未记录的结构,其中包含解密和返回原始数据所需的所有内容(哈希算法,密码算法,salt,HMAC签名等)。

    为了完整起见,这是ProtectBytes的示例伪代码实现,该示例使用Crypt API保护字节:

    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.
    }
    

    TPM怎么做?

    上面的代码仅对本地计算机的数据加密有用。使用System帐户作为 key 生成器(details, while interesting, are unimportant)对数据进行加密。最终结果是我可以加密只能由本地计算机解密的数据(例如,硬盘驱动器加密主 key )。

    现在是时候将这一步骤更进一步了。我想加密一些只能由本地TPM解密的数据(例如,硬盘驱动器加密主 key )。换句话说,我想在下面用于Android的框图中用Windows中的TPM替换高通可信执行环境(TEE):

    注意:我意识到TPM不会进行数据签名(或者,如果这样做,则不能保证对相同数据进行签名每次都会给出相同的二进制输出)。这就是为什么我愿意将“RSA签名”替换为“用硬件绑定(bind) key 加密256位Blob”的原因。

    那么代码在哪里?

    问题是TPM编程是completely undocumented on MSDN。没有可用于执行任何操作的API。取而代之的是,您必须自己查找Trusted Computing Group's Software Stack (aka TSS)的副本,找出要以有效负载以什么顺序发送到TPM的命令,然后调用Window's Tbsip_Submit_Command function直接提交命令:
    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没有更高级别的API来执行操作。

    这在道德上等同于尝试通过向硬盘驱动器发出SATA I/O命令来创建文本文件。

    为什么不只使用裤子

    可信计算小组(TCG)确实定义了自己的API:TCB Software Stack (TSS)。此API的实现是由某些人创建的,称为TrouSerS。然后一个人ported that project to Windows

    该代码的问题在于它无法移植到Windows世界中。例如,您不能在Delphi中使用它,也不能从C#中使用它。这个需要:
  • OpenSSL
  • pThread

  • 我只希望代码用我的TPM加密某些内容。

    上面的CryptProtectData除了函数体中的内容外,什么都不需要。

    使用TPM加密数据的等效代码是什么?正如其他人指出的,you probably have to consult the three TPM manuals, and construct the blobs yourself。它可能涉及TPM_seal命令。虽然我认为我不想密封数据,但我想我想绑定(bind):



    我尝试阅读三个必需的卷,以找到我需要的20行代码:
  • Part 1 - Design Principles
  • Part 2 - Structures of the TPM
  • Part 3 - Commands

  • 但是我不知道我在读什么。如果有任何教程或示例,我可能会尝试一下。但是我完全迷路了。

    所以我们问Stackoverflow

    以同样的方式,我能够提供:

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

    有人可以提供相应的等效项:

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

    除了将 key 锁定在System LSA中之外,是否将同一件事锁定在TPM中?

    研究开始

    我不知道绑定(bind)到底意味着什么。但是,在TPM Main-Part 3 Commands-Specification Version 1.2中,提到了 bind :



    令人困惑的是 no Tspi_Data_Bind命令。

    研究工作

    令人震惊的是,没有人愿意花时间记录TPM或其操作。好像他们花了所有时间想出这个好玩的东西,但不想处理使它可用于某些东西的痛苦步骤。

    从(现在)免费书籍A Practical Guide to TPM 2.0: Using the Trusted Platform Module in the New Age of Security开始:



    如何使用TPM的公共(public) key 加密 key ?



    开发人员如何锁定TPM的 key ?



    这可能有效。如果TPM具有 secret HMAC key ,并且只有我的TPM知道HMAC key ,那么我可以将“Sign(也称为TPM用其私钥加密)”替换为“HMAC”。但是,在接下来的一行中,他完全扭转了自己:



    如果必须指定HMAC key ,这不是TPM secret 。当您意识到这是TPM提供的有关加密实用程序的章节时,HMAC key 不是 secret 这一事实变得很有意义。无需您自己编写SHA2,AES,HMAC或RSA,您可以重用TPM已有的内容。



    出色的!你怎么做呢!?



    TPM 是否能够生成加密 key 并在硬件边界内保护其 secret ?是这样吗?



    出色的!这正是我碰巧想要的用例。这也是Microsoft使用TPM的用例。我该怎么做!?

    因此,我阅读了整本书,但没有提供任何帮助。这很令人印象深刻,因为它有375页。您想知道书中包含什么-回头看,我不知道。

    因此,我们放弃了对TPM进行编程的权威指南,转而使用Microsoft的一些文档:

    来自Microsoft TPM Platform Crypto-Provider Toolkit。它确切地提到了我想做什么:



    TPM内部的某个地方是RSA私钥。那个 key 被锁在那儿了-外界再也看不到了。我希望TPM用它的私钥签名(即用它的私钥加密)。

    所以我想要可能存在的最基本的操作:

    用您的私钥加密某些内容。我什至还没有要求更复杂的东西:
  • 基于PCR状态“密封”
  • 创建 key 并将其存储在 volatile 或非 volatile 存储器中
  • 创建对称 key ,然后尝试将其加载到TPM


  • 我要求TPM可以执行的最基本的操作。为什么不可能获得有关如何做的任何信息?

    我可以得到随机数据

    当我说RSA签名是TPM可以做的最基本的事情时,我想我是glib。可以要求TPM执行的基本操作是给我随机字节。 我已经知道该怎么做:
    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;
    }
    

    花式的东西

    我意识到使用TPM的人数很少。这就是为什么Stackoverflow上没有人提供答案的原因。因此,我不能太贪婪地寻求解决常见问题的方法。但是我真正想做的是“密封”一些数据:

  • 向TPM提供一些数据(例如32字节的 key Material )
  • 使TPM加密数据,返回一些不透明的Blob结构
  • 稍后要求TPM解密Blob
  • 只有在TPM的PCR寄存器与加密期间相同的情况下,解密才能起作用。

  • 换一种说法:
    Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
    {
       //...
    }
    
    Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
    {
       //...
    }
    

    下一代密码术(Cng,又名BCrypt)支持TPM

    Windows中最初的加密API被称为Crypto API。

    从Windows Vista开始,Crypto API已替换为 Cryptography API: Next Generation (内部称为BestCrypt,缩写为BCrypt,请勿与the password hashing algorithm混淆)。

    Windows附带了两个BCrypt提供程序:
  • Microsoft基本提供程序(MS_PRIMITIVE_PROVIDER)默认:所有primitives (hashing, symmetric encryption, digital signatures, etc)的默认软件实现
  • Microsoft平台加密提供程序(MS_PLATFORM_CRYPTO_PROVIDER):提供TPM访问的提供程序

  • Platform Crypto提供程序未在MSDN上进行文档记录,但是具有2012 Microsoft Research网站的文档:



    似乎Microsoft的意图是使用密码学NG API的 Microsoft平台加密提供程序来展现TPM加密功能。

    使用Microsoft BCrypt进行公钥加密

    鉴于:
  • 我想执行RSA非对称加密(使用TPM)
  • Microsoft BestCrypt supports RSA asymmetric encryption
  • Microsoft BestCrypt具有 TPM提供程序

  • 前进的方法可能是弄清楚如何使用 Microsoft加密下一代API 进行数字签名。

    我的下一步将是使用标准提供程序(MS_PRIMITIVE_PROVIDER)提出使用RSA公钥在BCrypt中进行加密的代码。例如。:
  • 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

  • 有了该代码,我可以切换到使用TPM Provider(MS_PLATFORM_CRYPTO_PROVIDER)。

    2016年2月22日:随着Apple被迫帮助解密用户数据,人们重新关注如何使TPM执行其发明的最简单任务-加密内容。

    这大致相当于每个人都拥有一辆汽车,但没人知道如何启动汽车。只要我们能够通过步骤1 ,它就可以做真正有用和酷的事情。

    奖励阅读
  • Android - Encryption - Storing the encrypted key
  • Android Explorations - Revisiting Android disk encryption
  • DPAPI Secrets. Security analysis and data recovery in DPAPI (Part 1)
  • 最佳答案

    底漆

    接下来是关于TPM 1.2。请记住,Microsoft要求所有将来的Windows版本都使用TPM 2.0。 2.0代与1.2代根本不同

    由于TPM设计原则,没有一线解决方案。将TPM视为资源有限的微 Controller 。它的主要设计目标是便宜而又安全。因此,TPM被剥夺了安全操作不需要的所有逻辑。因此,TPM仅在您至少有一些或多或少的 fat 软件,以正确的顺序发出许多命令时才起作用。这些命令序列可能会变得非常复杂。这就是为什么TCG用明确定义的API指定TSS的原因。如果您想使用Java,甚至还有一个高级Java API。我不知道C#/.net的类似项目

    发展

    对于您的情况,建议您查看IBM的软件TPM。

  • Project page
  • Donwload the whole package

  • 在软件包中,您将找到3个非常有用的组件:
  • 一个软件TPM仿真器
  • 一个轻量级的tpm lib
  • 一些基本的命令行实用程序

  • 您不一定需要软件TPM仿真器,也可以连接到计算机的硬件TPM。但是,您可以拦截发出的命令并查看响应,从而了解它们的组装方式以及它们与命令规范的对应关系。

    高水平

    先决条件:
  • TPM已激活
  • 加载
  • TPM驱动程序
  • 您已拥有TPM的所有权

  • 为了密封 Blob ,您需要执行以下操作:
  • 创建 key
  • 将 keystore 存储在
  • 确保 key 已在TPM中加载
  • 密封 Blob

  • 要开封,您需要:
  • 获取 key
  • 将 key 加载到TPM
  • 解封密封的 Blob

  • 您可以将 key blob存储在用于存储 protected 字节的数据结构中。

    您需要的大多数TPM命令都是授权命令。因此,您需要在需要的地方建立授权 session 。这些 Activity 主要是OSAP session 。

    TPM命令

    目前,我无法运行调试版本,因此无法为您提供确切的顺序。因此,请考虑使用以下无序命令列表:
  • TPM_OSAP
  • TPM_CreateWrapKey
  • TPM_LoadKey2
  • TPM_Seal

  • 如果您也想读取当前的PCR值:
  • TPM_PCRRead
  • 10-08 08:08