You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The entire world apparently calls what BitLocker uses to wrap keys "AES-CCM". Unfortunately, that's not what is actually implemented. The algorithm implemented by libcaes_crypt_ccm isn't CCM: it doesn't have a MAC, it doesn't have associated data, and it doesn't use the first keystream block for that. That makes it just AES-CTR.
The only thing "CCM" about it is that the nonce is prepended with a byte of value 15 - (uint8_t) nonce_size - 1 (which CCM does, and is not inherent to CTR mode). There's none of the other bits that would make it compliant with the CCM specification (RFC3610). Crucially, BitLocker key unwrapping can be implemented using a standard AES-CTR implementation (just prepend 0x02 to the nonce), but cannot be implemented using a standard AES-CCM implementation (because there is no way to disable the whole MAC machinery).
I would recommend renaming all mentions of CCM to CTR, to avoid confusion. I just spent a few hours wondering why using PyCryptodome yielded incorrect decryptions of BitLocker wrapped keys. Instead, CTR mode is what you want. In PyCryptodome:
python
def decrypt(p, k):
nonce = p[:12]
nonce = bytes([15 - len(nonce) - 1]) + nonce
aes = AES.new(k, AES.MODE_CTR, nonce=nonce)
a = aes.decrypt(p[12:])
return a
~~ is the code you'd want to unwrap a BitLocker wrapped key, with MODE_CTR, not MODE_CCM.
The text was updated successfully, but these errors were encountered:
I take that back; it is CCM, it's just that the tag is prepended. I was really confused because there was no notion of the two chunks in the libbde codebase.
So the problem is that libcaes_crypt_ccm doesn't actually implement CCM. It implements the CTR part of CCM, and then returns 16 bytes of garbage in front of the result (what would be the tag section).
This is a correct implementation of BitLocker wrapped key decryption:
And a correct implementation of AES-CCM would validate the tag correctly according to RFC3610, and return an error if it mismatches (this also lets you recognize if the wrong key was supplied).
marcan
changed the title
Key wrapping algorithm name is incorrect (CCM should be CTR)
CCM key unwrapping does not validate tag and returns 16 bytes of garbage header
Jan 3, 2019
I think it should be fine in libcaes as it is a standard mode, if the interface is changed to be standard-compliant (and then libbde is changed to use it in a standard way).
The entire world apparently calls what BitLocker uses to wrap keys "AES-CCM". Unfortunately, that's not what is actually implemented. The algorithm implemented bylibcaes_crypt_ccm
isn't CCM: it doesn't have a MAC, it doesn't have associated data, and it doesn't use the first keystream block for that. That makes it just AES-CTR.The only thing "CCM" about it is that the nonce is prepended with a byte of value15 - (uint8_t) nonce_size - 1
(which CCM does, and is not inherent to CTR mode). There's none of the other bits that would make it compliant with the CCM specification (RFC3610). Crucially, BitLocker key unwrapping can be implemented using a standard AES-CTR implementation (just prepend 0x02 to the nonce), but cannot be implemented using a standard AES-CCM implementation (because there is no way to disable the whole MAC machinery).I would recommend renaming all mentions of CCM to CTR, to avoid confusion. I just spent a few hours wondering why using PyCryptodome yielded incorrect decryptions of BitLocker wrapped keys. Instead, CTR mode is what you want. In PyCryptodome:pythondef decrypt(p, k):
nonce = p[:12]
nonce = bytes([15 - len(nonce) - 1]) + nonce
aes = AES.new(k, AES.MODE_CTR, nonce=nonce)
a = aes.decrypt(p[12:])
return a
~~
is the code you'd want to unwrap a BitLocker wrapped key, withMODE_CTR
, notMODE_CCM
.The text was updated successfully, but these errors were encountered: