简体   繁体   中英

C# NTLM Hash Calculator

I recently began learning C#. I tried to generate an NTLM hash in this language but I could't find a function to do this for me. In python 3.x I would import hashlib and calculate it with hashlib.new("md4", "Hello, World!".encode("utf-16le")) .

I searched through the Object Browser in C# but didn't find anything, the closest was a windows NTLM authentication class. I also searched Microsoft's docs and found hash calculators, but only for sha1 and md5.

Is there a way to calculate an NTLM hash in C#? Can you please show me an example of how to do it, and I would prefer a short method to keep it simple.

Thanks.

You can create an extension to the existing cryptography providers using Reflection to call CNG for MD4 (something .Net should probably either do, or make much easier):

namespace System.Security.Cryptography {
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class MD4 : HashAlgorithm {
        static MD4() {
            CryptoConfig.AddAlgorithm(typeof(MD4CryptoServiceProvider), "System.Security.Cryptography.MD4");
        }

        protected MD4() {
            HashSizeValue = 128;
        }

        new static public MD4 Create() {
            return Create("System.Security.Cryptography.MD4");
        }

        new static public MD4 Create(string algName) {
            return (MD4)CryptoConfig.CreateFromName(algName);
        }
    }

    [System.Runtime.InteropServices.ComVisible(true)]
    public sealed class MD4CryptoServiceProvider : MD4 {
        internal static class Utils {
            internal static Type UtilsType = Type.GetType("System.Security.Cryptography.Utils");

            public static T InvokeInternalMethodOfType<T>(object o, object pType, string methodName, params object[] args) {
                var internalType = (pType is string internalTypeName) ? Type.GetType(internalTypeName) : (Type)pType;
                var internalMethods = internalType.GetMethods(BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | (o == null ? BindingFlags.Static : 0));
                var internalMethod = internalMethods.Where(m => m.Name == methodName && m.GetParameters().Length == args.Length).Single();
                return (T)internalMethod?.Invoke(o, args);
            }

            public static T GetInternalPropertyValueOfInternalType<T>(object o, object pType, string propertyName) {
                var internalType = (pType is string internalTypeName) ? Type.GetType(internalTypeName) : (Type)pType;
                var internalProperty = internalType.GetProperty(propertyName, BindingFlags.NonPublic | (o == null ? BindingFlags.Static : 0));
                return (T)internalProperty.GetValue(o);
            }

            internal static SafeHandle CreateHash(int algid) {
                return InvokeInternalMethodOfType<SafeHandle>(null, UtilsType, "CreateHash", GetInternalPropertyValueOfInternalType<object>(null, UtilsType, "StaticProvHandle"), algid);
            }

            internal static void HashData(SafeHandle h, byte[] data, int ibStart, int cbSize) {
                InvokeInternalMethodOfType<object>(null, UtilsType, "HashData", h, data, ibStart, cbSize);
            }

            internal static byte[] EndHash(SafeHandle h) {
                return InvokeInternalMethodOfType<byte[]>(null, UtilsType, "EndHash", h);
            }
        }

        internal const int ALG_CLASS_HASH = (4 << 13);
        internal const int ALG_TYPE_ANY = (0);
        internal const int ALG_SID_MD4 = 2;
        internal const int CALG_MD4 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4);

        [System.Security.SecurityCritical]
        private SafeHandle _safeHashHandle = null;

        [System.Security.SecuritySafeCritical]
        public MD4CryptoServiceProvider() {
            if (CryptoConfig.AllowOnlyFipsAlgorithms)
                throw new InvalidOperationException("Cryptography_NonCompliantFIPSAlgorithm");
            Contract.EndContractBlock();
            // cheat with Reflection
            _safeHashHandle = Utils.CreateHash(CALG_MD4);
        }

        protected override void Dispose(bool disposing) {
            if (_safeHashHandle != null && !_safeHashHandle.IsClosed)
                _safeHashHandle.Dispose();
            base.Dispose(disposing);
        }

        public override void Initialize() {
            if (_safeHashHandle != null && !_safeHashHandle.IsClosed)
                _safeHashHandle.Dispose();

            _safeHashHandle = Utils.CreateHash(CALG_MD4);
        }

        protected override void HashCore(byte[] rgb, int ibStart, int cbSize) {
            Utils.HashData(_safeHashHandle, rgb, ibStart, cbSize);
        }

        protected override byte[] HashFinal() {
            return Utils.EndHash(_safeHashHandle);
        }
    }
}

Once you've done that, a couple of helper extensions will let you use it easily (I modified this to create a singleton so it doesn't have to do the work of reflecting/creating every time you use it):

static class Ext {
    public static HashAlgorithm MD4Singleton;

    static Ext() { 
        MD4Singleton = System.Security.Cryptography.MD4.Create();   
    }

    public static byte[] MD4(this string s) { 
        return MD4Singleton.ComputeHash(System.Text.Encoding.Unicode.GetBytes(s));
    }

    public static string AsHexString(this byte[] bytes) { 
        return String.Join("", bytes.Select(h => h.ToString("X2")));
    }
}

Now you just call the extension methods on some sample data:

void Main() {
    var input = "testing";

    var hash = input.MD4();
    var hashStr = hash.AsHexString();
    Console.WriteLine(hashStr);
}

I think you need to use the BouncyCastle to calculate the HASH, there is a .net porting that works quite well.

and here is all the step to calculate the NTLM hash: https://asecuritysite.com/encryption/lmhash

Code can be found at the end of the post here. It uses BC for the MD4, as most MD4 implementations have a way to avid weak keys. NTLM does not account weak keys, so you must be able to use them if they arise.

https://markgamache.blogspot.com/2013/01/ntlm-challenge-response-is-100-broken.html

Here's a general solution to call CNG for any valid ALG_ID , based on the accepted answer above. Thank you NetMage!

public class HashByID : HashAlgorithm {
    static readonly Dictionary<int, int> hashSizes = new Dictionary<int,int>() { {0x8001,128},{0x8002,128},{0x8003,128},{0x8004,160},{0x8006,128},{0x8007,160},{0x800c,256},{0x800d,384},{0x800e,512}};
    static readonly Type hUtils;
    static readonly SafeHandle hStaticProv;
    static readonly Func<SafeHandle, int, SafeHandle> fCreate;
    static readonly Action<SafeHandle, byte[], int, int> fHash;
    static readonly Func<SafeHandle, byte[]> fHashEnd;
    public static bool inited;
    public readonly int algID;
    SafeHandle hh = null;
    static HashByID() {
        try {
            hUtils = Type.GetType("System.Security.Cryptography.Utils");
            hStaticProv = (SafeHandle)hUtils.GetProperty("StaticProvHandle", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null);
            fCreate = (Func<SafeHandle, int, SafeHandle>)hUtils.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "CreateHash" && x.GetParameters().Length == 2).Single().CreateDelegate(null, typeof(SafeHandle), typeof(int), typeof(SafeHandle));
            fHash = (Action<SafeHandle, byte[], int, int>)hUtils.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "HashData" && x.GetParameters().Length == 4).Single().CreateDelegate(null, typeof(SafeHandle), typeof(byte[]), typeof(int), typeof(int));
            fHashEnd = (Func<SafeHandle, byte[]>)hUtils.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "EndHash" && x.GetParameters().Length == 1).Single().CreateDelegate(null, typeof(SafeHandle), typeof(byte[]));
            inited = true;
        } catch { }
    }
    public HashByID(int algID) {
        if (algID == 0x8009) algID = 0x8004;    //map CALG_HMAC -> CALG_SHA1
        this.algID = algID;
        hashSizes.TryGetValue(algID, out HashSizeValue);
        Initialize();
    }
    protected override void Dispose(bool disposing) {
        if (hh != null && !hh.IsClosed) hh.Dispose();
        base.Dispose(disposing);
    }
    public override void Initialize() {
        if (hh != null && !hh.IsClosed) hh.Dispose();
        hh = fCreate(hStaticProv, algID);
    }
    protected override void HashCore(byte[] data, int ofs, int len) {
        fHash(hh, data, ofs, len);
    }
    protected override byte[] HashFinal() {
        return fHashEnd(hh);
    }
}

//Delegate creation helper
public static Delegate CreateDelegate(this MethodInfo methodInfo, object target, params Type[] custTypes) {
    Func<Type[], Type> getType;
    bool isAction = methodInfo.ReturnType.Equals((typeof(void))), cust = custTypes.Length > 0;
    Type[] types = cust ? custTypes : methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
    if (isAction) getType = Expression.GetActionType;
    else {
        getType = Expression.GetFuncType;
        if (!cust) types = types.Concat(new[] { methodInfo.ReturnType }).ToArray();
    }
    if (cust) {
        int i, nargs = types.Length - (isAction ? 0 : 1);
        var dm = new DynamicMethod(methodInfo.Name, isAction ? typeof(void) : types.Last(), types.Take(nargs).ToArray(), typeof(object), true);
        var il = dm.GetILGenerator();
        for (i = 0; i < nargs; i++)
            il.Emit(OpCodes.Ldarg_S, i);
        il.Emit(OpCodes.Call, methodInfo);
        il.Emit(OpCodes.Ret);
        if (methodInfo.IsStatic) return dm.CreateDelegate(getType(types));
        return dm.CreateDelegate(getType(types), target);
    }
    if (methodInfo.IsStatic) return Delegate.CreateDelegate(getType(types), methodInfo);
    return Delegate.CreateDelegate(getType(types), target, methodInfo.Name);
}

Create an instance with algID = 0x8002 for MD4.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM