4

Why does this code return the weak key error?

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;
}

When I try to execute the line "tdes.Key = key", I get the error

deriveSessionKeyIS System.Security.Cryptography.CryptographicException: Specified key is a known weak key for TripleDES and cannot be used

Why? The key I'm trying is random, but one of the tested keys, for example, is FB13347FE570DC4FFB13347FE570DC4F. Where is the problem?

Piero Alberto
  • 3,823
  • 6
  • 56
  • 108

3 Answers3

5

You can read in wikipedia for example about what is the weak key in cryptography. For triple DES there is a method (TripleDES.IsWeakKey) which checks triple DES key for weakness. In you case, key FB13347FE570DC4FFB13347FE570DC4F is symmetric in a sense that first 8 bytes of it are exactly equal last 8 bytes. That means if you encrypt something with that key, and then encrypt that encrypted info one more time - you will restore original text (because of how this concrete encryption algorithm works), which is obviously dangerous.

So in short .NET protects you from doing dangerous things resulting in cryptographic weakness. If you will use standard GenerateKey() function to generate key (or just don't set Key explicitly) - weak keys won't be generated.

A bit more information about why that key is weak for triple DES. 3DES is named like this because it essentially uses 3 keys and applies pure DES encryption\decryption with those keys 3 times. Each key is 8 bytes long, so 3DES key size is 8*3 = 24 bytes. However, algorithm also allows for first and third keys to be the same, and as such allows to use 16-byte keys (like in your example). In that case first half of those 16-bytes are used as a third key. This option provides less security but is still viable.

Now, when in your case first half and second half of your 16-bytes key are the same, so all three keys which will be used by 3DES are the same. Given that 3DES works like this:

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

You see that in your case you fall back to using simple DES, which defeats whole purpose of using 3DES in the first place.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • In what sense using 16-byte key is not covered? – Evk May 31 '16 at 12:17
  • A 3DES key is 24-bytes. – zaph May 31 '16 at 12:19
  • I've extended my answer a bit. – Evk May 31 '16 at 12:34
  • Great but the answer is not complete. One key element is that the particular function (`TDESDecrypt`) supplied the repeated bytes, not all 3DES implementations do that. Also a 3DES key that repeats the first 8-bytes is only weak in that the encryption reverts to DES with a 8-byte (56-bit) key. The wikipedia is weak WRT repeated 8-byte sections. Using repeated sections was common about 10 years ago for a compatibility mode, that may be where this comes from. – zaph May 31 '16 at 13:04
  • Encryption twice with a repeating key the same 8-bytes for all three encryptions, does not decrypt the data. Consider encryption with `ede` followed be a second invocation of `ede`, that encrypts twice with a 8-byte key `edeede` resulting in `ee` encryption . Thus that part of the answer is still incorrect. If indeed DES encryption is identical to decryption please provide a reference because I am ignorant of that. – zaph May 31 '16 at 13:13
  • Well you are definetly more advanced in cryptography than I am, but that is what stated in documentation of IsWeakKey function (link to it is in my answer): "If text is encrypted with a weak key, encrypting the resulting cipher again with the same weak key returns the original text". – Evk May 31 '16 at 13:22
  • That is WRT DES weak keys, not repeated DES strong keys repeated in 3DES. Note: When banking was moving to 3DES from DES the DES algorithms were updated to 3DES and by repeating DES keys 3 times as a migration and everything still worked. Eventually the move was fully made to using 3DES keys. – zaph May 31 '16 at 13:35
1

It is a weak 3DES key because the additional 8-byte will again be repeated as the last 8-bits. Thus the 3DES encryption has reverted to DES and that is weak.

3DES does three operations, in the most common form of ede the data is first encrypted with the first 8-bytes of the key, then decrypted with the second 8-bytes and finally encrypted with the final 8-bytes (which in this case are the first 8-bytes). Note that after the first two operations the data is back to the original data thus the only encryption that is actually performed is the last encryption and that is 8-bytes which is a 56-bit key. That is a weak 3DES key.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    In [Keying Option 2 (Sec. 3.2)](http://csrc.nist.gov/publications/nistpubs/800-67-Rev1/SP-800-67-Rev1.pdf) K3 is copied from K1. For reference the [code of IsWeakKey](http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/tripledes.cs,362322fbcfdb6230,references) actually checks whether K1 and K2 are equal in case of Keying Option 2. – Artjom B. May 31 '16 at 14:17
  • Thanks for digging up the references. – zaph May 31 '16 at 14:28
0

I found this solution on MSDN Forum. This solution works perfectly with weak keys.

With the code from the forum I made 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
}