Come posso crittografare i byte utilizzando il modulo TPM di una macchina?
CryptProtectData
Windows fornisce un'API (relativamente) semplice per crittografare un BLOB utilizzando l' CryptProtectData
API, che possiamo racchiudere in una funzione facile da usare:
public Byte[] ProtectBytes(Byte[] plaintext)
{
//...
}
I dettagli di ProtectBytes
sono meno importanti dell'idea che puoi usarlo abbastanza facilmente:
- ecco i byte che voglio crittografare da una chiave segreta contenuta nel file
System
- restituiscimi il BLOB crittografato
Il BLOB restituito è una documentazione non documentata struttura di che contiene tutto il necessario per decrittografare e restituire i dati originali (algoritmo hash, algoritmo di cifratura, salt, firma HMAC, ecc.).
Per completezza, ecco l'implementazione dello pseudocodice di esempio ProtectBytes
che utilizza Crypt API
per proteggere i byte:
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.
}
Come fare lo stesso con il TPM?
Il codice sopra è utile per crittografare i dati solo per la macchina locale. I dati vengono crittografati utilizzando l' System
account come generatore di chiavi (i dettagli, sebbene interessanti, non sono importanti ). Il risultato finale è che posso crittografare i dati (ad esempio una chiave master di crittografia del disco rigido) che possono essere decrittografati solo dalla macchina locale.
Ora è il momento di fare un ulteriore passo avanti. Desidero crittografare alcuni dati (ad esempio una chiave master di crittografia del disco rigido) che possono essere decrittografati solo dal TPM locale. In altre parole, voglio sostituire Qualcomm Trusted Execution Environment ( TEE ) nello schema a blocchi seguente per Android, con il TPM in Windows:
Nota : mi rendo conto che il TPM non esegue la firma dei dati (o se lo fa, non garantisce che la firma degli stessi dati fornirà ogni volta lo stesso output binario). Ecco perché sarei disposto a sostituire "firma RSA" con "crittografia di un BLOB a 256 bit con una chiave associata a hardware" .
Allora dov'è il codice?
Il problema è che la programmazione TPM è completamente non documentata su MSDN . Non sono disponibili API per eseguire operazioni. Invece devi trovarti una copia dello Stack software del Trusted Computing Group (noto anche come TSS) , capire quali comandi inviare al TPM, con i payload, in quale ordine e chiamare la funzione Tbsip_Submit_Command di Window per inviare direttamente i comandi:
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 non dispone di API di livello superiore per eseguire azioni.
È l'equivalente morale di provare a creare un file di testo inviando comandi di I / O SATA al disco rigido .
Perché non usare solo pantaloni
Il Trusted Computing Group (TCG) ha definito la propria API: TCB Software Stack (TSS) . Un'implementazione di questa API è stata creata da alcune persone e si chiama TrouSerS . Un ragazzo ha poi trasferito quel progetto su Windows .
Il problema con quel codice è che non è portabile nel mondo Windows. Ad esempio, non puoi usarlo da Delphi, non puoi usarlo da C #. Richiede:
- OpenSSL
- pThread
Voglio solo il codice crittografi qualcosa con il mio TPM.
Quanto sopra CryptProtectData
non richiede altro che ciò che è nel corpo della funzione.
Qual è il codice equivalente per crittografare i dati utilizzando il TPM? Come altri hanno notato, probabilmente è necessario consultare i tre manuali TPM e creare i BLOB da soli . Probabilmente coinvolge il TPM_seal
comando. Anche se penso di non voler sigillare i dati, penso di volerlo legare :
Binding : crittografa i dati utilizzando la chiave di binding TPM, una chiave RSA univoca derivata da una chiave di archiviazione. Sigillatura : crittografa i dati in modo simile all'associazione, ma in aggiunta specifica uno stato in cui deve essere TPM affinché i dati vengano decrittografati (non protetti)
Provo a leggere i tre volumi richiesti per trovare le 20 righe di codice di cui ho bisogno:
Ma non ho alcun idea di cosa sto leggendo. Se ci fosse qualche tipo di tutorial o esempi, potrei avere una possibilità. Ma sono completamente perso.
Quindi chiediamo Stackoverflow
Allo stesso modo ho potuto fornire:
Byte[] ProtectBytes_Crypt(Byte[] plaintext)
{
//...
CryptProtectData(...);
//...
}
qualcuno può fornire l'equivalente corrispondente:
Byte[] ProtectBytes_TPM(Byte[] plaintext)
{
//...
Tbsip_Submit_Command(...);
Tbsip_Submit_Command(...);
Tbsip_Submit_Command(...);
//...snip...
Tbsip_Submit_Command(...);
//...
}
che fa la stessa cosa, tranne che invece di una chiave bloccata in System
LSA, è bloccata nel TPM?
Inizio della ricerca
Non so esattamente cosa significhi legare . Ma guardando TPM Main - Part 3 Commands - Specification Version 1.2, c'è una menzione di bind :
10.3 TPM_UnBind
TPM_UnBind prende il BLOB di dati che è il risultato di un comando Tspi_Data_Bind e lo decrittografa per l'esportazione all'utente. Il chiamante deve autorizzare l'uso della chiave che decrittograferà il BLOB in arrivo. TPM_UnBind opera blocco per blocco e non ha alcuna nozione di alcuna relazione tra un blocco e l'altro.
Ciò che è fonte di confusione è che non c'è alcun Tspi_Data_Bind
comando.
Sforzo di ricerca
È orribile come nessuno si sia mai preso la briga di documentare il TPM o il suo funzionamento. È come se passassero tutto il loro tempo a inventare questa cosa fantastica con cui giocare, ma non volessero affrontare il passo doloroso di renderla utilizzabile per qualcosa.
A partire dal libro (ora) gratuito A Practical Guide to TPM 2.0: Using the Trusted Platform Module in the New Age of Security :
Capitolo 3 - Esercitazione rapida su TPM 2.0
Il TPM ha accesso a una chiave privata autogenerata, quindi può crittografare le chiavi con una chiave pubblica e quindi archiviare il BLOB risultante sul disco rigido. In questo modo, il TPM può mantenere un numero virtualmente illimitato di chiavi disponibili per l'uso ma non sprecare preziosa memoria interna. Le chiavi memorizzate sul disco rigido possono essere cancellate, ma è anche possibile eseguirne il backup, il che è sembrato ai progettisti un compromesso accettabile.
Come posso crittografare una chiave con la chiave pubblica del TPM?
Capitolo 4 - Applicazioni esistenti che utilizzano TPM
Applicazioni che dovrebbero utilizzare il TPM ma non lo fanno
Negli ultimi anni, il numero di applicazioni basate sul web è aumentato. Tra questi ci sono backup e archiviazione basati sul Web. Un gran numero di aziende ora offre tali servizi, ma per quanto ne sappiamo, nessuno dei client per questi servizi consente all'utente di bloccare la chiave per il servizio di backup su un TPM. Se ciò fosse fatto, sarebbe sicuramente bello se fosse stato eseguito il backup della chiave TPM stessa duplicandola su più macchine. Questa sembra essere un'opportunità per gli sviluppatori.
In che modo uno sviluppatore blocca una chiave per il TPM?
Capitolo 9 - Heirarchies
CASO D'USO: MEMORIZZAZIONE DELLE PASSWORD DI ACCESSO
Un tipico file di password memorizza gli hash salati delle password. La verifica consiste nel saltare e hashing una password fornita e confrontarla con il valore memorizzato. Poiché il calcolo non include un segreto, è soggetto ad un attacco offline al file della password.
Questo caso d'uso usa una chiave HMAC generata da TPM. Il file della password memorizza un HMAC della password salata. La verifica consiste nel salare e HMAC la password fornita e confrontarla con il valore memorizzato. Poiché un utente malintenzionato offline non dispone della chiave HMAC, non può eseguire un attacco eseguendo il calcolo.
Questo potrebbe funzionare. Se il TPM ha una chiave HMAC segreta e solo il mio TPM conosce la chiave HMAC, allora potrei sostituire "Firma (ovvero crittografia TPM con la sua chiave privata)" con "HMAC". Ma poi nella riga successiva si inverte completamente:
TPM2_Create, specificando una chiave HMAC
Non è un segreto TPM se devo specificare la chiave HMAC. Il fatto che la chiave HMAC non sia segreta ha senso quando ti rendi conto che questo è il capitolo sulle utilità crittografiche fornite dal TPM. Invece di dover scrivere personalmente SHA2, AES, HMAC o RSA, puoi riutilizzare ciò che il TPM ha già in giro.
Capitolo 10 - Chiavi
In quanto dispositivo di sicurezza, la capacità di un'applicazione di utilizzare le chiavi mantenendole al sicuro in un dispositivo hardware è il più grande punto di forza del TPM. Il TPM può generare e importare chiavi generate esternamente. Supporta chiavi sia asimmetriche che simmetriche.
Eccellente! Come si fa!?
Generatore di chiavi
Probabilmente, il più grande punto di forza del TPM è la sua capacità di generare una chiave crittografica e proteggere il suo segreto all'interno di un confine hardware. Il generatore di chiavi si basa sul generatore di numeri casuali del TPM e non si basa su fonti esterne di casualità. Elimina così i punti deboli basati su un software debole con una fonte di entropia insufficiente.
Il TPM ha la capacità di generare chiavi crittografiche e proteggere i suoi segreti entro un limite hardware? È così, come?
Capitolo 12 - Registri di configurazione della piattaforma
PCR per l'autorizzazione
CASO D'USO: SIGILLARE UNA CHIAVE DI CRITTOGRAFIA SU DISCO RIGIDO ALLO STATO DELLA PIATTAFORMA
Le applicazioni di crittografia dell'intero disco sono molto più sicure se un TPM protegge la chiave di crittografia rispetto a se è archiviata sullo stesso disco, protetta solo da una password. Innanzitutto, l'hardware TPM dispone di una protezione anti-martellamento (vedere il Capitolo 8 per una descrizione dettagliata della protezione dagli attacchi del dizionario TPM), rendendo impraticabile un attacco di forza bruta alla password. Una chiave protetta solo dal software è molto più vulnerabile a una password debole. In secondo luogo, una chiave software memorizzata su disco è molto più facile da rubare. Prendi il disco (o un backup del disco) e ottieni la chiave. Quando un TPM detiene la chiave, l'intera piattaforma, o almeno il disco e la scheda madre, devono essere rubati.
La sigillatura consente di proteggere la chiave non solo da una password ma da una policy. Un criterio tipico blocca la chiave sui valori PCR (lo stato del software) correnti al momento della sigillatura. Ciò presuppone che lo stato al primo avvio non sia compromesso. Qualsiasi malware preinstallato presente al primo avvio verrebbe misurato nei PCR e quindi la chiave verrebbe sigillata in uno stato software compromesso. Un'impresa meno affidabile potrebbe avere un'immagine disco standard e un sigillo per PCR che rappresenta quell'immagine. Questi valori PCR sarebbero precalcolati su una piattaforma presumibilmente più affidabile. Un'azienda ancora più sofisticata utilizzerebbe TPM2_PolicyAuthorize e fornirebbe diversi ticket che autorizzano una serie di valori PCR affidabili. Vedere il Capitolo 14 per una descrizione dettagliata dell'autorizzazione della politica e della sua applicazione per risolvere il problema della fragilità PCR.
Sebbene una password possa anche proteggere la chiave, c'è un guadagno in termini di sicurezza anche senza una password della chiave TPM. Un utente malintenzionato potrebbe avviare la piattaforma senza fornire una password TPMkey ma non potrebbe accedere senza il nome utente e la password del sistema operativo. La sicurezza del sistema operativo protegge i dati. L'aggressore potrebbe avviare un sistema operativo alternativo, ad esempio da un DVD live o da una chiavetta USB piuttosto che dal disco rigido, per aggirare la sicurezza di accesso del sistema operativo. Tuttavia, questa diversa configurazione di avvio e software cambierebbero i valori PCR. Poiché queste nuove PCR non corrisponderebbero ai valori sigillati, il TPM non rilascerà la chiave di decrittografia e il disco rigido non potrà essere decrittografato.
Eccellente! Questo è esattamente il caso d'uso che desidero. È anche il caso d'uso per cui Microsoft utilizza il TPM. Come lo faccio!?
Così ho letto l'intero libro e non ha fornito nulla di utile. Il che è abbastanza impressionante perché sono 375 pagine. Ti chiedi cosa contenesse il libro e, ripensandoci, non ne ho idea.
Rinunciamo quindi alla guida definitiva alla programmazione del TPM, e ci rivolgiamo invece a qualche documentazione di Microsoft:
Dal toolkit del provider di crittografia della piattaforma Microsoft TPM . Menziona esattamente quello che voglio fare:
La chiave di approvazione o EK
L'EK è progettato per fornire un identificatore crittografico affidabile per la piattaforma. Un'azienda potrebbe mantenere un database delle chiavi di verifica dell'autenticità appartenenti ai TPM di tutti i PC della propria azienda, oppure un controller dell'infrastruttura del data center potrebbe avere un database dei TPM in tutti i blade. Su Windows è possibile utilizzare il provider NCrypt descritto nella sezione "Platform Crypto Provider in Windows 8" per leggere la parte pubblica dell'EK.
Da qualche parte all'interno del TPM c'è una chiave privata RSA. Quella chiave è chiusa lì dentro, per non essere mai vista dal mondo esterno. Voglio che il TPM firmi qualcosa con la sua chiave privata (cioè lo crittografi con la sua chiave privata).
Quindi voglio l' operazione più elementare che può eventualmente esistere:
Crittografa qualcosa con la tua chiave privata. Non sto nemmeno (ancora) chiedendo le cose più complicate:
- "sigillarlo" in base allo stato della PCR
- creazione di una chiave e memorizzazione in memoria volatile o non volatile
- creando una chiave simmetrica e provando a caricarla nel TPM
Chiedo l'operazione più semplice che un TPM può eseguire. Perché è impossibile ottenere informazioni su come farlo?
Posso ottenere dati casuali
Suppongo di essere stato disinvolto quando ho detto che la firma RSA era la cosa più semplice che il TPM può fare. La cosa più semplice che si può chiedere al TPM è di darmi byte casuali. Che ho capito come fare:
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 fantastica
Mi rendo conto che il volume di persone che utilizzano il TPM è molto basso. Ecco perché nessuno su Stackoverflow ha una risposta. Quindi non posso davvero diventare troppo avido nell'ottenere una soluzione al mio problema comune. Ma la cosa che vorrei veramente fare è "sigillare" alcuni dati:
- presentare al TPM alcuni dati (es. 32 byte di materiale chiave)
- fare in modo che il TPM crittografi i dati, restituendo una struttura blob opaca
- successivamente chiedere al TPM di decrittografare il BLOB
- la decrittografia funzionerà solo se i registri PCR del TPM sono gli stessi di durante la crittografia.
In altre parole:
Byte[] ProtectBytes_TPM(Byte[] plaintext, Boolean sealToPcr)
{
//...
}
Byte[] UnprotectBytes_TPM(Byte[] protectedBlob)
{
//...
}
Cryptography Next Gen (Cng, aka BCrypt) supporta TPM
L'API di crittografia originale in Windows era nota come API di crittografia.
A partire da Windows Vista, la Crypto API è stata sostituita con Cryptography API: Next Generation (internamente nota come BestCrypt , abbreviato in BCrypt , da non confondere con l'algoritmo di hashing delle password ).
Windows viene fornito con due provider BCrypt :
- Microsoft Primitive Provider (
MS_PRIMITIVE_PROVIDER
) predefinito : implementazione software predefinita di tutte le primitive (hash, crittografia simmetrica, firme digitali, ecc.) - Microsoft Platform Crypto Provider (
MS_PLATFORM_CRYPTO_PROVIDER
): provider che fornisce l'accesso al TPM
Il provider Platform Crypto non è documentato su MSDN, ma dispone della documentazione di un sito di ricerca Microsoft del 2012:
Toolkit del provider di crittografia della piattaforma TPM
Il toolkit e il provider di crittografia della piattaforma TPM contengono codice di esempio, utilità e documentazione per l'utilizzo della funzionalità relativa a TPM in Windows 8. I sottosistemi descritti includono il provider di crittografia della piattaforma Crypto-Next-Gen (CNG) supportato da TPM e i provider di servizi di attestazione può utilizzare le nuove funzionalità di Windows. Sono supportati entrambi i sistemi basati su TPM1.2 e TPM2.0.
Sembra che l'intento di Microsoft sia quello di far emergere la funzionalità di crittografia TPM con il provider di crittografia della piattaforma Microsoft di Cryptography NG dell'API .
Crittografia a chiave pubblica utilizzando Microsoft BCrypt
Dato che:
- voglio eseguire la crittografia asimmetrica RSA (utilizzando il TPM)
- Microsoft BestCrypt supporta la crittografia asimmetrica RSA
- Microsoft BestCrypt ha un provider TPM
una via d'uscita potrebbe essere quella di capire come fare la firma digitale utilizzando l' API Microsoft Cryptography Next Gen .
Il prossimo passo sarà trovare il codice per eseguire la crittografia in BCrypt, con una chiave pubblica RSA, utilizzando il provider standard ( MS_PRIMITIVE_PROVIDER
). Per esempio:
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 quel codice funzionante, potrei essere in grado di passare all'utilizzo del provider TPM ( MS_PLATFORM_CRYPTO_PROVIDER
).
22/02/2016: E con Apple costretta ad aiutare a decrittografare i dati degli utenti, c'è un rinnovato interesse su come fare in modo che il TPM esegua l'attività più semplice per cui è stato inventato: crittografare qualcosa.
È più o meno equivalente a chiunque possieda un'auto, ma nessuno sa come avviarne una. Può fare cose davvero utili e interessanti, se solo riuscissimo a superare il passaggio 1 .