Add TPM+PIN decryption support (-t/--tpm-datum option)#355
Add TPM+PIN decryption support (-t/--tpm-datum option)#355ludovictyack wants to merge 1 commit intoAorimn:masterfrom
Conversation
Allow decrypting BitLocker volumes protected with TPM+PIN by providing a TPM datum file (the AES-CCM blob manually extracted from the TPM) along with the user PIN. Usage: dislocker -t vmk_datum.bin -u PIN -V /dev/sdX The implementation iterates all VMK datums in the volume metadata, derives an intermediate key from the PIN and the salt found in each VMK's stretch key datum, decrypts the TPM blob to obtain an intermediate key, then uses it to decrypt the actual VMK. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
billatarm
left a comment
There was a problem hiding this comment.
I'm not a maintainer, but I also have patches staged for dislocker, as a TPM maintainer for Linux, I was interested in your patch. My 2 cents in the review, for what it's worth, take it or leave it. Nice patch.
|
|
||
| /* If the user password/PIN wasn't provided, ask for it */ | ||
| if(!cfg->user_password) | ||
| if(!prompt_up(&cfg->user_password)) |
There was a problem hiding this comment.
Nit, I think this is more clear to read and avoids the unbracketed if followed by a bracketed if.
if(!cfg->user_password) && !prompt_up(@cfg->user_password)() {
dis_printf(L_ERROR, "Cannot get valid user PIN. Abort.\n");
return FALSE;
}| } | ||
|
|
||
| file_size = dis_lseek(file_fd, 0, SEEK_END); | ||
| if(file_size < (off_t)sizeof(datum_aes_ccm_t) || file_size > 65536) |
There was a problem hiding this comment.
Why 65536? Is this the max an unsigned 16 bit can hold, which is 0xFFFF or 65535? Should we use the UINT16_MAX define or create a new one here to make the size restriction more clear.
| L_ERROR, | ||
| "Invalid TPM datum file size: %d (expected at least %lu bytes)\n", | ||
| (int)file_size, | ||
| (unsigned long)sizeof(datum_aes_ccm_t) |
There was a problem hiding this comment.
%jd for off_t and %zu for size_t. I am not sure if there some weird thing where this has to be c89 or some anchient compiler support needed, so I won't mention these again. But there are lots of spots where %zu or other format specifiers could be used vs casting. Then you wont have any truncation or other issues.
| !stretch_datum) | ||
| { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
bracket consistency, looks like single line conditions don't get brackets.
| continue; | ||
| } | ||
|
|
||
| memcpy(salt, ((datum_stretch_key_t*) stretch_datum)->salt, 16); |
There was a problem hiding this comment.
use sizeof(stretch_datum->salt) instead of repeating the constant 16.
| )) | ||
| { | ||
| /* Look for a STRETCH_KEY nested datum (contains the salt) */ | ||
| void* stretch_datum = NULL; |
There was a problem hiding this comment.
I would change this to type datum_stretch_key_t and then pass that to get_nested_datumvaluetype, then you don't need to cast it again later. You can pass any pointer as a void pointer too.
| memcpy(salt, ((datum_stretch_key_t*) stretch_datum)->salt, 16); | ||
|
|
||
| dis_printf(L_DEBUG, "Found VMK with stretch key, salt:\n"); | ||
| hexdump(L_DEBUG, salt, 16); |
| } | ||
|
|
||
| dis_printf(L_DEBUG, "Derived user hash:\n"); | ||
| hexdump(L_DEBUG, user_hash, 32); |
| if(!get_vmk( | ||
| (datum_aes_ccm_t*) tpm_aesccm, | ||
| user_hash, | ||
| 32, |
| if(opt_value == NULL) | ||
| cfg->tpm_datum_file = NULL; | ||
| else | ||
| cfg->tpm_datum_file = strdup((const char*) opt_value); |
There was a problem hiding this comment.
I know you're matching the code around you, and the other option handling code ignores this bug, but if this fails here will this get detected in some meaningful way? Maybe add a dis_strdup that dies like dis_malloc.
Allow decrypting BitLocker volumes protected with TPM+PIN by providing a TPM datum file (the AES-CCM blob manually extracted from the TPM) along with the user PIN. Usage: dislocker -t vmk_datum.bin -u PIN -V /dev/sdX
The implementation iterates all VMK datums in the volume metadata, derives an intermediate key from the PIN and the salt found in each VMK's stretch key datum, decrypts the TPM blob to obtain an intermediate key, then uses it to decrypt the actual VMK.