TripleDES: Specified key is a known weak key for 'TripleDES' and cannot be used
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.
<1111111111111111> is not a weak DES key.
This will calculate a 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;
}
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
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.
- 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.
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.
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 :)
Good luck! If you need additional instructions, please feel free to use the commentbox.
edit2:
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.
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.
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\
But instead, in what appears to be a non-existent location: 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.
I give up. I hope someone will be able to answer what the hell is going on because I sure don't know. :)
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).
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.
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.
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);
}
}
}