【问题标题】:C# NTLM Hash CalculatorC# NTLM 哈希计算器
【发布时间】:2017-10-18 21:36:01
【问题描述】:

我最近开始学习 C#。我试图用这种语言生成一个 NTLM 哈希,但我找不到一个函数来为我做这件事。在 python 3.x 中,我将导入 hashlib 并使用 hashlib.new("md4", "Hello, World!".encode("utf-16le")) 计算它。

我在 C# 中的对象浏览器中进行了搜索,但没有找到任何东西,最接近的是 Windows NTLM 身份验证类。我还搜索了 Microsoft 的文档并找到了哈希计算器,但仅限于 sha1 和 md5。

有没有办法在 C# 中计算 NTLM 哈希?你能告诉我一个如何做的例子吗,我更喜欢一个简短的方法来保持简单。

谢谢。

【问题讨论】:

    标签: c# hash ntlm


    【解决方案1】:

    您可以使用反射为现有的加密提供程序创建扩展,以调用 CNG for MD4(.Net 可能应该这样做,或者更容易):

    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);
            }
        }
    }
    

    一旦你这样做了,几个帮助扩展将让你轻松使用它(我修改它以创建一个单例,因此它不必在每次使用时都进行反射/创建工作):

    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")));
        }
    }
    

    现在您只需对一些示例数据调用扩展方法:

    void Main() {
        var input = "testing";
    
        var hash = input.MD4();
        var hashStr = hash.AsHexString();
        Console.WriteLine(hashStr);
    }
    

    【讨论】:

    • NTLM 哈希使用 UTF-16LE,而不是 ASCII。 (Encoding.Unicode 是 UTF-16LE 的内置实例。)
    • 我检查了它在网上创建的哈希,它工作得非常好,谢谢!
    【解决方案2】:

    我认为您需要使用 BouncyCastle 来计算 HASH,有一个 .net 移植效果很好。

    这是计算 NTLM 哈希的所有步骤: https://asecuritysite.com/encryption/lmhash

    【讨论】:

      【解决方案3】:

      代码可以在文章末尾找到。它对 MD4 使用 BC,因为大多数 MD4 实现都有一种方法来支持弱键。 NTLM 不考虑弱密钥,因此如果它们出现,您必须能够使用它们。

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

      【讨论】:

      • 我测试了一个包含 120 000 个单词的字典,两种方法都创建了相同的哈希值,尽管 BC 版本的速度大约是前者的两倍。 (0.9 秒对 1.8 秒)
      【解决方案4】:

      根据上面接受的答案,这是为任何有效的ALG_ID 调用 CNG 的通用解决方案。谢谢 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);
      }
      

      使用algID = 0x8002 为 MD4 创建一个实例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-23
        • 2012-07-12
        • 1970-01-01
        • 2016-08-03
        • 2017-02-04
        • 2012-04-14
        • 2014-01-14
        • 1970-01-01
        相关资源
        最近更新 更多