为什么此代码会返回弱密钥错误?
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 。问题在哪里?
答案 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
}