mirror of
https://github.com/MichaelGrafnetter/DSInternals
synced 2025-01-09 15:49:53 +00:00
Fixed pekList padding
This commit is contained in:
parent
054f978316
commit
d09436c9b3
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user