Cómo encriptar bytes usando el TPM (Trusted Platform Module)

¿Cómo puedo encriptar bytes usando el módulo TPM de una máquina?

CryptProtectData

Windows proporciona una API (relativamente) simple para encriptar un blob usando elCryptProtectData API, que podemos envolver una función fácil de usar:

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

Los detalles deProtectBytes son menos importantes que la idea de que puedes usarlo con bastante facilidad:

aquí están los bytes que quiero encriptar con una clave secreta contenida en elSystemdevuélveme el blob cifrado

El retornogota es un indocumentadodocumentación estructura que contiene todo lo necesario para descifrar y devolver los datos originales (algoritmo hash, algoritmo de cifrado, sal, firma HMAC, etc.).

Para completar, aquí está la implementación de pseudocódigo de muestra deProtectBytes que usa elCrypt API para proteger 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.
}
¿Cómo hacer lo mismo con el TPM?

El código anterior es útil para cifrar datos solo para la máquina local. Los datos se cifran utilizando elSystem cuenta como el generador de claves (los detalles, aunque interesantes, no son importantes) El resultado final es que puedo cifrar datos (por ejemplo, una clave maestra de cifrado del disco duro) que solo puede ser descifrada por la máquina local.

Ahora es el momento de llevar esto un paso más allá. Quiero cifrar algunos datos (por ejemplo, una clave maestra de cifrado del disco duro) que solo puede ser descifrada por el TPM local. En otras palabras, quiero reemplazar el Entorno de ejecución de confianza de Qualcomm (TEE) en el diagrama de bloques a continuación para Android, con el TPM en Windows:

Nota: Me doy cuenta de que el TPM no hace la firma de datos (o si lo hace, no garantiza que la firma de los mismos datos dará la misma salida binaria cada vez). Por eso estaría dispuesto a reemplazar"Firma RSA" con"cifrar un blob de 256 bits con una clave vinculada por hardware".

Entonces, ¿dónde está el código?

El problema es que la programación TPM escompletamente indocumentado en MSDN. No hay API disponible para realizar ninguna operación. En su lugar, debe buscar una copia delPila de software de Trusted Computing Group (también conocido como TSS), averiguar qué comandos enviar al TPM, con cargas útiles, en qué orden y llamarVentanasTbsip_Submit_Command función para enviar comandos directamente:

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 no tiene una API de nivel superior para realizar acciones.

Es el equivalente moral de tratar de crear un archivo de texto emitiendo comandos de E / S SATA en su disco duro.

¿Por qué no solo usar pantalones?

Trusted Computing Group (TCG) definió su propia API:Pila de software TCB (TSS). Algunas personas crearon una implementación de esta API y se llamaPantalones. Un chico entoncesportó ese proyecto a Windows.

El problema con ese código es que no es portátil en el mundo de Windows. Por ejemplo, no puede usarlo desde Delphi, no puede usarlo desde C #. Requiere:

OpenSSLpThread

Solo quiero elcódigo para encriptar algo con mi TPM.

Lo anteriorCryptProtectData no requiere nada más que lo que hay en el cuerpo de la función.

¿Cuál es el código equivalente para cifrar datos usando el TPM? Como otros han notado,probablemente tenga que consultar los tres manuales de TPM y construir los blobs usted mismo. Probablemente implica elTPM_seal mando. Aunque creo que no quierosello datos, creo que quieroenlazar eso:

Unión - Cifra los datos utilizando la clave de enlace TPM, una clave RSA única que desciende de una clave de almacenamiento.Sellando - cifra los datos de manera similar al enlace, pero además especifica un estado en el que TPM debe estar para que los datos se descifren (sin sellar)

Intento leer los tres volúmenes necesarios para encontrar las 20 líneas de código que necesito:

Parte 1 - Principios de diseñoParte 2 - Estructuras del TPMParte 3 - Comandos

Pero tengoNo idea de lo que estoy leyendo. Si hubiera algún tipo de tutorial o ejemplos, podría tener una oportunidad. Pero estoy completamente perdido.

Entonces le preguntamos a Stackoverflow

De la misma manera pude proporcionar:

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

alguien puede proporcionar el equivalente correspondiente:

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

eso hace lo mismo, excepto en lugar de una llave encerrada enSystem LSA, ¿está encerrado en el TPM?

Inicio de investigación

No se exactamente queenlazar medio. Pero mirando TPM Main - Parte 3 Comandos - Especificación Versión 1.2, hay una mención deenlazar:

10.3 TPM_UnBind

TPM_UnBind toma el blob de datos que es el resultado de un comando Tspi_Data_Bind y lo descifra para exportarlo al Usuario. La persona que llama debe autorizar el uso de la clave que descifrará el blob entrante. TPM_UnBind opera bloque por bloque y no tiene ninguna noción de relación entre un bloque y otro.

Lo que es confuso está ahí.es NoTspi_Data_Bind mando.

Esfuerzo de investigación

Es horrible cómo nadie se ha molestado en documentar el TPM o su funcionamiento. Es como si pasaran todo su tiempo pensando en estocosa para jugar, pero no quería lidiar con el doloroso paso de hacerlousable para algo.

Comenzando con el (ahora) libro gratisUna guía práctica para TPM 2.0: uso del módulo de plataforma confiable en la nueva era de seguridad:

Capítulo 3 - Tutorial rápido en TPM 2.0

El TPM tiene acceso a una clave privada autogenerada, por lo que puede cifrar las claves con una clave pública y luego almacenar el blob resultante en el disco duro. De esta manera, el TPM puede mantener un número prácticamente ilimitado de claves disponibles para su uso, pero no desperdiciará un valioso almacenamiento interno. Las claves almacenadas en el disco duro pueden borrarse, pero también pueden copiarse, lo que a los diseñadores les pareció una compensación aceptable.

¿Cómo puedo cifrar una clave con la clave pública del TPM?

Capítulo 4 - Aplicaciones existentes que usan TPMAplicaciones que deberían usar el TPM pero no

En los últimos años, el número de aplicaciones basadas en la web ha aumentado. Entre ellos se encuentran el respaldo y el almacenamiento basados en la web. Una gran cantidad de compañías ahora ofrecen dichos servicios, pero hasta donde sabemos, ninguno de los clientes de estos servicios permite que el usuario bloquee la clave del servicio de respaldo a un TPM. Si se hiciera esto, sin duda sería bueno si la clave TPM se copiara en varias máquinas. Esto parece ser una oportunidad para los desarrolladores.

¿Cómo bloquea un desarrollador una clave para el TPM?

Capítulo 9 - JerarquíasCASO DE USO: ALMACENAMIENTO DE CONTRASEÑAS DE INICIO DE SESIÓN

Un archivo de contraseña típico almacena hashes de contraseñas salados. La verificación consiste en salar y trocear una contraseña suministrada y compararla con el valor almacenado. Debido a que el cálculo no incluye un secreto, está sujeto a un ataque fuera de línea en el archivo de contraseña.

Este caso de uso utiliza una clave HMAC generada por TPM. El archivo de contraseña almacena un HMAC de la contraseña salada. La verificación consiste en salar y HMACing la contraseña suministrada y compararla con el valor almacenado. Debido a que un atacante sin conexión no tiene la clave HMAC, el atacante no puede montar un ataque realizando el cálculo.

Estapodría trabajo. Si el TPM tiene una clave HMAC secreta, y solo mi TPM conoce la clave HMAC, entonces podría reemplazar "Firmar (también conocido como TPM cifrar con su clave privada)" con "HMAC". Pero luego, en la siguiente línea, se revierte por completo:

TPM2_Create, especificando una clave HMAC

No es un secreto TPM si tengo que especificar la clave HMAC. El hecho de que la clave HMAC no sea secreta tiene sentido cuando te das cuenta de que este es el capítulo sobre las utilidades criptográficas que proporciona el TPM. En lugar de tener que escribir SHA2, AES, HMAC o RSA usted mismo, puede reutilizar lo que ya tiene el TPM.

Capítulo 10 - Llaves

Como dispositivo de seguridad, la capacidad de una aplicación parause las llaves mientras las mantiene a salvo en un dispositivo de hardware es la mayor fortaleza del TPM. El TPM puede generar e importar claves generadas externamente. Admite teclas asimétricas y simétricas.

¡Excelente! ¿¡Cómo lo haces!?

Generador de llaves

Podría decirse que la mayor fortaleza del TPM es su capacidad para generar una clave criptográfica y proteger su secreto dentro de un límite de hardware. El generador de claves se basa en el generador de números aleatorios del TPM y no depende de fuentes externas de aleatoriedad. Por lo tanto, elimina las debilidades basadas en software de software débil con una fuente insuficiente de entropía.

Hace ¿El TPM tiene la capacidad de generar claves criptográficas y proteger sus secretos dentro de un límite de hardware? ¿Es así cómo?

Capítulo 12 - Registros de configuración de la plataformaPCR para autorizaciónCASO DE USO: SELLAR UNA CLAVE DE ENCRIPTACIÓN DE DISCO DURO PARA PLATAFORMAR EL ESTADO

Las aplicaciones de cifrado de disco completo son mucho más seguras si un TPM protege la clave de cifrado que si está almacenada en el mismo disco, protegida solo por una contraseña. Primero, el hardware TPM tiene protección contra el martilleo (consulte el Capítulo 8 para obtener una descripción detallada de la protección contra ataques de diccionario TPM), lo que hace que un ataque de fuerza bruta en la contraseña no sea práctico. Una clave protegida solo por software es mucho más vulnerable a una contraseña débil. En segundo lugar, una clave de software almacenada en el disco es mucho más fácil de robar. Tome el disco (o una copia de seguridad del disco) y obtendrá la clave. Cuando un TPM tiene la llave, se debe robar toda la plataforma, o al menos el disco y la placa base.

El sellado permite que la clave esté protegida no solo por una contraseña sino también por una política. Una política típica bloquea la clave de los valores de PCR (el estado del software) actual en el momento del sellado. Esto supone que el estado en el primer arranque no está comprometido. Cualquier malware preinstalado presente en el primer arranque se mediría en los PCR y, por lo tanto, la clave se sellaría a un estado de software comprometido. Una empresa menos confiable podría tener una imagen de disco estándar y sellar a los PCR que representan esa imagen. Estos valores de PCR se calcularían previamente en una plataforma presumiblemente más confiable. Una empresa aún más sofisticada usaría TPM2_PolicyAuthorize y proporcionaría varios tickets que autorizan un conjunto de valores de PCR confiables. Consulte el Capítulo 14 para obtener una descripción detallada de la autorización de políticas y su aplicación para resolver el problema de brillo de PCR.

Aunque una contraseña también podría proteger la clave, hay una ganancia de seguridad incluso sin una contraseña de clave TPM. Un atacante podría arrancar la plataforma sin proporcionar una contraseña de TPMkey pero no podría iniciar sesión sin el nombre de usuario y la contraseña del sistema operativo. OSsecurity protege los datos. El atacante podría iniciar un sistema operativo alternativo, por ejemplo, desde un DVD en vivo o una memoria USB en lugar de hacerlo desde el disco duro, para evitar la seguridad de inicio de sesión del sistema operativo. Sin embargo, esta configuración y software de arranque diferentes cambiarían los valores de PCR. Debido a que estos nuevos PCR no coincidirían con los valores sellados, el TPM no liberaría la clave de descifrado y el disco duro no podría descifrarse.

¡Excelente! Este es exactamente el caso de uso que deseo. También es el caso de uso para el que Microsoft usa el TPM. ¿¡Cómo lo hago!?

Entonces leí todo el libro y no me proporcionó nada útil. Lo cual es bastante impresionante porque tiene 375 páginas. Te preguntas qué contiene el libro y, si lo recuerdo, no tengo idea.

Por lo tanto, renunciamos a la guía definitiva para programar el TPM, y recurrimos a alguna documentación de Microsoft:

Desde elKit de herramientas de criptoproveedor de plataforma Microsoft TPM. Menciona exactamente lo que quiero hacer:

La clave de aprobación o EK

El EK está diseñado para proporcionar un identificador criptográfico confiable para la plataforma. Una empresa puede mantener una base de datos de las Claves de aprobación que pertenecen a los TPM de todas las PC de su empresa, o un controlador de estructura de centro de datos puede tener una base de datos de los TPM en todos los blades. En Windows, puede usar el proveedor NCrypt descrito en la sección "Proveedor de cifrado de plataforma en Windows 8" para leer la parte pública del EK.

En algún lugar dentro del TPM hay una clave privada RSA. Esa llave está encerrada allí, nunca será vista por el mundo exterior. Quiero que el TPM firme algo con su clave privada (es decir, cifrarlo con su clave privada).

Así que quiero másbásico operación que posiblemente puede existir:

Cifre algo con su clave privada. Ni siquiera estoy (todavía) preguntando por las cosas más complicadas:

"sellando" se basa en el estado de PCRcrear una clave y almacenarla en una memoria volátil o no volátilcreando una clave simétrica e intentando cargarla en el TPM

Estoy pidiendo la operación más básica que puede hacer un TPM. ¿Por qué es imposible obtener información sobre cómo hacerlo?

Puedo obtener datos aleatorios

Supongo que estaba siendo simplista cuando dije que la firma de RSA era lo más básico que podía hacer el TPM. losmás Lo básico que se le puede pedir al TPM que haga es darme bytes aleatorios.Ese He descubierto cómo hacer:

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;
}
La cosa de lujo

Me doy cuenta de que el volumen de personas que usan el TPM es muy bajo. Es por eso que nadie en Stackoverflow tiene una respuesta. Así que no puedo ser demasiado codicioso para encontrar una solución a mi problema común. Pero la cosa que yoDe Verdad querer hacer es"sello" algunos datos:

presentar al TPM algunos datos (por ejemplo, 32 bytes de material clave)haga que el TPM encripte los datos, devolviendo una estructura de gotas opacasluego pida al TPM que descifre el blobel descifrado solo funcionará si los registros de PCR del TPM son los mismos que durante el cifrado.

En otras palabras:

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

Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
   //...
}
Criptografía Next Gen (Cng, también conocido como BCrypt) es compatible con TPM

La API de criptografía original en Windows se conocía como la API de criptografía.

A partir de Windows Vista, la API de cifrado ha sido reemplazada porAPI de criptografía: próxima generación (internamente conocido comoBestCrypt, abreviado comoBCrypt, no debe confundirse conel algoritmo de hash de contraseña)

Windows se envía con dos BCryptproveedores:

Proveedor primitivo de Microsoft (MS_PRIMITIVE_PROVIDER) defecto: Implementación de software predeterminada de todos losprimitivas (hash, cifrado simétrico, firmas digitales, etc.)Proveedor de cifrado de plataforma Microsoft (MS_PLATFORM_CRYPTO_PROVIDER): Proveedor que proporciona acceso TPM

losCrypto de plataforma El proveedor no está documentado en MSDN, pero tiene documentación de un sitio de 2012 de Microsoft Research:

Kit de herramientas de proveedor de cifrado de plataforma TPM

El Kit de herramientas y el proveedor de cifrado de la plataforma TPM contiene código de muestra, utilidades y documentación para usar la funcionalidad relacionada con TPM en Windows 8. Los subsistemas descritos incluyen el proveedor criptográfico de la plataforma Crypto-Next-Gen (CNG) respaldado por TPM y cómo los proveedores de servicios de certificación puede usar las nuevas funciones de Windows. Se admiten los sistemas basados en TPM1.2 y TPM2.0.

Parece que la intención de Microsoft es sacar a la superficie la funcionalidad criptográfica TPM con elProveedor de cifrado de plataforma Microsoft delCriptografía NG API

Cifrado de clave pública con Microsoft BCrypt

Dado que:

Quiero realizar el cifrado asimétrico RSA (usando el TPM)MicrosoftBestCrypt admite el cifrado asimétrico RSAMicrosoft BestCrypt tiene unProveedor TPM

un camino a seguir podría ser descubrir cómo hacer la firma digital usando elAPI de Microsoft Cryptography Next Gen.

Mi próximo paso será crear el código para cifrar en BCrypt, con una clave pública RSA, utilizando el proveedor estándar (MS_PRIMITIVE_PROVIDER) P.ej.:

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 55publicExponent: 65537

Con ese código funcionando, es posible que pueda cambiar a usar el proveedor TPM (MS_PLATFORM_CRYPTO_PROVIDER)

22/02/2016: Y con la obligación de Apple de ayudar a descifrar los datos del usuario, hay un renovado interés en cómo hacer que el TPM realice la tarea más simple para la que se inventó: cifrar algo.

Es más o menos equivalente a que todos tengan un automóvil, pero nadie sabe cómo arrancarlo. Puede hacer cosas realmente útiles y geniales, si solo pudiéramos pasarPaso 1.

Lectura adicionalAndroid - Cifrado - Almacenamiento de la clave cifradaExploraciones de Android: revisión del cifrado de disco de AndroidDPAPI Secrets. Análisis de seguridad y recuperación de datos en DPAPI (Parte 1)

Respuestas a la pregunta(3)

Su respuesta a la pregunta