diff --git a/Src/DSInternals.Common.Test/Cryptography/WDigestHashTester.cs b/Src/DSInternals.Common.Test/Cryptography/WDigestHashTester.cs
index 803f256..5377072 100644
--- a/Src/DSInternals.Common.Test/Cryptography/WDigestHashTester.cs
+++ b/Src/DSInternals.Common.Test/Cryptography/WDigestHashTester.cs
@@ -1,6 +1,7 @@
namespace DSInternals.Common.Cryptography.Test
{
using DSInternals.Common;
+ using DSInternals.Common.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
@@ -94,6 +95,21 @@
Assert.AreEqual(WDigestHash.HashCount, hashes.Length);
}
+ [TestMethod]
+ public void WDigestHash_Compute_LDS()
+ {
+ // Property value taken from AD LDS
+ string expectedBlob = "3100011d000000000000000000000000af4156909297baece4e553b731d9d552da58c12e5880cad54a3f909c07b0792eec9d262783c811ad9cc7aeb1ab019fe0af4156909297baece4e553b731d9d552af4156909297baece4e553b731d9d552ec9d262783c811ad9cc7aeb1ab019fe0da58c12e5880cad54a3f909c07b0792e95e11e920c7405ca6639d932888cc11c53d9e953141b322f29eb1a02798c299042eea90067734b2a81abbc79618cc1519d9aac28e63107a495266e755f7a2babac6b5dfb3bfa3b7039058310d5b36ccc7c97824dd59b9a6a053b5fae3d8603f20a5e2bc3111c759efb3a91e3740633e83b12daad09e83cb92477ac59993c5a843b12daad09e83cb92477ac59993c5a843b12daad09e83cb92477ac59993c5a8471e7228faba51df979beef06b34f791820aa1475f40540f0db59f9d2d93fc3da5f88f6d82d185741a82c7fa79e801c6d8eae592a0ce55271a17de0b39cf1e5e9923354fb99887724cf2b10e88108776b427804b8a6d6ed92c11ecb94e40da72c0c997bc1906b1f0092d61bd0efee428b0c997bc1906b1f0092d61bd0efee428b0c997bc1906b1f0092d61bd0efee428bd93e9a9a7452dff036a67a5d5d333d7c4effe21b0afc142382943ef26024649aaa6a6a95c237f2b8efa2f13ecb0cb220";
+ string password = @"Pa$$w0rd";
+ string userDN = "CN=john,DC=dsinternals,DC=com";
+ string namingContext = "DC=dsinternals,DC=com";
+
+ // Compute and compare
+ byte[][] hashes = WDigestHash.ComputeHash(password.ToSecureString(), userDN, namingContext);
+ byte[] blob = WDigestHash.Encode(hashes);
+ Assert.AreEqual(expectedBlob, blob.ToHex());
+ }
+
[TestMethod]
public void WDigestHash_EncodeProperty()
{
@@ -104,4 +120,4 @@
Assert.AreEqual(blob.ToHex(), newBlob.ToHex());
}
}
-}
\ No newline at end of file
+}
diff --git a/Src/DSInternals.Common/Cryptography/WDigestHash.cs b/Src/DSInternals.Common/Cryptography/WDigestHash.cs
index 8ed70d9..c284d9c 100644
--- a/Src/DSInternals.Common/Cryptography/WDigestHash.cs
+++ b/Src/DSInternals.Common/Cryptography/WDigestHash.cs
@@ -33,7 +33,7 @@
private const byte DefaultReserved1Value = (byte)'1';
///
- /// Calculates WDigest hashes of a password.
+ /// Calculates WDigest hashes of a password, as used by AD DS.
///
/// User's password.
/// The userPrincipalName attribute value.
@@ -47,11 +47,11 @@
// Validate the input
Validator.AssertNotNull(password, "password");
Validator.AssertNotNullOrWhiteSpace(samAccountName, "samAccountName");
- Validator.AssertNotNullOrWhiteSpace(netBiosDomainName, "netBiosDomainName");
- Validator.AssertNotNullOrWhiteSpace(dnsDomainName, "dnsDomainName");
+ Validator.AssertNotNull(netBiosDomainName, "netBiosDomainName");
+ Validator.AssertNotNull(dnsDomainName, "dnsDomainName");
// Note that a user does not need to have a UPN.
- if(String.IsNullOrEmpty(userPrincipalName))
+ if(userPrincipalName == null)
{
// Construct the UPN as samAccountName@dnsDomainName
userPrincipalName = String.Format(@"{0}@{1}", samAccountName, dnsDomainName);
@@ -155,6 +155,19 @@
return result;
}
+ ///
+ /// Calculates WDigest hashes of a password, as used by AD LDS.
+ ///
+ /// Account's password.
+ /// Distinguished name of the account.
+ /// Distinguished name of the account's naming context.
+ /// 29 MD5 hashes.
+ /// SecureString is copied into managed memory while calculating the hashes, which is not the best way to deal with it.
+ public static byte[][] ComputeHash(SecureString password, string accountDN, string namingContext)
+ {
+ return ComputeHash(password, String.Empty, accountDN, String.Empty, namingContext);
+ }
+
///
/// Parses the WDIGEST_CREDENTIALS structure within the supplementalCredentials attribute.
///
@@ -242,4 +255,4 @@
return Encoding.UTF8.GetBytes(concatenatedString);
}
}
-}
\ No newline at end of file
+}