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

时间:2016-05-31 09:37:48

标签: c# cryptography key des tripledes

为什么此代码会返回弱密钥错误

static public byte[] TDESDecrypt(byte[] toDecrypt, byte[] key, CipherMode mode = CipherMode.ECB, PaddingMode padding = PaddingMode.None)
{
    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    tdes.Key = key;
    tdes.Mode = mode;
    tdes.Padding = padding;
    ICryptoTransform cTransform = tdes.CreateDecryptor();
    byte[] resultArray = cTransform.TransformFinalBlock(toDecrypt, 0, toDecrypt.Length);
    tdes.Clear();
    return resultArray;
}

当我尝试执行该行" tdes.Key = key"时,我收到错误

  

deriveSessionKeyIS System.Security.Cryptography.CryptographicException :   指定密钥是TripleDES的已知弱密钥,无法使用

为什么呢?我尝试的密钥是随机的,但是其中一个经过测试的密钥是 FB13347FE570DC4FFB13347FE570DC4F 。问题在哪里?

3 个答案:

答案 0 :(得分:3)

您可以在wikipedia中阅读有关密码学中弱密钥的内容。对于三重DES,有一种方法(TripleDES.IsWeakKey)可以检查三重DES密钥的弱点。在你的情况下,密钥FB13347FE570DC4FFB13347FE570DC4F在某种意义上是对称的,它的前8个字节恰好等于最后8个字节。这意味着如果您使用该密钥加密某些内容,然后再次加密该加密信息 - 您将恢复原始文本(因为这种具体的加密算法如何工作),这显然很危险。

因此,简而言之,.NET可以防止您做出危险的事情,从而导致加密漏洞。如果您使用标准GenerateKey()功能生成密钥(或者只是不明确设置Key) - 将无法生成弱密钥。

有关为什么该密钥对于三重DES而言较弱的更多信息。 3DES的命名是这样的,因为它基本上使用了3个密钥,并将这些密钥用于纯DES加密\解密3次。每个密钥长度为8个字节,因此3DES密钥大小为8 * 3 = 24个字节。但是,算法还允许第一个和第三个键相同,因此允许使用16字节键(如您的示例中所示)。在那种情况下,这些16字节的前半部分用作第三个密钥。此选项提供的安全性较低,但仍然可行。

现在,在您的情况下,当您的16字节密钥的前半部分和后半部分相同时,3DES将使用的所有三个密钥都是相同的。鉴于3DES的工作原理如下:

DES encrypt with 3rd(DES Decrypt with 2nd(DES Encrypt with 1st(plaintext)))

你可以看到,在你的情况下,你会回到使用简单的DES,这首先打破了使用3DES的全部目的。

答案 1 :(得分:1)

这是一个弱3DES密钥,因为额外的8字节将再次作为最后的8位重复。因此,3DES加密已经恢复到DES,而且很弱。

3DES执行三项操作,最常见的形式是ede,数据首先用密钥的前8个字节加密,然后用第二个8字节解密,最后用最终的8-加密字节(在本例中是前8个字节)。请注意,在前两个操作之后,数据返回到原始数据,因此实际执行的唯一加密是最后一次加密,即8字节,即56位密钥。这是一个弱3DES密钥。

答案 2 :(得分:0)

我在MSDN论坛上找到了this解决方案。此解决方案与弱键完美配合。

使用论坛中的代码,我做到了:

using System.Security.Cryptography;
using System.IO;
using System.Reflection;

static class MyDES
{
    public static byte[] Encrypt(byte[] data, byte[] key, byte[] IV)
    {
        MemoryStream mStream = new MemoryStream();
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.ECB;
        des.Padding = PaddingMode.None;
        CryptoStream cStream = new CryptoStream(mStream,
            des.CreateWeakEncryptor(key, IV),
            CryptoStreamMode.Write);
        cStream.Write(data, 0, data.Length);
        cStream.FlushFinalBlock();
        byte[] ret = mStream.ToArray();
        cStream.Close();
        mStream.Close();
        return ret;
    }

    public static byte[] Decrypt(byte[] data, byte[] key, byte[] IV)
    {
        MemoryStream msDecrypt = new MemoryStream(data);
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        des.Mode = CipherMode.ECB;
        des.Padding = PaddingMode.None;
        CryptoStream csDecrypt = new CryptoStream(msDecrypt,
            des.CreateWeakDecryptor(key, IV),
            CryptoStreamMode.Read);
        byte[] fromEncrypt = new byte[data.Length];
        csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
        return fromEncrypt;
    }


    #region DESCryptoExtensions
    public static ICryptoTransform CreateWeakEncryptor(this DESCryptoServiceProvider cryptoProvider, byte[] key, byte[] iv)
    {
        MethodInfo mi = cryptoProvider.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
        object[] Par = { key, cryptoProvider.Mode, iv, cryptoProvider.FeedbackSize, 0 };
        ICryptoTransform trans = mi.Invoke(cryptoProvider, Par) as ICryptoTransform;
        return trans;
    }
    public static ICryptoTransform CreateWeakEncryptor(this DESCryptoServiceProvider cryptoProvider)
    {
        return CreateWeakEncryptor(cryptoProvider, cryptoProvider.Key, cryptoProvider.IV);
    }
    public static ICryptoTransform CreateWeakDecryptor(this DESCryptoServiceProvider cryptoProvider, byte[] key, byte[] iv)
    {
        return CreateWeakEncryptor(cryptoProvider, key, iv);
    }
    public static ICryptoTransform CreateWeakDecryptor(this DESCryptoServiceProvider cryptoProvider)
    {
        return CreateWeakDecryptor(cryptoProvider, cryptoProvider.Key, cryptoProvider.IV);
    }
    #endregion
}