TripleDES: указанный ключ является известным слабым ключом для TripleDES и не может использоваться - PullRequest
12 голосов
/ 13 апреля 2009

Я использую класс .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: Ответ Даниэля ниже содержит очень хорошую информацию о взломе .NET. К сожалению, я не смог решить свою проблему, используя эту технику, но там все еще есть некоторые интересные материалы.

Ответы [ 8 ]

6 голосов
/ 13 апреля 2009

Я бы не советовал, но вы сможете изменить IL-код, который проверяет наличие слабых ключей, используя Reflector и надстройку ReflexIL

редактирование:

Извините, мне потребовалось некоторое время, чтобы загрузить все это на мою виртуальную машину (под управлением Ubuntu), и я не хотел связываться с Mono.

  • Установка надстройки ReflexIL: Просмотр -> Надстройки -> Добавить
  • Открыть ReflexIL: Инструменты -> ReflexIL v0.9
  • Найдите функцию IsWeakKey (). (Вы можете использовать Поиск: F3)
  • Появятся две функции, дважды щелкните ту, которая найдена в System.Security.Cryptography.TripleDES
  • ReflexIL тоже должен был появиться. На вкладке «Инструкции» выполните прокрутку до строки 29 (смещение 63).
  • Измените ldc.i4.1 на ldc.i4.0, это означает, что функция всегда будет возвращать false.

На панели сборок (слева) теперь можно прокрутить вверх и щелкнуть «Common Language Runtime Library», панель ReflexIL даст вам возможность сохранить ее.

Важные примечания:

  • Сначала создайте резервную копию вашей оригинальной сборки! (Mscorlib.dll)
  • mscorlib.dll является подписанной сборкой, и вам потребуется .NET SDK (инструмент sn.exe) для ReflexIL, чтобы пропустить проверку. Я только что проверил это сам, у вас уже должно быть это с установленным Visual C #. Просто нажмите «Зарегистрировать для пропуска проверки (на этом компьютере)», когда вас попросят.
  • Не думаю, что я должен говорить вам использовать это только на вашей машине разработки:)

Удачи! Если вам нужны дополнительные инструкции, пожалуйста, не стесняйтесь использовать поле для комментариев.

edit2:

Я в замешательстве!

http://i44.tinypic.com/2r6fwbo_th.png

Я полностью удалил проверку IsWeakKey из функции set_Key в сборке mscorlib. Я абсолютно уверен, что я изменил правильную функцию, и что я сделал это правильно. Дизассемблер рефлектора больше не показывает чек. Самое смешное, что Visual C # по-прежнему вызывает то же исключение.

Это наводит меня на мысль, что mscorlib каким-то образом все еще нужно где-то кэшировать. Однако переименование mscorlib.dll в mscorlib.dll_ приводит к сбою MSVC #, поэтому он все равно должен зависеть от исходного dll.

Это довольно интересный материал, но я думаю, что дошел до того, что я понятия не имею, что происходит, просто это не имеет никакого смысла! Смотрите прикрепленное изображение. : (

Edit3:

Я замечаю в Олли, что в отличие от таких сборок, как mscoree, mscorsec и mscorwks; mscorlib.dll фактически не находится в: C: \ WINDOWS \ Microsoft.NET \ Framework \ v2.0.50727 \

Но вместо этого в том, что кажется несуществующим местоположением: C: \ WINDOWS \ сборка \ NativeImages_v2.0.50727_32 \ mscorlib \ 6d667f19d687361886990f3ca0f49816 \ mscorlib.ni.dll

Я думаю, что я что-то здесь упускаю :) Исследую это еще немного.

edit4:

Даже после того, как я пропатчил ВСЕ в IsWeakKey и поиграл с удалением и генерацией новых собственных образов (x. ni .dll) mscorlib.dll с помощью «ngen.exe», я получаю такое же исключение. Я должен отметить, что даже после удаления собственных образов mscorlib он все еще использует файл mscorlib.ni.dll ... Meh.

Я сдаюсь. Я надеюсь, что кто-то сможет ответить, что, черт возьми, происходит, потому что я точно не знаю. :)

4 голосов
/ 15 апреля 2009

Я узнал, что тебе нужно делать. К счастью, есть метод, который создает 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);
        }
    }
}
1 голос
/ 14 августа 2009

На форумах MSDN

есть отличное предложение использовать отражение
1 голос
/ 14 апреля 2009

Вместо использования MACTripleDES с повторяющейся клавишей DES для подделки одного DES-CBC-MAC, вы можете просто реализовать CBC-MAC самостоятельно поверх 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;
    }
1 голос
/ 13 апреля 2009

К сожалению, поведение не может быть переопределено.

0 голосов
/ 20 августа 2013

Довольно просто (после просмотра кода из GitHub)

статическое bool TripleDES.IsWeakKey (Byte [] rgbKey)

Поскольку он статичен, его легко проверить с помощью ключа

  1. Размер должен быть 16 или 24 байта (???) Почему они не могут поместить это в документацию
  2. Проверка кода для нескольких простых повторений Просто создайте случайные значения

См. Код по адресу: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

Dekel

0 голосов
/ 29 ноября 2011

Решения, основанные на отражении, помогут вам решить проблему, но они грязные и злые. Еще никто не упомянул очень полезный метод: TripleDES.IsWeakKey

У меня возникла эта проблема, и я решил ее с помощью очень простой утилиты, которую я использую непосредственно перед установкой Ключа на моем CryptoServiceProvider:

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

Если вы вызываете его в любое время, когда создаете шифратор или дешифровщик, это должно предотвратить сбой и всегда дает вам безопасный ключ.

0 голосов
/ 13 апреля 2009

Я не эксперт по безопасности, но не будет ли XOR вашего ключа с другим значением достаточно для проверки работоспособности? Вы можете сделать это для своей отладочной версии (с надлежащим IFDEF), чтобы вы могли выполнить надлежащую проверку и удалить ее для своей версии или рабочей версии, где ключ будет достаточно сильным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...