TripleDES:指定密钥是’TripleDES’的已知弱密钥,无法使用

我正在使用.NET 3.0类System.Security.Cryptography.MACTripleDES类来生成MAC值。 不幸的是,我正在使用一个使用“ 1111111111111111 ”(作为hex)作为单长DES密钥的硬件设备。 System.Security.Cryptography库对密钥进行一些健全性检查,如果您尝试使用加密弱密钥,则返回Exception。

例如:

 byte[] key = new byte[24]; for (int i = 0; i < key.Length; i++) key[i] = 0x11; byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] computedMac = null; using (MACTripleDES mac = new MACTripleDES(key)) { computedMac = mac.ComputeHash(data); } 

抛出一个例外

 System.Security.Cryptography.CryptographicException : Specified key is a known weak key for 'TripleDES' and cannot be used. 

我知道这不是一个安全的密钥。 在生产中,设备将使用新的安全密钥进行闪存。 同时,有没有办法抑制这个exception被抛出? 也许app.config或注册表设置?

编辑:密钥实际上是101010 …由于算法强制奇校验。 我不确定这是DES算法的通用性还是我付款处理工作的要求。

编辑2:Daniel的答案下面有一些关于黑客.NET的非常好的信息。 不幸的是,我无法使用这种技术解决我的问题,但仍然有一些有趣的阅读。

您可以在DESCryptoServiceProvider之上自行实现CBC-MAC,而不是使用重复使用DES密钥的MACTripleDES来伪造单个DES CBC-MAC。

<1111111111111111>不是一个弱DES密钥。

这将计算DES CBC-MAC:

 public static byte[] CalcDesMac(byte[] key, byte[] data){ DESCryptoServiceProvider des = new DESCryptoServiceProvider(); des.Key = key; des.IV = new byte[8]; des.Padding = PaddingMode.Zeros; MemoryStream ms = new MemoryStream(); using(CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write)){ cs.Write(data, 0, data.Length); } byte[] encryption = ms.ToArray(); byte[] mac = new byte[8]; Array.Copy(encryption, encryption.Length-8, mac, 0, 8); PrintByteArray(encryption); return mac; } 

我不会真的推荐它,但你应该能够使用Reflector和Add-in ReflexIL修改检查弱键的IL代码

编辑:

对不起,我需要一段时间才能在我的虚拟机(运行Ubuntu)中加载所有内容并且不想搞乱Mono。

  • 安装ReflexIL加载项:视图 – >加载项 – >添加
  • 打开ReflexIL:工具 – > ReflexIL v0.9
  • 找到IsWeakKey()函数。 (您可以使用搜索:F3)
  • 将出现两个函数,双击System.Security.Cryptography.TripleDES中找到的函数
  • ReflexIL也应该出现。 在“说明”选项卡中,一直向下滚动到第29行(偏移63)。
  • 将ldc.i4.1更改为ldc.i4.0,这意味着该函数将始终返回false。

在程序集窗格(左侧)中,您现在可以向上滚动并单击“公共语言运行库”,ReflexIL窗格将为您提供保存选项。

重要笔记:

  • 首先备份原始组件! (mscorlib.dll中)
  • mscorlib.dll是一个已签名的程序集,您需要使用.NET SDK(sn.exe工具)来使ReflexIL跳过validation。 我自己检查了一下,你应该已经安装了Visual C#。 当被要求时,只需点击“注册它以进行validation跳过(在此计算机上)”。
  • 我不认为我必须告诉你只在你的开发机器上使用它:)

祝好运! 如果您需要其他说明,请随时使用评论框。

EDIT2:

我糊涂了!

http://sofzh.miximages.com/c%23/2r6fwbo_th.png

我完全从mscorlib程序集中的set_Key函数中删除了IsWeakKey检查。 我绝对肯定我修改了正确的function,并且我做得正确。 Reflector的反汇编程序不再显示检查。 然而,有趣的是,Visual C#仍然会抛出相同的exception。

这让我相信mscorlib必须以某种方式仍然在某处缓存。 但是,将mscorlib.dll重命名为mscorlib.dll_导致MSVC#崩溃,因此它仍必须依赖于原始dll。

这是非常有趣的东西,但我想我已经达到了一点,我不知道发生了什么,它只是没有任何意义! 见附图。 🙁

EDIT3:

我在Olly注意到,与mscoree,mscorsec和mscorwks等组件不同; mscorlib.dll实际上不在:c:\ WINDOWS \ Microsoft.NET \ Framework \ v2.0.50727 \

但相反,在看起来不存在的位置:C:\ WINDOWS \ assembly \ NativeImages_v2.0.50727_32 \ mscorlib \ 6d667f19d687361886990f3ca0f49816 \ mscorlib.ni.dll

我想我在这里遗漏了一些东西:)将对此进行更多调查。

edit4:

即使在IsWeakKey中修复了所有内容,并使用“ngen.exe”删除和生成mscorlib.dll的新本机映像(x.ni .dll)之后,我也得到了相同的exception。 我必须注意,即使在卸载本机mscorlib映像后,它仍然使用mscorlib.ni.dll … Meh。

我放弃。 我希望有人能够回答到底是怎么回事,因为我肯定不知道。 🙂

我发现了你需要做的事情。 幸运的是,有一种方法可用于创建不检查弱键的ICryptoTranforms。 您还需要注意基类,因为它也会进行健全性检查。 通过reflection简单地调出_NewEncryptor方法(你需要做一些反思,但这就是想法)。

幸运的是,MACTripleDES有一个TripleDES类型的字段,因此从MACTripleDES派生并通过构造函数中的reflection替换它。 我为你完成了所有的工作。

我无法validation是否生成了正确的MAC,但没有抛出exception。 此外,您可能希望doc注释代码并执行exception处理(reflection失败 – 例如,如果字段/方法不存在) – 但这是SO; 所以我没有打扰。

 using System; using System.Reflection; using System.Security.Cryptography; using System.IO; namespace DesHack { class Program { static void Main(string[] args) { byte[] key = new byte[24]; for (int i = 0; i < key.Length; i++) key[i] = 0x11; byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] computedMac = null; using (MACTripleDES mac = new MACTripleDESHack(key)) { computedMac = mac.ComputeHash(data); } } } class MACTripleDESHack : MACTripleDES { TripleDES _desHack = new DesHack(); static FieldInfo _cspField = typeof(MACTripleDES).GetField("des", BindingFlags.Instance | BindingFlags.NonPublic); public MACTripleDESHack() : base() { RewireDes(); } public MACTripleDESHack(byte[] rgbKey) : base(rgbKey) { RewireDes(); } private void RewireDes() { _cspField.SetValue(this, _desHack); } } class DesHack : TripleDES { TripleDESCryptoServiceProvider _backing = new TripleDESCryptoServiceProvider(); static MethodInfo _newEncryptor; static object _encrypt; static object _decrypt; public override int BlockSize { get { return _backing.BlockSize; } set { _backing.BlockSize = value; } } public override int FeedbackSize { get { return _backing.FeedbackSize; } set { _backing.FeedbackSize = value; } } // For these two we ALSO need to avoid // the base class - it also checks // for weak keys. private byte[] _iv; public override byte[] IV { get { return _iv; } set { _iv = value; } } private byte[] _key; public override byte[] Key { get { return _key; } set { _key = value; } } public override int KeySize { get { return _backing.KeySize; } set { _backing.KeySize = value; } } public override KeySizes[] LegalBlockSizes { get { return _backing.LegalBlockSizes; } } public override KeySizes[] LegalKeySizes { get { return _backing.LegalKeySizes; } } public override CipherMode Mode { get { return _backing.Mode; } set { _backing.Mode = value; } } public override PaddingMode Padding { get { return _backing.Padding; } set { _backing.Padding = value; } } static DesHack() { _encrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Encrypt").GetValue(null); _decrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Decrypt").GetValue(null); _newEncryptor = typeof(TripleDESCryptoServiceProvider).GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance); } public DesHack() { } public override ICryptoTransform CreateDecryptor() { return CreateDecryptor(_key, _iv); } public override ICryptoTransform CreateEncryptor() { return CreateEncryptor(_key, _iv); } public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) { // return this._NewEncryptor(rgbKey, base.ModeValue, rgbIV, base.FeedbackSizeValue, CryptoAPITransformMode.Decrypt); return (ICryptoTransform) _newEncryptor.Invoke(_backing, new object[] { rgbKey, ModeValue, rgbIV, FeedbackSizeValue, _decrypt }); } public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) { // return this._NewEncryptor(rgbKey, base.ModeValue, rgbIV, base.FeedbackSizeValue, CryptoAPITransformMode.Encrypt); return (ICryptoTransform) _newEncryptor.Invoke(_backing, new object[] { rgbKey, ModeValue, rgbIV, FeedbackSizeValue, _encrypt }); } public override void GenerateIV() { _backing.GenerateIV(); } public override void GenerateKey() { _backing.GenerateKey(); } protected override void Dispose(bool disposing) { if (disposing) ((IDisposable) _backing).Dispose(); base.Dispose(disposing); } } } 

不幸的是,这种行为无法被覆盖。

在MSDN论坛中使用reflection有一个很好的建议

我不是安全专家,但不会将你的密钥与另一个值进行异或,以满足理智检查的要求吗? 您可以为您的调试版本(使用正确的IFDEF)执行此操作,以便您可以对您的发行版或生产版本进行适当的检查并将其删除,其中密钥足够强大。

基于reflection的解决方案可以解决问题,但它们是肮脏和邪恶的。 还没有人提到一个非常有用的方法: TripleDES.IsWeakKey

我遇到了这个问题并使用一个非常简单的实用程序来解决它,我在使用CryptoServiceProvider上的Key之前立即使用它:

 private void MakeSecureKey(byte[] key) { while(TripleDES.IsWeakKey(key)) { var sha = SHA256Managed.Create().ComputeHash(key); Array.Copy(sha,key,key.Length); } } 

如果您在制作加密器或解密器时随时调用它,它应该可以防止崩溃并始终为您提供安全密钥。

非常简单(看完GitHub的代码后)

static bool TripleDES.IsWeakKey(Byte [] rgbKey)

由于它是静态的 – 很容易测试你的密钥

  1. 大小必须是16或24字节(???)为什么他们不能把它放在文档中
  2. 代码检查几个简单的重复只是创建随机enuogh值

请参阅以下代码: https : //github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

德克尔