Tripledes : 지정된 키는 '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 : 아래의 Daniel의 답변은 .NET 해킹에 대한 아주 좋은 정보가 있습니다. 불행히도, 나는이 기술을 사용하여 내 문제를 해결할 수 없었지만 여전히 흥미로운 독서가 있습니다.

도움이 되었습니까?

해결책

단일 DES CBC-MAC를 가짜로 반복하기 위해 DES 키와 함께 MacTripledes를 사용하는 대신 CBC-Mac을 직접 구현할 수 있습니다. descryptoserviceprovider.

<11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 미오까지는 약한 키가 아닙니다.

이것은 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 코드를 수정할 수 있어야합니다. 반사기 그리고 추가 기능 반사

편집하다:

죄송합니다. 가상 머신 (Ubuntu 실행)에 모든 것을로드하는 데 시간이 걸렸으며 Mono를 엉망으로 만들고 싶지 않았습니다.

  • Reflexil Add -In 설치 :보기 -> 추가 인 -> 추가
  • 개방 반사 : 도구 -> 반사 v0.9
  • isweakkey () 함수를 찾으십시오. (검색을 사용할 수 있습니다 : F3)
  • 두 가지 기능이 나타나고 System.security.cryptography.tripledes에서 찾은 기능을 Doubleclick합니다.
  • Reflexil도 나왔을 것입니다. 지침 탭에서 29 행까지 스크롤하십시오 (오프셋 63).
  • ldc.i4.1을 ldc.i4.0으로 변경하면 함수가 항상 false를 반환한다는 것을 의미합니다.

어셈블리 창 (왼쪽)에서 이제 위로 스크롤하여 "공통 언어 런타임 라이브러리"를 클릭 할 수 있습니다. Reflexil 창은 저장 옵션을 제공합니다.

중요한 메모 :

  • 원래 어셈블리를 먼저 백업하십시오! (mscorlib.dll)
  • mscorlib.dll은 서명 된 어셈블리이며, 검증을 건너 뛰기 위해서는 .net sdk (sn.exe 도구)가 필요합니다. 방금 이것을 직접 확인했습니다. 이미 시각적 C#을 설치하여 이것을 가져야합니다. 요청할 때 "검증 건너 뛰기 (이 컴퓨터에서)"를 클릭하십시오.
  • 나는 당신의 개발 기계에서만 이것을 사용하라고 말해야한다고 생각하지 않습니다. :)

행운을 빕니다! 추가 지침이 필요한 경우 댓글 상자를 자유롭게 사용하십시오.

edit2 :

나는 혼란스러워!

Mscorlib 어셈블리의 Set_key 함수에서 Isweakkey 검사를 완전히 제거했습니다. 올바른 기능을 수정했으며 올바르게 수행했다고 확신합니다. 반사판의 분해기는 더 이상 점검을 표시하지 않습니다. 그러나 재미있는 것은 시각적 C#이 여전히 동일한 예외를 던지는 것입니다.

이것은 Mscorlib가 어딘가에 어딘가에 캐시되어야한다고 믿게합니다. 그러나 mscorlib.dll을 mscorlib.dll_로 바꾸면 msvc#을 충돌시켜 원래 DLL에 의존해야합니다.

이것은 매우 흥미로운 것들이지만, 나는 무슨 일이 일어나고 있는지 전혀 모르는 지점에 도달했다고 생각합니다. 첨부 된 이미지를 참조하십시오. :(

edit3 :

나는 Olly에서 Mscoree, MSCorsec 및 MSCorwks와 같은 어셈블리와 달리; mscorlib.dll은 실제로 다음에 없습니다 : c : windows microsoft.net framework v2.0.50727

대신, 존재하지 않는 위치 : C : Windows Assembly aventiams_v2.0.50727_32 mscorlib 6d667f19d687361886990f3ca0f49816 mscorlib.ni.dll

나는 여기서 뭔가를 놓치고 있다고 생각합니다 :) 이것을 더 조사 할 것입니다.

edit4 :

Isweakkey의 모든 것을 패치 한 후에도 새로운 기본 이미지를 제거하고 생성하는 데 모두 놀았습니다 (x.NI"ngen.exe"를 사용하여 mscorlib.dll의 .dll). 나는 기본 mscorlib 이미지를 제거한 후에도 여전히 mscorlib.ni.dll ... meh를 사용하고 있음을 주목해야합니다.

나는 포기한다. 나는 누군가가 모르기 때문에 도대체 무슨 일이 일어나고 있는지 대답 할 수 있기를 바랍니다. :)

나는 당신이해야 할 일을 알았습니다. 다행히도 약한 키를 확인하지 않는 Icryptotranforms를 생성하는 방법이 있습니다. 또한 기본 클래스도 정신 점검을 수행하므로 조심해야합니다. 반사를 통해 단순히 _newencryptor 방법을 불러냅니다 (조금 더 반사해야하지만 그것이 아이디어입니다).

운 좋게도 MacTripledes에는 Triple Tripledes 필드가 있으므로 Mactripledes에서 파생되어 생성자의 반사를 통해 교체하십시오. 나는 당신을 위해 모든 일을했습니다.

올바른 Mac이 생성되었는지 확인할 수는 없지만 예외는 발생하지 않습니다. 또한 코드를 문의하고 예외 처리 (반사 실패 - 필드/메소드가없는 경우) - 그러나 이것은 그렇습니다. 그래서 나는 귀찮게하지 않았다.

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

불행히도 행동은 무시할 수 없습니다.

사용하는 훌륭한 제안이 있습니다 반사 MSDN 포럼에서

나는 보안 전문가는 아니지만 다른 가치로 키를 XCONIT하지 않을 것입니까? 디버그 버전 (적절한 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의 코드를 본 후)

정적 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