¿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 .
Lectura adicional
fuente
Respuestas:
Cebador
Todo lo que sigue es sobre TPM 1.2. Tenga en cuenta que Microsoft requiere un TPM 2.0 para todas las versiones futuras de Windows. La generación 2.0 es fundamentalmente diferente a la 1.2
No existe una solución de una línea debido a los principios de diseño de TPM. Piense en el TPM como un microcontrolador con recursos limitados. Su principal objetivo de diseño era ser barato y, al mismo tiempo, seguro. Así que el TPM fue despojado de toda lógica que no era necesaria para una operación segura. Por lo tanto, un TPM solo funciona cuando tiene al menos algún software más o menos pesado , emitiendo muchos comandos en el orden correcto. Y esas secuencias de comandos pueden volverse muy complejas. Es por eso que TCG especificó el TSS con una API bien definida. Si desea seguir el camino de Java, existe incluso una API de Java de alto nivel . No tengo conocimiento de un proyecto similar para C # / .net
Desarrollo
En su caso, le sugiero que consulte el software TPM de IBM.
En el paquete encontrará 3 componentes muy útiles:
No necesita necesariamente el emulador de software TPM, también puede conectarse al HW TPM de la máquina. Sin embargo, puede interceptar los comandos emitidos y observar las respuestas, aprendiendo así cómo se ensamblan y cómo se corresponden con la especificación del comando.
Nivel alto
Prerrequisitos:
Para sellar una gota, debe hacer lo siguiente:
Para abrir es necesario:
Puede almacenar el blob de claves en su estructura de datos que usa para almacenar los bytes protegidos.
La mayoría de los comandos de TPM que necesita están autorizados. Por lo tanto, debe establecer sesiones de autorización donde sea necesario. AFAIR, esas son en su mayoría sesiones OSAP.
Comandos TPM
Actualmente no puedo ejecutar una versión de depuración, por lo que no puedo proporcionarles la secuencia exacta. Así que considere esto como una lista desordenada de comandos que tendrá que usar:
TPM_OSAP
TPM_CreateWrapKey
TPM_LoadKey2
TPM_Seal
Si también desea leer los valores actuales de PCR:
TPM_PCRRead
fuente
Claves de confianza y cifradas
Las claves fiables y cifradas son dos nuevos tipos de claves añadidos al servicio de anillo de claves del kernel existente. Ambos tipos nuevos son claves simétricas de longitud variable y, en ambos casos, todas las claves se crean en el kernel y el espacio de usuario ve, almacena y carga solo blobs cifrados. Las claves de confianza requieren la disponibilidad de un chip de módulo de plataforma segura (TPM) para una mayor seguridad, mientras que las claves cifradas se pueden utilizar en cualquier sistema. Todos los blobs de nivel de usuario se muestran y cargan en ascii hexadecimal para mayor comodidad y se verifica su integridad.
Las claves de confianza utilizan un TPM tanto para generar como para sellar las claves. Las claves se sellan con una clave RSA de 2048 bits en el TPM y, opcionalmente, se sellan a valores especificados de PCR (medición de integridad) y solo se desbloquean mediante el TPM, si las PCR y las verificaciones de integridad de blob coinciden. Una clave de confianza cargada se puede actualizar con nuevos (futuros) valores de PCR, por lo que las claves se migran fácilmente a nuevos valores de pcr, como cuando se actualizan el kernel y initramfs. La misma clave puede tener muchos blobs guardados con diferentes valores de PCR, por lo que se admiten fácilmente varios arranques.
De forma predeterminada, las claves de confianza están selladas bajo SRK, que tiene el valor de autorización predeterminado (20 ceros). Esto se puede configurar en el momento takeownership con la utilidad del pantalón:
tpm_takeownership -u -z
.keyctl print
devuelve una copia hexadecimal ascii de la clave sellada, que está en formato estándar TPM_STORED_DATA. La longitud de la clave para las claves nuevas siempre está en bytes. Las claves de confianza pueden ser de 32 a 128 bytes (256 a 1024 bits), el límite superior debe ajustarse a la longitud de clave SRK (RSA) de 2048 bits, con toda la estructura / relleno necesarios.Las claves cifradas no dependen de un TPM y son más rápidas, ya que utilizan AES para el cifrado / descifrado. Las nuevas claves se crean a partir de números aleatorios generados por el kernel y se cifran / descifran utilizando una clave 'maestra' especificada. La clave 'maestra' puede ser una clave confiable o un tipo de clave de usuario. La principal desventaja de las claves cifradas es que si no están enraizadas en una clave de confianza, son tan seguras como la clave de usuario que las cifra. Por lo tanto, la clave de usuario maestra debe cargarse de la manera más segura posible, preferiblemente al principio del inicio.
La parte descifrada de las claves cifradas puede contener una clave simétrica simple o una estructura más compleja. El formato de la estructura más compleja es específico de la aplicación, que se identifica por "formato".
Ejemplos de uso de claves cifradas y confiables
Cree y guarde una clave de confianza llamada "kmk" de 32 bytes de longitud:
Cargue una clave de confianza desde el blob guardado:
Vuelva a sellar una clave de confianza con nuevos valores de pcr:
El consumidor inicial de claves de confianza es EVM, que en el momento del arranque necesita una clave simétrica de alta calidad para la protección HMAC de metadatos de archivos. El uso de una clave confiable proporciona sólidas garantías de que la clave EVM no se ha visto comprometida por un problema de nivel de usuario y, cuando está sellada a valores específicos de PCR de inicio, protege contra ataques de inicio y fuera de línea. Cree y guarde una clave cifrada "evm" utilizando la clave de confianza "kmk" anterior:
opción 1: omitir 'formato'
opción 2: definir explícitamente 'formato' como 'predeterminado'
Cargue una clave cifrada "evm" del blob guardado:
Se anticipan otros usos de claves confiables y cifradas, como para cifrado de archivos y discos. En particular, se ha definido el nuevo formato 'ecryptfs' para utilizar claves cifradas para montar un sistema de archivos eCryptfs. Se pueden encontrar más detalles sobre el uso en el archivo 'Documentation / security / keys-ecryptfs.txt'.
fuente
Documentation/security/keys-ecryptfs.tx
Depende de su intención y circunstancias:
Cada uno de estos casos de uso (y hay más), o una combinación de los mismos, presenta una ruta de implementación diferente. Piense en el TPM como una navaja suiza de dispositivos criptográficos: no hay mucho que no pueda hacer con él, pero la facilidad de uso sufre por esa versatilidad. La pregunta sigue rebotando entre cifrar, firmar y bloquear la configuración del sistema, pero la parte principal de esta respuesta considerará que el comando Seal cubre la mayoría de las necesidades descritas en la pregunta.
Para esto es el comando Bind (reemplazado por el comando Create para TPM 2). Carga una clave que se deriva de una clave vinculada a TPM y la cifra con ella (o directamente con una clave vinculada al hardware). De esta forma, los datos solo se pueden descifrar con acceso al mismo TPM.
No estoy seguro de si replicar todo este proceso es una buena idea. Por un lado, no es necesario utilizar una operación de firma en ningún lugar del proceso. Parece que, en el momento en que se estaba desarrollando Android 5, la API de Keystore se limitaba a las operaciones de firma y verificación. Mi mejor suposición es que el equipo de cifrado de disco hizo todo lo posible para trabajar con lo que tenía y diseñó un algoritmo mediante el cual una de las claves intermedias se derivaba con una operación de firma , utilizando una clave TEE almacenada, vinculando así todo el proceso a un hardware. La clave vinculada solo está disponible en la plataforma, ya que la firma era la única forma de hacerlo en ese momento. Sin embargo, no es necesario limitarse de esa manera si tiene acceso a un TPM, que le brinda más capacidades de las que sabía que necesitaba.
Esto es falso, ambas versiones de TPM admiten la firma.
Esto no tiene sentido. La firma de los mismos datos con la misma clave se producirá la misma firma. Puede estar confundiendo la operación de firma con la operación de cotización, que se mezclará en un momento.
Esta debería ser la opción preferida, aunque ambas son posibles con un TPM. Véase más arriba.
Desafortunadamente, no hay mucho que documentar. La API de Win está limitada a un par de funciones de TBS que se eliminan en un nivel del controlador.
En realidad, no, si tuvieras un TSS no tendrías que usarlo
Tbsip_submit_Command()
. Ese es el objetivo de tener un TSS: los detalles de bajo nivel se abstraen.Sigue siendo cierto para TPM 1, pero para TPM 2 existe TSS.MSR .
Correcto.
No está claro que este sea un desafío insuperable. Acceder a TrouSerS a través de una interoperabilidad debería ser preferible a reescribir todo el código de estructuración de datos. Además, estaba
doTSS
en el momento de redactar la pregunta.La pregunta contiene una cita que describe la diferencia entre los dos comandos, por lo que no debería haber mucha confusión. El sellado es similar al enlace, con la restricción adicional de que el estado del sistema debe ser el mismo para que los datos se desbloqueen.
Primero, vale la pena señalar que hay dos versiones principales de TPM, que son totalmente incompatibles entre sí. De modo que prácticamente ningún código que haya escrito para TPM 1 funcionará para TPM 2. La API de TBS es el único código común entre los dos y, para ser justos con Microsoft, esta puede haber sido una de las razones por las que esa API nunca creció. La parte principal de la respuesta presentará el código para TPM 1 por dos razones:
En segundo lugar, hagamos la pregunta más específica. Lo estoy reinterpretando de la siguiente manera:
El comando Seal es el más adecuado para esto, ya que realiza la misma función que el comando Bind cuando el tamaño de selección de PCR se establece en cero, pero la selección de PCR se puede cambiar fácilmente para incluir cualquier PCR que desee. Hace que uno se pregunte por qué el comando Bind se incluyó en la especificación y, como se señaló, se eliminó en la especificación TPM 2 y los dos se combinaron en un comando Create.
Aquí está el código C # para usar el comando TPM 1.2 Seal para cifrar datos solo con funciones de TBS (nota: este código no está probado y no es probable que funcione sin depurar) :
Análisis de código:
Estas son algunas de las pocas funciones disponibles en Tbs.h y las únicas que usaremos aquí. Básicamente, le permiten abrir un identificador al dispositivo y comunicarse con él enviando y recibiendo bytes sin procesar.
TPM es big endian, Windows es little endian. Por lo tanto, el orden de los bytes deberá invertirse para cualquier dato que enviemos. Solo tenemos que preocuparnos por revertir entradas sin firmar de 32 bits y 16 bits aquí.
Aquí usamos Tbsi_Context_Create () para abrir un identificador para hablar con el TPM. El
TBS_CONTEXT_PARAMS
parámetro es solo una estructura C con un campo int de 32 bits sin firmar que debe establecerse en 1 para comunicarse con una instancia de TPM 1.2, y eso es lo que lo configuramos.Esto se especifica como el tamaño de búfer mínimo en la especificación de cliente de TPM PC . Será más que suficiente para nuestras necesidades aquí.
TPM 1.2 Spec Part 3 dice lo siguiente:
Necesitamos XOR-encriptar este parámetro "secreto" usando un nonce generado durante una sesión OSAP. Uno de los identificadores de entrada del comando Seal es también un identificador OSAP:
Entonces, primero debemos establecer esta sesión OSAP. OSAP se describe en TPM 1.2 Spec Part 1 . OSAP, o Protocolo de autorización específico de objeto, se inventó para manejar el caso de uso en el que desea usar un objeto TPM que requiere autorización varias veces, pero no desea proporcionar autorización cada vez: en su lugar, se usa una sesión OSAP, que depende sobre el concepto de "secreto compartido", que es un HMACque mezcla los datos de autorización del objeto con nonces generados en cada lado para evitar ataques de respuesta. Por lo tanto, el "secreto compartido" solo es conocido por las dos partes en esta sesión: la parte que inició la sesión (usuario) y la parte que la aceptó (TPM); además, ambas partes deben tener los mismos datos de autorización de objeto para que el "secreto compartido" sea el mismo; Además, el "secreto compartido" utilizado en una sesión no será válido en otra. Este diagrama de la especificación describe el proceso:
No usaremos múltiples sesiones en este caso particular (de hecho, ¡ese parámetro se ignora con el comando Seal!) Y la clave que usaremos no requiere autorización, pero desafortunadamente todavía estamos obligados por la especificación a establecer un OSAP. sesión.
Los operandos del comando TPM_OSAP son:
Cada comando de TPM 1.2 se presenta así:
La etiqueta es un valor de dos bytes que indica si lo que sigue es entrada o salida, y si hay valores de datos de autenticación después de los parámetros de comando. Para TPM_OSAP, la etiqueta debe ser TPM_TAG_RQU_COMMAND (0x00C1) según las especificaciones, lo que significa "un comando sin autorización".
El tamaño es un valor de cuatro bytes que especifica el tamaño del comando en bytes, incluida la etiqueta y el tamaño en sí. Estableceremos este valor más tarde, una vez que lo hayamos calculado.
El código de comando es un valor de cuatro bytes que los servidores como ID de comando: le dice al TPM cómo interpretar el resto del comando. Nuestro código de comando aquí es TPM_OSAP (0x0000000B).
Las siguientes dos cosas a establecer son el tipo de entidad y el valor de la entidad. Dado que queremos usar una clave que ya existe en el TPM, usaremos el tipo de entidad "SRK" (0x0004), y dado que estamos trabajando bajo el supuesto de que el TPM ya ha sido propiedad, es seguro asumir que tiene un SRK cargado bajo el identificador permanente 0x40000000 según la especificación, por lo que usaremos este valor de identificador permanente para nuestro valor de entidad. (SRK significa "Storage Root Key" y es la clave raíz de la que derivan la mayoría de las otras claves propiedad de TPM)
Finalmente calculamos el tamaño del comando, lo configuramos y enviamos el comando.
Los datos que se supone que debemos recuperar del TPM en TPM_OSAP son:
Entonces volvemos:
Extraemos esos valores y los almacenamos en variables.
Luego calculamos el "secreto compartido". Según la especificación, los valores que entran en el cálculo son los dos nonces OSAP (uno generado por el usuario y otro generado por el TPM) y el valor de autorización para la clave que queremos usar - el SRK. Por convención, el valor de autenticación SRK es la "autenticación conocida": un búfer de 20 bytes puesto a cero. Técnicamente, se podría cambiar este valor por otro al tomar posesión del TPM, pero esto no se hace en la práctica, por lo que podemos asumir con seguridad que el valor de "autenticación conocida" es bueno.
A continuación, echemos un vistazo a lo que incluye el comando TPM_Seal:
La mayoría de estos parámetros son triviales de construir, excepto dos de ellos:
encAuth
ypubAuth
. Veámoslos uno por uno.encAuth
es "AuthData cifrado para los datos sellados". Nuestro AuthData aquí es el "auth conocido" de antes, pero sí, todavía tenemos que cifrarlo. Debido a que estamos usando una sesión OSAP, está encriptada siguiendo ADIP, o Protocolo de inserción de datos de autorización. De la especificación: "El ADIP permite la creación de nuevas entidades y la inserción segura de la nueva entidad AuthData. La transmisión de la nueva AuthData utiliza encriptación con la clave basada en el secreto compartido de una sesión OSAP". Además: "Para el algoritmo de cifrado XOR obligatorio, el creador crea una clave de cifrado utilizando un hash SHA-1 del secreto compartido OSAP y un nonce de sesión. El creador XOR cifra el nuevo AuthData utilizando la clave de cifrado como un pad de un solo uso y envía estos datos cifrados junto con la solicitud de creación al TPM ".El siguiente diagrama explica cómo funciona ADIP:
pubAuth
es "El resumen de la sesión de autorización para entradas y keyHandle". La parte 1 de la especificación, en "Declaraciones de parámetros para ejemplos de OIAP y OSAP", explica cómo interpretar la tabla de parámetros TPM_Seal anterior: "La columna HMAC # detalla los parámetros utilizados en el cálculo de HMAC. Los parámetros 1S, 2S, etc. están concatenados y hash a inParamDigest o outParamDigest, llamado implícitamente 1H1 y posiblemente 1H2 si hay dos sesiones de autorización. Para la primera sesión, 1H1, 2H1, 3H1 y 4H1 se concatenan y HMAC'ed. Para la segunda sesión, 1H2, 2H2, 3H2, y 4H2 se concatenan y HMAC '. " Así que tendremos que hacer un hash del texto plano, su tamaño, el tamaño de la información de PCR,encAuth
desde arriba y el ordinal TPM_Seal, y luego HMAC que con los dos nonces y el booleano "continuar sesión" usando el OSAP "Poniéndolo todo junto en un diagrama:
Observe cómo establecemos el "tamaño de información de PCR" en cero en este código, ya que solo queremos cifrar los datos sin bloquearlos en un estado del sistema. Sin embargo, es trivial proporcionar una estructura de "información de PCR" si es necesario.
Finalmente construimos el comando y lo enviamos.
Usamos la función Tbsip_Context_Close () para cerrar nuestro identificador de comunicación.
Devolvemos la respuesta como está aquí. Lo ideal sería invertir los bytes nuevamente y validarlos volviendo a calcular el
resAuth
valor para evitar ataques man-in-the-middle.Esto se debe a que Tspi_Data_Bind es un comando de TSS, no un comando de TPM. La razón es porque no requiere secretos (solo se usa la clave pública) por lo que se puede hacer sin involucrar al TPM. Sin embargo, esto causó confusión e incluso los comandos que no requieren secretos ahora se incluyen en la especificación TPM 2.
Depende de la versión de TPM. Con el comando TPM_CreateWrapKey para TPM 1.2. Con el comando TPM2_Create para TPM 2.
Créelo en el TPM, envuélvalo o utilice cualquier otro de los métodos disponibles.
El texto del libro es confuso. No especifica la clave HMAC , especifica que desea una clave HMAC .
No, no tiene sentido. La clave es secreta.
Hay comandos para crear claves o importarlas para ambas versiones de TPM. Para TPM 1, solo había una clave raíz, la SRK, a partir de la cual se podía establecer una jerarquía de claves creando claves envueltas. Con TPM 2 puede tener varias claves primarias o raíz.
Véase más arriba.
Probablemente depende del tipo de unidad. En el caso de las unidades que no son SED, la clave de cifrado de la unidad probablemente esté envuelta con una clave TPM. En el caso de las unidades SED, la contraseña de Admin1 (o tal) está sellada con el TPM.
La EK no es una clave de firma, es una clave de cifrado. Sin embargo, no es una clave de cifrado de propósito general: solo se puede usar en ciertos contextos .
Véase más arriba.
fuente
Cuando dice
NO significa proporcionar la clave HMAC; significa "señalar la clave HMAC que desea usar" .
Los TPM pueden utilizar una cantidad prácticamente ilimitada de claves HMAC, como se indica en el libro. Tienes que decirle al TPM cuál usar.
fuente