C# TripleDES:指定的密钥是“TripleDES”的已知弱密钥,不能使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/744530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:30:17  来源:igfitidea点击:

TripleDES: Specified key is a known weak key for 'TripleDES' and cannot be used

c#.netcryptographycryptographicexception

提问by David Chappelle

I'm using the .NET 3.0 class System.Security.Cryptography.MACTripleDESclass to generate a MAC value. Unfortunately, I am working with a hardware device that uses "1111111111111111" (as hex) as a single-length DES key. The System.Security.Cryptographylibrary does some sanity checking on the key and returns a Exception if you try to use a cryptographically weak key.

我正在使用 .NET 3.0System.Security.Cryptography.MACTripleDES类来生成 MAC 值。不幸的是,我正在使用使用“ 1111111111111111”(作为十六进制)作为单长度 DES 密钥的硬件设备。System.Security.Cryptography如果您尝试使用加密弱密钥,该库会对密钥进行一些完整性检查并返回异常。

For example:

例如:

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

throws an exception

抛出异常

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

I know this is not a secure key. In production, the device will be flashed with a new, secure key. In the mean time, is there any way to inhibit this Exception from being thrown? Perhaps an app.configor registry setting?

我知道这不是安全密钥。在生产中,设备将使用新的安全密钥进行刷写。同时,有什么办法可以禁止抛出这个异常?也许是一个app.config或注册表设置?

Edit: The key would actually be 101010... due to the algorithm forcing odd parity. I'm not sure if this is universal to the DES algorithm or just a requirement in the payment processing work I do.

编辑:密钥实际上是 101010... 由于算法强制奇偶校验。我不确定这是否适用于 DES 算法,或者只是我所做的支付处理工作中的一个要求。

Edit 2: Daniel's answer below has some very good information about hacking .NET. Unfortunately, I wasn't able to solve my problem using this technique, but there is still some interesting reading there.

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

采纳答案by Rasmus Faber

Instead of using MACTripleDES with the DES key repeated to fake a single DES CBC-MAC, you could just implement CBC-MAC yourself on top of DESCryptoServiceProvider.

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

<1111111111111111> is not a weak DES key.

<1111111111111111> 不是弱 DES 密钥。

This will calculate a DES CBC-MAC:

这将计算 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;
    }

回答by Dave Cluderay

Unfortunately, the behaviour can't be overridden.

不幸的是,该行为不能被覆盖。

回答by Daniel Sloof

I wouldn't really recommend it, but you should be able to modify the IL-code that checks for weak keys using Reflectorand the Add-in ReflexIL

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

edit:

编辑:

Sorry, it took a while for me to load all of it up in my Virtual Machine (running Ubuntu) and didn't want to mess with Mono.

抱歉,我花了一段时间才将所有内容加载到我的虚拟机(运行 Ubuntu)中,并且不想弄乱 Mono。

  • Install the ReflexIL Add-in: View -> Add-ins -> Add
  • Open ReflexIL: Tools -> ReflexIL v0.9
  • Find the IsWeakKey() function. (You can use Search: F3)
  • Two functions will come up, doubleclick the one found in System.Security.Cryptography.TripleDES
  • ReflexIL should have come up too. In the Instructions tab, scroll all the way down to line 29 (offset 63).
  • Change ldc.i4.1 to ldc.i4.0, this means the function will always return false.
  • 安装 ReflexIL 插件:查看 -> 插件 -> 添加
  • 打开 ReflexIL:工具 -> ReflexIL v0.9
  • 找到 IsWeakKey() 函数。(您可以使用搜索:F3)
  • 会出现两个函数,双击 System.Security.Cryptography.TripleDES 中的一个
  • ReflexIL 也应该出现。在“说明”选项卡中,一直向下滚动到第 29 行(偏移量 63)。
  • 将 ldc.i4.1 更改为 ldc.i4.0,这意味着该函数将始终返回 false。

In your assemblies pane (left one), you can now scroll up and click on "Common Language Runtime Library", the ReflexIL pane will give you an option to save it.

在您的程序集窗格(左侧)中,您现在可以向上滚动并单击“Common Language Runtime Library”,ReflexIL 窗格将为您提供一个选项来保存它。

Important notes:

重要笔记:

  • BACK UP your original assembly first! (mscorlib.dll)
  • mscorlib.dll is a signed assembly and you will need the .NET SDK (sn.exe tool) for ReflexIL to make it skip verification. I just checked this myself, you should already have this with Visual C# installed. Just click "Register it for verification skipping (on this computer)" when asked to.
  • I don't think I have to tell you to only use this on your development machine :)
  • 首先备份您的原始组件!(mscorlib.dll)
  • mscorlib.dll 是一个签名的程序集,您将需要 ReflexIL 的 .NET SDK(sn.exe 工具)以使其跳过验证。我刚刚自己检查过这个,你应该已经安装了 Visual C#。只需单击“注册以跳过验证(在此计算机上)”。
  • 我不认为我必须告诉你只能在你的开发机器上使用它:)

Good luck! If you need additional instructions, please feel free to use the commentbox.

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

edit2:

编辑2:

I'm confused!

我糊涂了!

I completely removed the IsWeakKey check from the set_Key function in the mscorlib assembly. I am absolutely certain that I modified the correct function, and that I did it correctly. Reflector's disassembler does no longer show the check. The funny thing is however, that Visual C# still throws the same exception.

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

This leads me to believe that mscorlib must somehow still be cached somewhere. However, renaming mscorlib.dll to mscorlib.dll_ leads MSVC# to crash, so it must still be dependent on the original dll.

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

This is quite interesting stuff, but I think I've reached the point where I have no clue what is going on, it just doesn't make any sense! See attached image. :(

这是非常有趣的事情,但我想我已经到了不知道发生了什么的地步,这没有任何意义!见附图。:(

edit3:

编辑3:

I notice in Olly, that unlike assemblies such as mscoree, mscorsec and mscorwks; mscorlib.dll isn't actually located in: c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\

我在 Olly 中注意到,与 mscoree、mscorsec 和 mscorwks 等程序集不同;mscorlib.dll 实际上并不位于:c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\

But instead, in what appears to be a non-existent location: C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

但相反,在一个似乎不存在的位置:C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

I think I am missing something here :) Will investigate this some more.

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

edit4:

编辑4:

Even after having patched out EVERYTHING in IsWeakKey, and played around with both removing and generating new native images (x.ni.dll) of mscorlib.dll using "ngen.exe", I am getting the same exception. I must be noted that even after uninstalling the native mscorlib images, it is still using mscorlib.ni.dll... Meh.

即使在修补了 IsWeakKey 中的所有内容并使用“ngen.exe”删除和生成mscorlib.dll 的新本机映像(x. ni.dll)后,我仍然遇到相同的异常。我必须注意的是,即使卸载了本机 mscorlib 映像后,它仍在使用 mscorlib.ni.dll... 嗯。

I give up. I hope someone will be able to answer what the hell is going on because I sure don't know. :)

我放弃。我希望有人能够回答到底发生了什么,因为我肯定不知道。:)

回答by Robert Kozak

I'm not a security expert but wouldn't XORing your key with another value be enough to satisfy the sanity check? You could do this for your debug version (with proper IFDEF) so you can do proper checking and remove it for your release or production version where the key would be strong enough.

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

回答by Jonathan C Dickinson

I found out what you need to do. Fortunately there is a method that available that creates the ICryptoTranforms that doesn't check for weak keys. You also need to watch out for the base class as it also does sanity checks. Via reflection simply call out the _NewEncryptor method (you need to do a little more reflection, but that's the idea).

我发现你需要做什么。幸运的是,有一种方法可以创建不检查弱密钥的 ICryptoTranforms。您还需要注意基类,因为它也进行健全性检查。通过反射简单地调用 _NewEncryptor 方法(您需要做更多的反射,但这就是想法)。

Luckily the MACTripleDES has a field of type TripleDES, so derive from MACTripleDES and replace it via reflection in the constructors. I have done all the work for you.

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

I can't verify that the correct MAC is generated, but no exceptions are thrown. Furthermore, you might want to doc comment the code and do exception handling (reflection failures - e.g. if the fields/methods are not there) - but this is SO; so I didn't bother.

我无法验证是否生成了正确的 MAC,但没有抛出异常。此外,您可能希望对代码进行文档注释并进行异常处理(反射失败 - 例如,如果字段/方法不存在) - 但这是如此;所以我没有打扰。

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

回答by user156397

There is a great suggestion using reflectionin the MSDN forums

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

回答by captncraig

The reflection based solutions get you around the problem, but they are dirty and evil. Nobody has yet mentioned a very useful method: TripleDES.IsWeakKey

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

I have had this problem and solved it with a very simple utility that I use immediately before I set the Key on my CryptoServiceProvider:

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

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

If you call it anytime you make an encryptor or decryptor, it should prevent the crash and always give you a secure key.

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

回答by user2699139

Quite simple (After looking at the code from GitHub)

很简单(查看GitHub代码后)

static bool TripleDES.IsWeakKey(Byte[] rgbKey)

static bool TripleDES.IsWeakKey(Byte[] rgbKey)

Since it is static - it is easy to test your key against it

由于它是静态的 - 很容易根据它测试您的密钥

  1. Size must be either 16 or 24 bytes (???) Why can't they put it in the documentation
  2. The code check for few simple repetitions Just create random enuogh values
  1. 大小必须是 16 或 24 字节 (???) 为什么他们不能把它放在文档中
  2. 代码检查几个简单的重复只需创建随机足够的值

See code at: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

见代码:https: //github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

Dekel

德克尔