12

.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 のハッキングに関する非常に優れた情報が含まれています。残念ながら、この手法を使用して問題を解決することはできませんでしたが、興味深い読み物がまだいくつかあります。

4

8 に答える 8

6

あまりお勧めしませんが、 Reflectorと Add-in ReflexILを使用して弱いキーをチェックする 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\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

ここで何かが足りないと思います:)これをもう少し調査します。

編集4:

IsWeakKey のすべてにパッチを適用し、「ngen.exe」を使用して mscorlib.dll の新しいネイティブ イメージ (x. ni .dll) を削除および生成して遊んだ後でも、同じ例外が発生します。ネイティブの mscorlib イメージをアンインストールした後でも、まだ mscorlib.ni.dll を使用していることに注意してください。

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

于 2009-04-13T17:16:13.923 に答える
4

私はあなたが何をする必要があるかを知りました。幸いなことに、弱いキーをチェックしない ICryptoTranforms を作成する方法があります。健全性チェックも行うため、基本クラスにも注意する必要があります。リフレクションを介して _NewEncryptor メソッドを呼び出すだけです (もう少しリフレクションを行う必要がありますが、それがアイデアです)。

幸いなことに、MACTripleDES には TripleDES 型のフィールドがあるため、MACTripleDES から派生させ、コンストラクターでのリフレクションを介して置き換えます。私はあなたのためにすべての仕事をしました。

正しい MAC が生成されていることを確認できませんが、例外はスローされません。さらに、コードにドキュメントコメントを付けて例外処理を行いたい場合があります (リフレクションの失敗 - フィールド/メソッドが存在しない場合など) - しかし、これは 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);
        }
    }
}
于 2009-04-14T20:58:22.023 に答える
1

MSDN フォーラムには、リフレクションを使用する優れた提案があります。

于 2009-08-14T10:14:32.260 に答える
1

単一の DES CBC-MAC を偽造するために DES キーを繰り返し使用して MACTripleDES を使用する代わりに、 DESCryptoServiceProviderの上に CBC-MAC を自分で実装することができます。

<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;
    }
于 2009-04-14T13:58:57.710 に答える
1

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

于 2009-04-13T17:11:35.167 に答える
0

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

于 2009-04-13T18:47:23.703 に答える
-1

リフレクション ベースのソリューションで問題を回避できますが、それらは汚くて邪悪です。非常に便利な方法についてはまだ誰も言及していません。TripleDES.IsWeakKey

私はこの問題を抱えており、CryptoServiceProvider にキーを設定する直前に使用する非常に単純なユーティリティで解決しました。

private void MakeSecureKey(byte[] key)
{
    while(TripleDES.IsWeakKey(key))
    {
        var sha = SHA256Managed.Create().ComputeHash(key);
        Array.Copy(sha,key,key.Length);
    }
}

暗号化または復号化を作成するときにいつでも呼び出すと、クラッシュが防止され、常に安全なキーが提供されます。

于 2011-11-29T17:01:05.713 に答える
-1

非常に単純です(GitHubのコードを見た後)

static bool TripleDES.IsWeakKey(Byte[] rgbKey)

静的であるため、鍵を簡単にテストできます

  1. サイズは 16 バイトまたは 24 バイトでなければなりません (???) ドキュメントに記載できないのはなぜですか
  2. いくつかの単純な繰り返しのコードチェック ランダムな十分な値を作成するだけ

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

デケル

于 2013-08-20T08:43:22.043 に答える