NTLM Strong Hash generation

This commit is contained in:
Michael Grafnetter 2018-07-19 13:23:36 +02:00
parent 02b3066b5f
commit 6cfe1c16a5
4 changed files with 44 additions and 39 deletions

View File

@ -70,5 +70,18 @@ namespace DSInternals.Common.Cryptography.Test
string expected = "92937945B518814341DE3F726500D4FF";
Assert.AreEqual(expected, result);
}
[TestMethod]
public void NTHash_GenerateRandom()
{
byte[] randomHash1 = NTHash.GetRandom();
byte[] randomHash2 = NTHash.GetRandom();
// Check hash size
Assert.AreEqual(NTHash.HashSize, randomHash1.Length);
// Check that the hashes are not the same
Assert.AreNotEqual(randomHash1.ToHex(), randomHash2.ToHex());
}
}
}

View File

@ -2,6 +2,7 @@
{
using DSInternals.Common.Interop;
using System.Security;
using System.Security.Cryptography;
// See http://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm%28v=vs.110%29.aspx
public static class NTHash
@ -45,5 +46,15 @@
Validator.AssertSuccess(result);
return hash;
}
public static byte[] GetRandom()
{
using (var rng = RandomNumberGenerator.Create())
{
var randomHash = new byte[HashSize];
rng.GetBytes(randomHash);
return randomHash;
}
}
}
}

View File

@ -10,27 +10,27 @@
/// </summary>
/// <remarks>This structure is undocumented. Kudos to Benjamin Delpy for figuring out the most important parts of it.</remarks>
[StructLayout(LayoutKind.Sequential)]
internal struct KerberosCryptoSystem
internal class KerberosCryptoSystem
{
internal KerberosKeyType Type;
int BlockSize;
KerberosKeyType Type1;
internal int KeySize;
int Size;
int Unknown2;
int Unknown3;
internal readonly KerberosKeyType Type;
readonly int BlockSize;
readonly KerberosKeyType Type1;
internal readonly int KeySize;
readonly int Size;
readonly int Unknown2;
readonly int Unknown3;
[MarshalAs(UnmanagedType.LPWStr)]
internal string AlgorithmName;
IntPtr Initialize;
IntPtr Encrypt;
IntPtr Decrypt;
IntPtr Finish;
private KerberosKeyDerivationFunction KeyDerivationFunction;
IntPtr RandomKey;
IntPtr Control;
IntPtr Unknown4;
IntPtr Unknown5;
IntPtr Unknown6;
internal readonly string AlgorithmName;
readonly IntPtr Initialize;
readonly IntPtr Encrypt;
readonly IntPtr Decrypt;
readonly IntPtr Finish;
readonly KerberosKeyDerivationFunction KeyDerivationFunction;
readonly IntPtr RandomKey;
readonly IntPtr Control;
readonly IntPtr Unknown4;
readonly IntPtr Unknown5;
readonly IntPtr Unknown6;
delegate NtStatus KerberosKeyDerivationFunction([In] ref SecureUnicodeString password, [In] ref UnicodeString salt, int iterations, [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] key);

View File

@ -14,7 +14,6 @@ namespace DSInternals.Common.Interop
internal const int LMHashNumBits = 128;
internal const int LMHashNumBytes = NTHashNumBits / 8;
internal const int LMPasswordMaxChars = 14;
// TODO: Validate NT Hash max chars
internal const int NTPasswordMaxChars = 127;
private const int MaxRegistryKeyClassSize = 256;
@ -198,25 +197,7 @@ namespace DSInternals.Common.Interop
}
[DllImport(CryptDll, CharSet = CharSet.Auto, SetLastError = true)]
private static extern NtStatus CDLocateCSystem(KerberosKeyType type, out IntPtr cryptoSystem);
internal static NtStatus CDLocateCSystem(KerberosKeyType type, out KerberosCryptoSystem cryptoSystem)
{
IntPtr cryptoSystemPtr;
NtStatus status = CDLocateCSystem(type, out cryptoSystemPtr);
if(status == NtStatus.Success)
{
cryptoSystem = (KerberosCryptoSystem)Marshal.PtrToStructure(cryptoSystemPtr, typeof(KerberosCryptoSystem));
}
else
{
// Return a blank structure
cryptoSystem = new KerberosCryptoSystem();
}
return status;
}
internal static extern NtStatus CDLocateCSystem(KerberosKeyType type, out KerberosCryptoSystem cryptoSystem);
/// <summary>
/// Creates a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and loads the data from the specified registry hive into that subkey.