¿Cómo puedo cifrar bytes usando el módulo TPM de una máquina?
CryptProtectData
Windows proporciona una API (relativamente) simple para cifrar un blob usando la CryptProtectData
API, que podemos envolver en una función fácil de usar:
public Byte[] ProtectBytes(Byte[] plaintext)
{
//...
}
Los detalles de ProtectBytes
son menos importantes que la idea de que puedes usarlo con bastante facilidad:
- aquí están los bytes que quiero encriptados por una clave secreta en el
System
- devuélveme la gota encriptada
El blob devuelto es una estructura de documentación no documentada 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 ProtectBytes
que usa Crypt 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 la System
cuenta como 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 de disco duro) que solo puede descifrar la máquina local.
Ahora es el momento de dar un paso más. Quiero cifrar algunos datos (por ejemplo, una clave maestra de cifrado de disco duro) que solo puede descifrar el TPM local. En otras palabras, quiero reemplazar Qualcomm Trusted Execution Environment ( 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 realiza la firma de datos (o si lo hace, no garantiza que la firma de los mismos datos dé la misma salida binaria cada vez). Es por eso que estaría dispuesto a reemplazar la "firma RSA" por "cifrar un blob de 256 bits con una clave vinculada al hardware" .
Entonces, ¿dónde está el código?
El problema es que la programación de TPM está completamente indocumentada en MSDN . No hay ninguna API disponible para realizar ninguna operación. En su lugar, debe buscar una copia de la pila de software de Trusted Computing Group (también conocida como TSS) , averiguar qué comandos enviar al TPM, con cargas útiles, en qué orden, y llamar a la función Tbsip_Submit_Command de Windows 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 intentar crear un archivo de texto mediante la emisión de comandos de E / S SATA a su disco duro .
¿Por qué no usar pantalones?
Trusted Computing Group (TCG) definió su propia API: TCB Software Stack (TSS) . Algunas personas crearon una implementación de esta API y se llama TrouSerS . Luego, un chico transfirió 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:
- OpenSSL
- pThread
Solo quiero que el código cifre algo con mi TPM.
Lo anterior CryptProtectData
no requiere nada más que lo que está en el cuerpo de la función.
¿Cuál es el código equivalente para cifrar datos usando el TPM? Como han señalado otros, probablemente tenga que consultar los tres manuales de TPM y construir los blobs usted mismo . Probablemente implique el TPM_seal
comando. Aunque creo que no quiero sellar datos, creo que quiero vincularlos :
Enlace : cifra los datos mediante la clave de enlace TPM, una clave RSA única derivada de una clave de almacenamiento. Sellado : cifra los datos de manera similar a la vinculación, pero además especifica un estado en el que debe estar TPM para que los datos se descifren (desbloqueen)
Intento leer los tres volúmenes requeridos para encontrar las 20 líneas de código que necesito:
Pero no tengo ninguna 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(...);
//...
}
que hace lo mismo, excepto que en lugar de una llave guardada en System
LSA, está guardada en el TPM?
Inicio de la investigación
No sé exactamente qué significa enlazar . Pero mirando TPM Main - Part 3 Commands - Specification Version 1.2, hay una mención de bind :
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 noción de ninguna relación entre un bloque y otro.
Lo que es confuso no es ningún Tspi_Data_Bind
comando.
Esfuerzo de investigación
Es espantoso cómo nadie se ha molestado nunca en documentar el TPM o su funcionamiento. Es como si hubieran pasado todo el tiempo ideando algo genial para jugar, pero no quisieran lidiar con el doloroso paso de hacerlo utilizable para algo.
Comenzando con el (ahora) libro gratuito A Practical Guide to TPM 2.0: Using the Trusted Platform Module in the New Age of Security :
Capítulo 3 - Tutorial rápido sobre TPM 2.0
El TPM tiene acceso a una clave privada autogenerada, por lo que puede cifrar 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 virtualmente ilimitado de claves disponibles para su uso, pero sin desperdiciar un valioso almacenamiento interno. Las claves almacenadas en el disco duro se pueden borrar, pero también se pueden hacer copias de seguridad, lo que a los diseñadores les pareció una compensación aceptable.
¿Cómo puedo cifrar una clave con la clave pública de TPM?
Capítulo 4: Aplicaciones existentes que utilizan TPM
Aplicaciones que deberían usar el TPM pero no lo hacen
En los últimos años, ha aumentado el número de aplicaciones basadas en web. Entre ellos se encuentran el respaldo y el almacenamiento basados en la web. Actualmente, un gran número de empresas 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 en un TPM. Si se hiciera esto, sin duda sería bueno si se hiciera una copia de seguridad de la clave TPM duplicándola en varias máquinas. Esta parece ser una oportunidad para los desarrolladores.
¿Cómo bloquea un desarrollador una clave para el TPM?
Capítulo 9 - Jerarquías
CASO DE USO: ALMACENAMIENTO DE CONTRASEÑAS DE INICIO DE SESIÓN
Un archivo de contraseña típico almacena hashes de contraseñas. La verificación consiste en salar y aplicar hash a una contraseña proporcionada y compararla con el valor almacenado. Debido a que el cálculo no incluye un secreto, está sujeto a un ataque sin conexión al 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 con sal. La verificación consiste en salar y HMACing la contraseña proporcionada y compararla con el valor almacenado. Debido a que un atacante fuera de línea no tiene la clave HMAC, el atacante no puede montar un ataque realizando el cálculo.
Esto podría funcionar. 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 encriptar con su clave privada)" por "HMAC". Pero luego, en la siguiente línea, se invierte completamente:
TPM2_Create, especificando una clave HMAC
No es un secreto de TPM si tengo que especificar la clave HMAC. El hecho de que la clave HMAC no sea secreta tiene sentido cuando se da 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 el TPM ya tiene por ahí.
Capítulo 10 - Llaves
Como dispositivo de seguridad, la capacidad de una aplicación para usar claves mientras las mantiene seguras en un dispositivo de hardware es la mayor fortaleza del TPM. El TPM puede generar e importar claves generadas externamente. Es compatible con claves 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 propio generador de números aleatorios del TPM y no depende de fuentes externas de aleatoriedad. De este modo, elimina las debilidades basadas en software débil con una fuente de entropía insuficiente.
¿ 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 plataforma
ITP para autorización
CASO DE USO: SELLADO DE UNA CLAVE DE CIFRADO DE DISCO DURO A LA PLATAFORMA 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 anti-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 a la contraseña sea poco 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 clave, 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) actuales 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 confiada podría tener una imagen de disco estándar y sellar 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 la política y su aplicación para resolver el problema de la fragilidad de la PCR.
Aunque una contraseña también podría proteger la clave, existe una ganancia de seguridad incluso sin una contraseña de clave TPM. Un atacante podría iniciar 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, digamos desde un DVD en vivo o una memoria USB en lugar de desde el disco duro, para evitar la seguridad de inicio de sesión del sistema operativo. Sin embargo, esta configuración de arranque y software 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 se podría descifrar.
¡Excelente! Este es exactamente el caso de uso que quiero. También es el caso de uso para el que Microsoft usa el TPM. ¿¡Cómo lo hago!?
Así que leí todo el libro y no proporcionó nada útil. Lo cual es bastante impresionante porque tiene 375 páginas. Te preguntas qué contenía el libro y, mirando hacia atrás, no tengo ni idea.
Así que renunciamos a la guía definitiva para programar el TPM y, en su lugar, recurrimos a alguna documentación de Microsoft:
Desde el kit de herramientas del proveedor de cifrado de la plataforma Microsoft TPM . Menciona exactamente lo que quiero hacer:
La clave de respaldo 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 del centro de datos puede tener una base de datos de los TPM en todos los blades. En Windows, puede utilizar 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á guardada allí, para que el mundo exterior nunca la vea. Quiero que el TPM firme algo con su clave privada (es decir, que lo cifre con su clave privada).
Entonces quiero la operación más básica que pueda existir:
Cifre algo con su clave privada. Ni siquiera estoy pidiendo (todavía) las cosas más complicadas:
- "sellarlo" según el estado de la PCR
- crear una clave y almacenarla en memroy volátil o no volátil
- creando una clave simétrica e intentando cargarla en el TPM
Estoy solicitando 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 puede hacer el TPM. Lo más básico que se le puede pedir al TPM es que me dé bytes aleatorios. Que 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 elegante
Me doy cuenta de que el volumen de personas que utilizan el TPM es muy bajo. Es por eso que nadie en Stackoverflow tiene una respuesta. Así que realmente no puedo ser demasiado codicioso para encontrar una solución a mi problema común. Pero lo que realmente me gustaría hacer es "sellar" algunos datos:
- presentar al TPM algunos datos (por ejemplo, 32 bytes de material clave)
- hacer que el TPM encripte los datos, devolviendo una estructura de blob opaca
- luego pida al TPM que descifre el blob
- el 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)
{
//...
}
Cryptography Next Gen (Cng, también conocido como BCrypt) admite TPM
La API de criptografía original en Windows se conoce como la API de criptografía.
A partir de Windows Vista, la Crypto API ha sido reemplazada por Cryptography API: Next Generation (internamente conocida como BestCrypt , abreviada como BCrypt , que no debe confundirse con el algoritmo hash de contraseñas ).
Windows se envía con dos proveedores de BCrypt :
- Proveedor primitivo de Microsoft (
MS_PRIMITIVE_PROVIDER
) predeterminado : implementación de software predeterminada de todas las primitivas (hash, cifrado simétrico, firmas digitales, etc.) - Proveedor de cifrado de plataforma Microsoft (
MS_PLATFORM_CRYPTO_PROVIDER
): proveedor que proporciona acceso a TPM
El proveedor de Platform Crypto no está documentado en MSDN, pero tiene documentación de un sitio de Microsoft Research de 2012:
Kit de herramientas para proveedores de cifrado de plataforma TPM
El proveedor 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 de cifrado de la plataforma Crypto-Next-Gen (CNG) respaldado por TPM y cómo los proveedores de servicios de certificación puede utilizar las nuevas funciones de Windows. Se admiten los sistemas basados en TPM1.2 y TPM2.0.
Parece que la intención de Microsoft es mostrar la funcionalidad de cifrado de TPM con el proveedor de cifrado de plataforma de Microsoft de la API de Cryptography NG .
Cifrado de clave pública con Microsoft BCrypt
Dado que:
- quiero realizar un cifrado asimétrico RSA (usando el TPM)
- Microsoft BestCrypt admite el cifrado asimétrico RSA
- Microsoft BestCrypt tiene un proveedor de TPM
un camino a seguir podría ser la de encontrar la manera de hacer la firma digital utilizando la API de criptografía de Microsoft de próxima generación .
Mi siguiente paso será crear el código para realizar el cifrado 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 en funcionamiento, es posible que pueda cambiar al proveedor de TPM ( MS_PLATFORM_CRYPTO_PROVIDER
).
22/02/2016: Y como Apple se ve obligada a ayudar a descifrar los datos del usuario, existe un interés renovado en cómo hacer que el TPM realice la tarea más simple para la que fue inventado: cifrar algo.
Es aproximadamente equivalente a que todo el mundo tenga un coche, pero nadie sabe cómo arrancar uno. Puede hacer cosas realmente útiles y geniales, si tan solo pudiéramos pasar del Paso 1 .