我正在使用.NET 3.0类System.Security.Cryptography.MACTripleDES
类来生成MAC值。不幸的是,我正在使用一个使用“1111111111111111
”(作为十六进制)作为单长DES密钥的硬件设备。 System.Security.Cryptography
库会对密钥进行一些健全性检查,如果您尝试使用加密弱密钥,则会返回异常。
例如:
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.
我知道这不是一个安全的密钥。在生产中,设备将使用新的安全密钥进行闪存。同时,有没有办法抑制这个异常被抛出?可能是app.config
或注册表设置?
编辑:密钥实际上是101010 ...由于算法强制奇校验。我不确定这是DES算法的通用性,还是我支付处理工作的要求。
编辑2:Daniel的答案下面有一些关于黑客攻击.NET的非常好的信息。不幸的是,我无法使用这种技术解决我的问题,但仍然有一些有趣的阅读。
答案 0 :(得分:6)
我不会真的推荐它,但您应该能够使用Reflector和加载项ReflexIL
修改检查弱密钥的IL代码编辑:
抱歉,我需要一段时间才能在我的虚拟机(运行Ubuntu)中加载所有内容并且不想搞乱Mono。
在程序集窗格(左侧)中,您现在可以向上滚动并单击“公共语言运行库”,ReflexIL窗格将为您提供保存选项。
重要说明:
EDIT2:
我很困惑!
http://i44.tinypic.com/2r6fwbo_th.png
我从mscorlib程序集中的set_Key函数中完全删除了IsWeakKey检查。我绝对肯定我修改了正确的功能,并且我做得正确。 Reflector的反汇编程序不再显示检查。然而,有趣的是,Visual C#仍然会引发相同的异常。
这让我相信mscorlib必须以某种方式仍然在某处缓存。但是,将mscorlib.dll重命名为mscorlib.dll_会导致MSVC#崩溃,因此它仍必须依赖于原始dll。
这是非常有趣的东西,但我想我已经达到了一点,我不知道发生了什么,它只是没有任何意义!见附图。 :(
EDIT3:
我在Olly注意到,与mscoree,mscorsec和mscorwks等组件不同; mscorlib.dll实际上并不位于: C:\ Windows \ Microsoft.NET \框架\ V2.0.50727 \
但相反,似乎是一个不存在的位置: C:\ Windows \组件\ NativeImages_v2.0.50727_32 \ mscorlib程序\ 6d667f19d687361886990f3ca0f49816 \ mscorlib.ni.dll
我想我在这里遗漏了一些东西:)将对此进行更多调查。
edit4:
即使在IsWeakKey中修复了所有内容,并使用“ngen.exe”删除并生成mscorlib.dll的新本机图像(x。 ni .dll),我也是得到同样的例外。我必须注意,即使在卸载本机mscorlib映像后,它仍然使用mscorlib.ni.dll ... Meh。
我放弃了。我希望有人能够回答到底是怎么回事,因为我肯定不知道。 :)
答案 1 :(得分:4)
我发现了你需要做的事情。幸运的是,有一种方法可用于创建不检查弱键的ICryptoTranforms。您还需要注意基类,因为它也会进行健全性检查。通过反射简单地调出_NewEncryptor方法(你需要做一些反思,但这就是想法)。
幸运的是,MACTripleDES有一个TripleDES类型的字段,因此从MACTripleDES派生并通过构造函数中的反射替换它。我为你完成了所有的工作。
我无法验证是否生成了正确的MAC,但没有抛出异常。此外,您可能希望对代码进行doc注释并进行异常处理(反射失败 - 例如,如果字段/方法不存在) - 但这是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);
}
}
}
答案 2 :(得分:1)
不幸的是,行为无法被覆盖。
答案 3 :(得分:1)
您可以在DESCryptoServiceProvider之上自行实现CBC-MAC,而不是使用重复使用DES密钥的MACTripleDES来伪造单个DES CBC-MAC。
&LT; 1111111111111111&GT;不是一个弱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;
}
答案 4 :(得分:1)
在MSDN论坛中使用reflection提出了一个很好的建议
答案 5 :(得分:0)
我不是安全专家,但不会用另一个值来对你的密钥进行异或,以满足理智检查的要求吗?您可以为您的调试版本(使用正确的IFDEF)执行此操作,以便您可以对您的版本或生产版本进行适当的检查并将其删除,其中密钥足够强大。
答案 6 :(得分:-1)
基于反射的解决方案可以解决问题,但它们是肮脏和邪恶的。还没有人提到一个非常有用的方法: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);
}
}
如果您在创建加密器或解密器时随时调用它,它应该可以防止崩溃并始终为您提供安全密钥。
答案 7 :(得分:-1)
非常简单(查看GitHub中的代码后)
static bool TripleDES.IsWeakKey(Byte [] rgbKey)
因为它是静态的 - 很容易测试你的密钥
请参阅代码:https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs
德克尔