Fixed pekList padding

This commit is contained in:
Michael Grafnetter 2019-01-03 11:52:50 +01:00
parent 054f978316
commit d09436c9b3
3 changed files with 61 additions and 16 deletions

View File

@ -188,5 +188,15 @@ namespace DSInternals.Common.Cryptography
return md5.Hash;
}
}
protected static byte[] GenerateSalt(int size)
{
byte[] salt = new byte[size];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
return salt;
}
}
}
}

View File

@ -80,6 +80,30 @@ namespace DSInternals.DataStore.Test
Assert.AreEqual(pek.CurrentKey.ToHex(), pek2.CurrentKey.ToHex());
}
[TestMethod]
public void PasswordEncryptionKey_DataStorePEK_W2019()
{
// Win 2019 RTM (Format is the same as WS 2016)
byte[] encryptedPEK = "030000000100000065DB55C82F7AB29C7FF2CC3518C0DC00433C80629D23D64420D9264BB2FE54288C3121B396CD4DC9BF094EDCBF559DAD3545C52399B883BD0F374EEAF3FA35C71C75DD1447FD0A59C81C60F6703F9B7000000000000000000000000000000000".HexToBinary();
byte[] bootKey = "f51aa1df3bb0175efbd6842bffba81c9".HexToBinary();
byte[] bootKey2 = "c965a6c04ac771ae10932f25efd8d85c".HexToBinary();
// Decrypt
var pek = new DataStoreSecretDecryptor(encryptedPEK, bootKey);
// Re-encrypt with a different boot key
byte[] encryptedPEK2 = pek.ToByteArray(bootKey2);
// Decrypt again with the new boot key
var pek2 = new DataStoreSecretDecryptor(encryptedPEK2, bootKey2);
// And re-encrypt with the original BootKey
byte[] encryptedPEK3 = pek2.ToByteArray(bootKey);
// Check if the newly encrypted PEK has the same length as the original one
Assert.AreEqual(encryptedPEK.Length, encryptedPEK3.Length);
}
[TestMethod]
public void PasswordEncryptionKey_DataStoreDecryptPEK_LDS()
{
@ -233,4 +257,4 @@ namespace DSInternals.DataStore.Test
Assert.AreEqual(4096, cred.KerberosNew.DefaultIterationCount);
}
}
}
}

View File

@ -11,6 +11,7 @@ namespace DSInternals.DataStore
{
private const int BootKeySaltHashRounds = 1000;
private const int EncryptedPekListOffset = sizeof(PekListVersion) + sizeof(PekListFlags) + SaltSize;
private const int AESBlockSize = 16;
// The flags field is probably not used by AD and is always 0.
private const ushort EncryptedSecretFlags = 0;
@ -85,8 +86,8 @@ namespace DSInternals.DataStore
// Blob structure Win2k: Algorithm ID (2B), Flags (2B), PEK ID (4B), Salt (16B), Encrypted secret (rest)
const int EncryptedDataOffsetDES = 2 * sizeof(short) + sizeof(uint) + SaltSize;
// Blob structure Win2016: Algorithm ID (2B), Flags (2B), PEK ID (4B), Salt (16B), Secret Length (4B), Encrypted secret (rest)
const int EncryptedDataOffsetAES = 2 * sizeof(short) + SaltSize + sizeof(ulong);
// const int EncryptedDataOffsetAES = 2 * sizeof(short) + SaltSize + sizeof(ulong);
// Validate (DES has shorter blob)
Validator.AssertMinLength(blob, EncryptedDataOffsetDES + 1, "blob");
@ -116,6 +117,7 @@ namespace DSInternals.DataStore
encryptedSecret = stream.ReadToEnd();
}
}
// Decrypt
byte[] decryptedSecret;
switch (encryptionType)
@ -151,13 +153,9 @@ namespace DSInternals.DataStore
// Write PEK ID(4B)
writer.Write(this.CurrentKeyIndex);
// Generate and Write Salt(16B)
byte[] salt = new byte[SaltSize];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
byte[] salt = GenerateSalt(SaltSize);
writer.Write(salt);
// Perform the encryption
@ -243,11 +241,7 @@ namespace DSInternals.DataStore
}
// Generate random salt
byte[] salt = new byte[SaltSize];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
byte[] salt = GenerateSalt(SaltSize);
// Encode the data structure
using (MemoryStream stream = new MemoryStream())
@ -270,7 +264,24 @@ namespace DSInternals.DataStore
switch (pekListVersion)
{
case PekListVersion.W2016:
encryptedBlob = EncryptUsingAES(cleartextBlob, salt, bootKey, PaddingMode.Zeros);
// We need to add some additional salt and padding to the data:
byte[] salt2 = GenerateSalt(SaltSize);
int cleartextWithSalt2Size = cleartextBlob.Length + SaltSize;
int paddingSize = (AESBlockSize - cleartextWithSalt2Size % AESBlockSize) % AESBlockSize;
byte[] paddedBlob = new byte[cleartextWithSalt2Size+paddingSize];
cleartextBlob.CopyTo(paddedBlob, 0);
// Fill the blob with padding bytes (similar to PKCS#7 padding mode)
for (int i = cleartextBlob.Length; i < cleartextBlob.Length + paddingSize; i++)
{
paddedBlob[i] = (byte)paddingSize;
}
// Add the salt to the end:
salt2.CopyTo(paddedBlob, cleartextBlob.Length + paddingSize);
// We can finally do the encryption
encryptedBlob = EncryptUsingAES(paddedBlob, salt, bootKey, PaddingMode.Zeros);
break;
case PekListVersion.W2k:
encryptedBlob = EncryptUsingRC4(cleartextBlob, salt, bootKey, BootKeySaltHashRounds);
@ -377,4 +388,4 @@ namespace DSInternals.DataStore
return encryptedPekList;
}
}
}
}