mirror of
https://github.com/nikaiw/VMkatz
synced 2026-09-25 07:51:06 +00:00
fix(chrome): DPAPI HMAC key must be SHA1(masterkey), not raw masterkey
DPAPI's protocol derives the session key as HMAC-SHA512(SHA1(masterkey), salt). LSASS exposes both the raw 64-byte master key AND its SHA-1 specifically for this reason. The previous implementation passed the raw 64-byte key as the HMAC input, which only round-tripped because the synthetic test built the blob with the same wrong key. Validated against real Edge Local State blobs on a Windows 10 VM with cleartext masterkey sourced from LSASS — derived v10 AES-GCM key now matches the value Chrome encrypts cookies with. Test updated to use the correct algorithm so it actually exercises the spec.
This commit is contained in:
@@ -7,6 +7,7 @@ use aes::Aes256;
|
||||
use cbc::cipher::block_padding::NoPadding;
|
||||
use cbc::cipher::{BlockDecryptMut, KeyIvInit};
|
||||
use hmac::{Hmac, Mac};
|
||||
use sha1::{Digest, Sha1};
|
||||
use sha2::Sha512;
|
||||
|
||||
type Aes256CbcDec = cbc::Decryptor<Aes256>;
|
||||
@@ -161,11 +162,13 @@ pub fn decrypt_blob(blob: &DpapiBlob<'_>, masterkey: &[u8]) -> Result<Vec<u8>> {
|
||||
blob.crypt_alg, blob.hmac_alg
|
||||
)));
|
||||
}
|
||||
// Derive session key: HMAC-SHA512(key=masterkey, data=salt).
|
||||
// First 32 bytes = AES key, next 16 = IV.
|
||||
// Derive session key: HMAC-SHA512(key=SHA1(masterkey), data=salt).
|
||||
// DPAPI hashes the 64-byte masterkey down to 20 bytes via SHA-1 before HMAC.
|
||||
// First 32 bytes of the 64-byte HMAC output = AES key, next 16 = IV.
|
||||
type HmacSha512 = Hmac<Sha512>;
|
||||
let mk_sha1 = Sha1::digest(masterkey);
|
||||
let mut h =
|
||||
HmacSha512::new_from_slice(masterkey).map_err(|_| Error::Parse("hmac key".into()))?;
|
||||
HmacSha512::new_from_slice(&mk_sha1).map_err(|_| Error::Parse("hmac key".into()))?;
|
||||
h.update(blob.salt);
|
||||
let session = h.finalize().into_bytes();
|
||||
|
||||
|
||||
@@ -7,13 +7,17 @@ use cbc::cipher::block_padding::NoPadding;
|
||||
use cbc::cipher::{BlockEncryptMut, KeyIvInit};
|
||||
use hmac::{Hmac, Mac};
|
||||
use sha2::Sha512;
|
||||
use sha1::Digest as Sha1Digest;
|
||||
use sha1::Sha1;
|
||||
use vmkatz::chrome::dpapi_decrypt::{decrypt_blob, parse_blob};
|
||||
|
||||
type Aes256CbcEnc = cbc::Encryptor<Aes256>;
|
||||
type HmacSha512 = Hmac<Sha512>;
|
||||
|
||||
fn build_blob(plaintext: &[u8], masterkey: &[u8], salt: &[u8]) -> Vec<u8> {
|
||||
let mut h = HmacSha512::new_from_slice(masterkey).unwrap();
|
||||
// DPAPI: HMAC-SHA512 key is SHA1(masterkey), not the raw masterkey.
|
||||
let mk_sha1 = Sha1::digest(masterkey);
|
||||
let mut h = HmacSha512::new_from_slice(&mk_sha1).unwrap();
|
||||
h.update(salt);
|
||||
let session = h.finalize().into_bytes();
|
||||
let key = &session[..32];
|
||||
|
||||
Reference in New Issue
Block a user