トリプルDES:指定されたキーは「TripleDES」の既知の弱いキーであるため、使用できません

StackOverflow https://stackoverflow.com/questions/744530

質問

.NET 3.0クラスを使用しています System.Security.Cryptography.MACTripleDES MAC 値を生成するクラス。残念ながら、私は「」を使用するハードウェア デバイスを使用しています。1111111111111111" (16 進数として) 単一長の 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:以下のダニエルの回答には、.NET のハッキングに関する非常に良い情報が含まれています。残念ながら、この手法を使用して問題を解決することはできませんでしたが、それでも興味深い読み物がいくつかあります。

役に立ちましたか?

解決

代わりに偽のシングルDES CBC-MACに繰り返さDESキーでMACTripleDESを使用しての

、あなただけの<のhref = "http://msdn.microsoft.com/en-usの上にCBC-MACを自分で実装することができ/library/system.security.cryptography.descryptoserviceprovider.aspx」のrel = "nofollowをnoreferrer"> DESCryptoServiceProvider を。

<1111111111111111>弱い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;
    }

他のヒント

あまりお勧めしませんが、弱いキーをチェックする IL コードを次のように変更できるはずです。 リフレクター そしてアドイン リフレックスIL

編集:

申し訳ありませんが、仮想マシン (Ubuntu を実行) にすべてをロードするのに時間がかかり、Mono をいじりたくありませんでした。

  • ReflexIL アドインをインストールします。表示 -> アドイン -> 追加
  • ReflexIL を開く:ツール -> ReflexIL v0.9
  • IsWeakKey() 関数を見つけます。(検索を使用できます:F3)
  • 2 つの関数が表示されるので、System.Security.Cryptography.TripleDES にある関数をダブルクリックします。
  • ReflexIL も登場しているはずです。[手順] タブで、29 行目 (オフセット 63) までスクロールします。
  • ldc.i4.1 を ldc.i4.0 に変更します。これは、関数が常に false を返すことを意味します。

アセンブリ ペイン (左側) で、上にスクロールして [共通言語ランタイム ライブラリ] をクリックすると、ReflexIL ペインに保存するオプションが表示されます。

重要な注意事項:

  • まず元のアセンブリをバックアップしてください。(mscorlib.dll)
  • mscorlib.dll は署名付きアセンブリであり、検証をスキップするには ReflexIL の .NET SDK (sn.exe ツール) が必要です。これは私自身で確認したところですが、Visual C# がインストールされているとすでにインストールされているはずです。求められたら、「(このコンピュータ上で)検証スキップ用に登録する」をクリックするだけです。
  • これを開発マシンでのみ使用するように言う必要はないと思います:)

幸運を!追加の手順が必要な場合は、お気軽にコメントボックスをご利用ください。

編集2:

私は混乱しています!

mscorlib アセンブリの set_Key 関数から IsWeakKey チェックを完全に削除しました。私は正しい関数を変更し、正しく実行したと確信しています。Reflector の逆アセンブラではチェックが表示されなくなりました。ただし、面白いことに、Visual C# は依然として同じ例外をスローします。

このため、mscorlib が何らかの方法でまだどこかにキャッシュされているに違いないと私は考えています。ただし、mscorlib.dll の名前を mscorlib.dll_ に変更すると MSVC# がクラッシュするため、元の DLL に依存したままにする必要があります。

これは非常に興味深い内容ですが、何が起こっているのか見当もつかない、まったく意味がわからないというところまで来ていると思います。添付の画像を参照してください。:(

編集3:

Olly では、mscoree、mscorsec、mscorwks などのアセンブリとは異なることに気付きました。mscorlib.dll は実際には次の場所にありません。c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\

しかし代わりに、存在しないように見える場所で:C:\WINDOWS\assembly ativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

ここで何かが欠けていると思います:) これをもう少し調査します。

編集4:

IsWeakKey のすべてにパッチを適用し、新しいネイティブ イメージの削除と生成の両方を試した後でも (x..dll) の mscorlib.dll を「ngen.exe」を使用して実行すると、同じ例外が発生します。ネイティブ mscorlib イメージをアンインストールした後でも、依然として mscorlib.ni.dll が使用されていることに注意する必要があります。うーん。

私はあきらめます。私には本当に何が起こっているのかわからないので、誰かが答えてくれることを願っています。:)

私はあなたが何をする必要があるかが分かりました。幸いなことに、弱いキーをチェックしません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);
        }
    }
}

残念ながら、動作をオーバーライドすることはできません。

<のhref = "http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8fdfcce7-3a8a-4271-8557-3df715c80df8" のrel = "nofollowをを使用して偉大な提案がありますnoreferrer "> MSDNフォーラムで反射する

私はセキュリティの専門家ではないが、健全性チェックを満たすには十分では別の値を使用してキーをXORはないでしょうか?あなたは(適切なIFDEFで)あなたのデバッグバージョンのためにこれを行うことができますので、あなたが適切なチェックを行うと、キーは十分に強いだろう、あなたのリリースや製品版のためにそれを削除することができます。

リフレクションベースのソリューションは、あなたが問題を回避するが、彼らは汚いと悪です。まだ誰も非常に有用な方法を言及していない:TripleDES.IsWeakKey

私はこの問題を抱えていたと私は私のCryptoServiceProvider上のキーを設定する前に、私はすぐに使用し、非常に簡単なユーティリティでそれを解決した。

private void MakeSecureKey(byte[] key)
{
    while(TripleDES.IsWeakKey(key))
    {
        var sha = SHA256Managed.Create().ComputeHash(key);
        Array.Copy(sha,key,key.Length);
    }
}
あなたが暗号化や復号化を行ういつでもそれを呼び出す場合は、

、それはクラッシュを防ぎ、常にあなたに安全な鍵を与える必要があります。

非常に単純です (GitHub からコードを確認した後)

static bool TripleDES.IsWeakKey(Byte[] rgbKey)

静的であるため、キーをそれに対してテストするのは簡単です

  1. サイズは16バイトまたは24バイトでなければなりません(???)なぜ彼らはそれをドキュメントに入れることができないのですか
  2. コードチェックは、ランダムなeNuogh値を作成するだけで、コードチェック

次のコードを参照してください。 https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

デケル

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top