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

时间:2021-07-25 18:25:22

I'm using the .NET 3.0 class System.Security.Cryptography.MACTripleDES class 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.Cryptography library does some sanity checking on the key and returns a Exception if you try to use a cryptographically weak key.

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

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.config or 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的答案下面有一些关于黑客.NET的非常好的信息。不幸的是,我无法使用这种技术解决我的问题,但仍然有一些有趣的阅读。

8 个解决方案

#1


1  

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,而不是使用重复使用DES密钥的MACTripleDES来伪造单个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;
    }

#2


6  

I wouldn't really recommend it, but you should be able to modify the IL-code that checks for weak keys using Reflector and 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
  • 安装ReflexIL加载项:视图 - >加载项 - >添加

  • Open ReflexIL: Tools -> ReflexIL v0.9
  • 打开ReflexIL:工具 - > ReflexIL v0.9

  • Find the IsWeakKey() function. (You can use Search: F3)
  • 找到IsWeakKey()函数。 (您可以使用搜索:F3)

  • Two functions will come up, doubleclick the one found in System.Security.Cryptography.TripleDES
  • 将出现两个函数,双击System.Security.Cryptography.TripleDES中找到的函数

  • ReflexIL should have come up too. In the Instructions tab, scroll all the way down to line 29 (offset 63).
  • ReflexIL也应该出现。在“说明”选项卡中,一直向下滚动到第29行(偏移63)。

  • Change ldc.i4.1 to ldc.i4.0, this means the function will always return false.
  • 将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.

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

Important notes:

  • BACK UP your original assembly first! (mscorlib.dll)
  • 首先备份原始组件! (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.
  • mscorlib.dll是一个已签名的程序集,您需要使用.NET SDK(sn.exe工具)来使ReflexIL跳过验证。我自己检查了一下,你应该已经安装了Visual C#。当被要求时,只需点击“注册它以进行验证跳过(在此计算机上)”。

  • I don't think I have to tell you to only use this on your development machine :)
  • 我不认为我必须告诉你只在你的开发机器上使用它:)

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

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

edit2:

I'm confused!

http://i44.tinypic.com/2r6fwbo_th.png

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检查。我绝对肯定我修改了正确的功能,并且我做得正确。 Reflector的反汇编程序不再显示检查。然而,有趣的是,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:

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:

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 ... Meh。

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

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

#3


4  

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,但没有抛出异常。此外,您可能希望对代码进行文档注释并进行异常处理(反射失败 - 例如,如果字段/方法不存在) - 但这是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);
        }
    }
}

#4


1  

Unfortunately, the behaviour can't be overridden.

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

#5


1  

There is a great suggestion using reflection in the MSDN forums

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

#6


0  

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)执行此操作,以便您可以对您的发行版或生产版本进行适当的检查并将其删除,其中密钥足够强大。

#7


-1  

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上的Key之前立即使用它:

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.

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

#8


-1  

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. 大小必须是16或24字节(???)为什么他们不能把它放在文档中

  3. The code check for few simple repetitions Just create random enuogh values
  4. 代码检查几个简单的重复只是创建随机enuogh值

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

#1


1  

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,而不是使用重复使用DES密钥的MACTripleDES来伪造单个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;
    }

#2


6  

I wouldn't really recommend it, but you should be able to modify the IL-code that checks for weak keys using Reflector and 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
  • 安装ReflexIL加载项:视图 - >加载项 - >添加

  • Open ReflexIL: Tools -> ReflexIL v0.9
  • 打开ReflexIL:工具 - > ReflexIL v0.9

  • Find the IsWeakKey() function. (You can use Search: F3)
  • 找到IsWeakKey()函数。 (您可以使用搜索:F3)

  • Two functions will come up, doubleclick the one found in System.Security.Cryptography.TripleDES
  • 将出现两个函数,双击System.Security.Cryptography.TripleDES中找到的函数

  • ReflexIL should have come up too. In the Instructions tab, scroll all the way down to line 29 (offset 63).
  • ReflexIL也应该出现。在“说明”选项卡中,一直向下滚动到第29行(偏移63)。

  • Change ldc.i4.1 to ldc.i4.0, this means the function will always return false.
  • 将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.

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

Important notes:

  • BACK UP your original assembly first! (mscorlib.dll)
  • 首先备份原始组件! (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.
  • mscorlib.dll是一个已签名的程序集,您需要使用.NET SDK(sn.exe工具)来使ReflexIL跳过验证。我自己检查了一下,你应该已经安装了Visual C#。当被要求时,只需点击“注册它以进行验证跳过(在此计算机上)”。

  • I don't think I have to tell you to only use this on your development machine :)
  • 我不认为我必须告诉你只在你的开发机器上使用它:)

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

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

edit2:

I'm confused!

http://i44.tinypic.com/2r6fwbo_th.png

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检查。我绝对肯定我修改了正确的功能,并且我做得正确。 Reflector的反汇编程序不再显示检查。然而,有趣的是,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:

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:

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 ... Meh。

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

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

#3


4  

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,但没有抛出异常。此外,您可能希望对代码进行文档注释并进行异常处理(反射失败 - 例如,如果字段/方法不存在) - 但这是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);
        }
    }
}

#4


1  

Unfortunately, the behaviour can't be overridden.

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

#5


1  

There is a great suggestion using reflection in the MSDN forums

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

#6


0  

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)执行此操作,以便您可以对您的发行版或生产版本进行适当的检查并将其删除,其中密钥足够强大。

#7


-1  

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上的Key之前立即使用它:

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.

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

#8


-1  

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. 大小必须是16或24字节(???)为什么他们不能把它放在文档中

  3. The code check for few simple repetitions Just create random enuogh values
  4. 代码检查几个简单的重复只是创建随机enuogh值

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