Como posso criptografar bytes usando o módulo TPM de uma máquina?
CryptProtectData
O Windows fornece uma API (relativamente) simples para criptografar um blob usando a CryptProtectData
API, que pode envolver uma função fácil de usar:
public Byte[] ProtectBytes(Byte[] plaintext)
{
//...
}
Os detalhes de ProtectBytes
são menos importantes do que a ideia de que você pode usá-lo com bastante facilidade:
- aqui estão os bytes que quero criptografados por uma chave secreta mantida no
System
- me devolva o blob criptografado
O blob retornado é uma documentação não documentada estrutura de que contém tudo o que é necessário para descriptografar e retornar os dados originais (algoritmo de hash, algoritmo de cifra, salt, assinatura HMAC, etc).
Para completar, aqui está o exemplo de implementação de pseudocódigo ProtectBytes
que usa o Crypt API
para proteger os 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.
}
Como fazer o mesmo com o TPM?
O código acima é útil para criptografar dados apenas para a máquina local. Os dados são criptografados usando a System
conta como gerador de chave (os detalhes, embora interessantes, não são importantes ). O resultado final é que posso criptografar dados (por exemplo, uma chave mestra de criptografia de disco rígido) que só podem ser descriptografados pela máquina local.
Agora é hora de dar um passo adiante. Desejo criptografar alguns dados (por exemplo, uma chave mestra de criptografia do disco rígido) que só podem ser descriptografados pelo TPM local. Em outras palavras, desejo substituir o Qualcomm Trusted Execution Environment ( TEE ) no diagrama de blocos abaixo para Android, pelo TPM no Windows:
Nota : Eu percebo que o TPM não faz assinatura de dados (ou se faz, não garante que assinar os mesmos dados dará sempre a mesma saída binária). É por isso que eu estaria disposto a substituir "assinatura RSA" por "criptografar um blob de 256 bits com uma chave associada ao hardware" .
Onde está o código?
O problema é que a programação TPM não está documentada no MSDN . Não há API disponível para realizar qualquer operação. Em vez disso, você precisa encontrar uma cópia da pilha de software do Trusted Computing Group (também conhecida como TSS) , descobrir quais comandos enviar para o TPM, com cargas úteis, em que ordem, e chamar a função Tbsip_Submit_Command do Windows para enviar comandos diretamente:
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
);
O Windows não tem API de nível superior para realizar ações.
É o equivalente moral de tentar criar um arquivo de texto emitindo comandos SATA I / O para seu disco rígido .
Por que não usar apenas calças
O Trusted Computing Group (TCG) definiu sua própria API: TCB Software Stack (TSS) . Uma implementação dessa API foi criada por algumas pessoas e é chamada de TrouSerS . Um cara então portou esse projeto para o Windows .
O problema com esse código é que não é portátil para o mundo do Windows. Por exemplo, você não pode usá-lo do Delphi, você não pode usá-lo do C #. Isso requer:
- OpenSSL
- pThread
Só quero que o código criptografe algo com meu TPM.
O acima CryptProtectData
requer nada além do que está no corpo da função.
Qual é o código equivalente para criptografar dados usando o TPM? Como outros notaram, você provavelmente terá que consultar os três manuais do TPM e construir você mesmo os blobs . Provavelmente envolve o TPM_seal
comando. Embora eu ache que não quero lacrar dados, acho que quero vinculá- los:
Vinculação - criptografa os dados usando a chave de vinculação TPM, uma chave RSA exclusiva descendente de uma chave de armazenamento. Selagem - criptografa os dados de maneira semelhante à vinculação, mas, além disso, especifica um estado em que o TPM deve estar para que os dados sejam descriptografados (sem lacre)
Tento ler os três volumes necessários para encontrar as 20 linhas de código de que preciso:
Mas eu não tenho idéia do que estou lendo. Se houvesse algum tipo de tutorial ou exemplo, eu poderia tentar. Mas estou completamente perdido.
Então pedimos Stackoverflow
Da mesma forma, fui capaz de fornecer:
Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
//...
CryptProtectData(...);
//...
}
alguém pode fornecer o equivalente correspondente:
Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
//...
Tbsip_Submit_Command(...);
Tbsip_Submit_Command(...);
Tbsip_Submit_Command(...);
//...snip...
Tbsip_Submit_Command(...);
//...
}
que faz a mesma coisa, exceto ao invés de uma chave trancada em System
LSA, é trancada no TPM?
Início da Pesquisa
Não sei exatamente o que significa ligar . Mas olhando para TPM Main - Parte 3 Comandos - Especificação Versão 1.2, há uma menção de bind :
10.3 TPM_UnBind
TPM_UnBind pega o blob de dados que é o resultado de um comando Tspi_Data_Bind e o descriptografa para exportação para o usuário. O chamador deve autorizar o uso da chave que descriptografará o blob de entrada. TPM_UnBind opera bloco a bloco e não tem noção de qualquer relação entre um bloco e outro.
O que está confundindo está lá é nenhum Tspi_Data_Bind
comando.
Esforço de Pesquisa
É horrível como ninguém jamais se preocupou em documentar o TPM ou sua operação. É como se eles passassem o tempo todo inventando uma coisa legal para brincar, mas não quisessem lidar com a dolorosa etapa de torná-la utilizável para alguma coisa.
Começando com o livro (agora) 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
O TPM tem acesso a uma chave privada gerada automaticamente, portanto, ele pode criptografar chaves com uma chave pública e, em seguida, armazenar o blob resultante no disco rígido. Dessa forma, o TPM pode manter um número virtualmente ilimitado de chaves disponíveis para uso, mas não desperdiça armazenamento interno valioso. As chaves armazenadas no disco rígido podem ser apagadas, mas também podem ser feitas cópias de segurança, o que pareceu aos projetistas uma troca aceitável.
Como posso criptografar uma chave com a chave pública do TPM?
Capítulo 4 - Aplicativos existentes que usam TPMs
Aplicativos que devem usar o TPM, mas não
Nos últimos anos, o número de aplicativos baseados na web aumentou. Entre eles estão backup e armazenamento baseados na web. Atualmente, um grande número de empresas oferece esses serviços, mas, pelo que sabemos, nenhum dos clientes desses serviços permite que o usuário bloqueie a chave do serviço de backup para um TPM. Se isso fosse feito, certamente seria bom se a própria chave TPM fosse copiada, duplicando-a em várias máquinas. Esta parece ser uma oportunidade para desenvolvedores.
Como um desenvolvedor bloqueia uma chave para o TPM?
Capítulo 9 - Heirarquias
CASO DE USO: ARMAZENAMENTO DE SENHAS DE LOGIN
Um arquivo de senha típico armazena hashes salgados de senhas. A verificação consiste em fazer o sal e hash de uma senha fornecida e compará-la com o valor armazenado. Como o cálculo não inclui um segredo, ele está sujeito a um ataque offline ao arquivo de senha.
Este caso de uso usa uma chave HMAC gerada por TPM. O arquivo de senha armazena um HMAC da senha com salt. A verificação consiste em salting e HMAC a senha fornecida e compará-la com o valor armazenado. Como um invasor offline não tem a chave HMAC, o invasor não pode montar um ataque executando o cálculo.
Isso pode funcionar. Se o TPM tiver uma chave HMAC secreta e apenas meu TPM souber a chave HMAC, eu poderia substituir "Assinar (também conhecido como criptografar TPM com sua chave privada)" por "HMAC". Mas então na linha seguinte ele se inverte completamente:
TPM2_Create, especificando uma chave HMAC
Não é um segredo do TPM se eu tiver que especificar a chave HMAC. O fato de a chave HMAC não ser secreta faz sentido quando você percebe que este é o capítulo sobre utilitários criptográficos que o TPM fornece. Em vez de escrever SHA2, AES, HMAC ou RSA por conta própria, você pode reutilizar o que o TPM já tem disponível.
Capítulo 10 - Chaves
Como um dispositivo de segurança, a capacidade de um aplicativo de usar chaves enquanto as mantém seguras em um dispositivo de hardware é a maior força do TPM. O TPM pode gerar e importar chaves geradas externamente. Ele oferece suporte a chaves assimétricas e simétricas.
Excelente! Como você faz isso!?
Gerador de Chaves
Indiscutivelmente, a maior força do TPM é sua capacidade de gerar uma chave criptográfica e proteger seu segredo dentro de um limite de hardware. O gerador de chaves é baseado no próprio gerador de números aleatórios do TPM e não depende de fontes externas de aleatoriedade. Assim, elimina fraquezas com base em softwares de software fracos com uma fonte insuficiente de entropia.
O TPM tem a capacidade de gerar chaves criptográficas e proteger seus segredos dentro de um limite de hardware? É assim como?
Capítulo 12 - Registros de configuração da plataforma
PCRs para autorização
CASO DE USO: VEDANDO UMA CHAVE DE ENCRIPTAÇÃO DE DISCO RÍGIDO PARA O ESTADO DA PLATAFORMA
Os aplicativos de criptografia de disco completo são muito mais seguros se um TPM proteger a chave de criptografia do que se ela estiver armazenada no mesmo disco, protegido apenas por uma senha. Primeiro, o hardware TPM tem proteção anti-hammering (consulte o Capítulo 8 para uma descrição detalhada da proteção contra ataques de dicionário do TPM), tornando um ataque de força bruta à senha impraticável. Uma chave protegida apenas por software é muito mais vulnerável a uma senha fraca. Em segundo lugar, uma chave de software armazenada em disco é muito mais fácil de roubar. Pegue o disco (ou um backup do disco) e você terá a chave. Quando um TPM detém a chave, toda a plataforma, ou pelo menos o disco e a placa-mãe, deve ser roubada.
O lacre permite que a chave seja protegida não apenas por uma senha, mas por uma política. Uma política típica bloqueia a chave para os valores PCR (o estado do software) atuais no momento da selagem. Isso pressupõe que o estado na primeira inicialização não está comprometido. Qualquer malware pré-instalado presente na primeira inicialização seria medido nos PCRs e, portanto, a chave seria selada para um estado de software comprometido. Uma empresa menos confiável pode ter uma imagem de disco padrão e selo para PCRs que representam essa imagem. Esses valores de PCR seriam pré-calculados em uma plataforma presumivelmente mais confiável. Uma empresa ainda mais sofisticada usaria TPM2_PolicyAuthorize e forneceria vários tíquetes autorizando um conjunto de valores PCR confiáveis. Consulte o Capítulo 14 para obter uma descrição detalhada da política de autorização e sua aplicação para resolver o problema de fragilidade PCR.
Embora uma senha também possa proteger a chave, há um ganho de segurança mesmo sem uma senha de chave TPM. Um invasor pode inicializar a plataforma sem fornecer uma senha TPMkey, mas não pode fazer login sem o nome de usuário e a senha do sistema operacional. O OSsecurity protege os dados. O invasor pode inicializar um sistema operacional alternativo, digamos a partir de um DVD ao vivo ou pen drive, em vez do disco rígido, para contornar a segurança de login do sistema operacional. No entanto, essa configuração de inicialização e software diferentes mudariam os valores PCR. Como esses novos PCRs não corresponderiam aos valores lacrados, o TPM não liberaria a chave de descriptografia e o disco rígido não poderia ser descriptografado.
Excelente! Este é exatamente o caso de uso que desejo. É também o caso de uso para o qual a Microsoft usa o TPM. Como eu faço isso!?
Portanto, li o livro inteiro e não trouxe nada de útil. O que é bastante impressionante porque tem 375 páginas. Você se pergunta o que o livro continha - e, olhando para trás, não tenho ideia.
Portanto, desistimos do guia definitivo para programar o TPM e, em vez disso, recorremos a alguma documentação da Microsoft:
Do Microsoft TPM Platform Crypto-Provider Toolkit . Ele menciona exatamente o que eu quero fazer:
A chave de endosso ou EK
O EK foi projetado para fornecer um identificador criptográfico confiável para a plataforma. Uma empresa pode manter um banco de dados das Chaves de Endosso pertencentes aos TPMs de todos os PCs em sua empresa, ou um controlador de malha do data center pode ter um banco de dados dos TPMs em todos os blades. No Windows, você pode usar o provedor NCrypt descrito na seção “Provedor de criptografia de plataforma no Windows 8” para ler a parte pública do EK.
Em algum lugar dentro do TPM está uma chave privada RSA. Essa chave está trancada lá - para nunca ser vista pelo mundo exterior. Quero que o TPM assine algo com sua chave privada (ou seja, criptografe-o com sua chave privada).
Então, eu quero a operação mais básica que pode existir:
Criptografe algo com sua chave privada. Não estou nem (ainda) pedindo as coisas mais complicadas:
- "selando" com base no estado de PCR
- criar uma chave e armazená-la em uma memória volátil ou não volátil
- criar uma chave simétrica e tentar carregá-la no TPM
Estou pedindo a operação mais básica que um TPM pode fazer. Por que é impossível obter informações sobre como fazer isso?
Posso obter dados aleatórios
Acho que estava sendo simplista quando disse que a assinatura do RSA era a coisa mais básica que o TPM pode fazer. A coisa mais básica que o TPM pode ser solicitado a fazer é me dar bytes aleatórios. Que descobri como fazer:
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
Percebo que o volume de pessoas que usam o TPM é muito baixo. É por isso que ninguém no Stackoverflow tem uma resposta. Portanto, não posso ficar muito ganancioso em encontrar uma solução para meu problema comum. Mas o que eu realmente quero fazer é "lacrar" alguns dados:
- apresentar ao TPM alguns dados (por exemplo, 32 bytes de material chave)
- fazer com que o TPM criptografe os dados, retornando alguma estrutura de blob opaca
- mais tarde, peça ao TPM para descriptografar o blob
- a descriptografia só funcionará se os registros PCR do TPM forem os mesmos que eram durante a criptografia.
Em outras palavras:
Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
{
//...
}
Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
//...
}
Cryptography Next Gen (Cng, aka BCrypt) suporta TPM
A API de criptografia original no Windows era conhecida como API de criptografia.
A partir do Windows Vista, a Crypto API foi substituída por Cryptography API: Next Generation (internamente conhecido como BestCrypt , abreviado como BCrypt , não deve ser confundido com o algoritmo de hash de senha ).
O Windows é fornecido com dois provedores BCrypt :
- Provedor Primitive Microsoft (
MS_PRIMITIVE_PROVIDER
) padrão : Implementação padrão software de todos os primitivos (hash, criptografia simétrica, assinaturas digitais, etc) - Provedor de criptografia da plataforma Microsoft (
MS_PLATFORM_CRYPTO_PROVIDER
): Provedor que fornece acesso TPM
O provedor Platform Crypto não está documentado no MSDN, mas possui a documentação de um site de pesquisa da Microsoft 2012:
TPM Platform Crypto-Provider Toolkit
O provedor de criptografia da plataforma TPM e o kit de ferramentas contém código de amostra, utilitários e documentação para usar a funcionalidade relacionada ao TPM no Windows 8. Os subsistemas descritos incluem o provedor de criptografia de plataforma Crypto-Next-Gen (CNG) apoiado por TPM e como provedores de serviço de atestado pode usar os novos recursos do Windows. Ambos os sistemas baseados em TPM1.2 e TPM2.0 são suportados.
Parece que a intenção da Microsoft é trazer à tona a funcionalidade de criptografia TPM com o Microsoft Platform Crypto Provider da Cryptography NG API.
Criptografia de chave pública usando Microsoft BCrypt
Dado que:
- quero realizar criptografia assimétrica RSA (usando o TPM)
- Microsoft BestCrypt suporta criptografia assimétrica RSA
- Microsoft BestCrypt tem um provedor de TPM
um caminho a seguir poderia ser a de descobrir como fazer a assinatura digital usando a API Microsoft Cryptography Next Gen .
Meu próximo passo será chegar ao código para fazer a criptografia no BCrypt, com uma chave pública RSA, usando o provedor padrão ( MS_PRIMITIVE_PROVIDER
). Por exemplo:
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
Com esse código funcionando, posso passar a usar o Provedor TPM ( MS_PLATFORM_CRYPTO_PROVIDER
).
22/02/2016: E com a Apple sendo obrigada a ajudar a descriptografar os dados do usuário, há um interesse renovado em como fazer o TPM executar a tarefa mais simples para a qual foi inventado - criptografar algo.
É mais ou menos equivalente a todo mundo que possui um carro, mas ninguém sabe como dar partida em um. Ele pode fazer coisas realmente úteis e interessantes, se ao menos pudéssemos passar da Etapa 1 .