TripleDES:Chiave specificata è un noto debole chiave per 'TripleDES' e non può essere utilizzato

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

Domanda

Sto usando il .NET 3.0 classe System.Security.Cryptography.MACTripleDES classe di generare un valore di MAC.Purtroppo, sto lavorando con un dispositivo hardware che usa "1111111111111111"(hex) come una singola lunghezza chiave DES.Il System.Security.Cryptography libreria po ' di sanità mentale controllo sulla chiave e restituisce un'Eccezione se si tenta di utilizzare una chiave di crittografia debole.

Per esempio:

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

genera un'eccezione

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

So che questa non è una chiave di sicurezza.In produzione, il dispositivo verrà aggiornata con una nuova chiave di sicurezza.Nel frattempo, c'è un modo per inibire questa Eccezione da buttare?Forse un app.config o impostazione del registro di sistema?

Edit:La chiave potrebbe essere effettivamente 101010...a causa dell'algoritmo di forzare parità dispari.Non sono sicuro se questo è universale per l'algoritmo DES o solo un requisito nel pagamento di elaborazione del lavoro che ho fatto.

Edit 2:Daniel risposta ha seguito alcuni molto buono informazioni sull'hacking .NET.Purtroppo, non ero in grado di risolvere il mio problema con questa tecnica, ma c'è ancora qualche lettura interessante lì.

È stato utile?

Soluzione

Invece di usare MACTripleDES con la chiave DES ripetuto di falsificare un singolo DES CBC-MAC, si può solo implementare CBC-MAC te in cima DESCryptoServiceProvider .

<1111111111111111> non è una chiave debole DES.

Questo calcolerà un 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;
    }

Altri suggerimenti

Non vorrei davvero raccomandare esso, ma si dovrebbe essere in grado di modificare il codice che controlla la presenza di chiavi deboli utilizzando Riflettore e l'Add-in ReflexIL

edit:

Mi dispiace, ci sono voluti un po ' per me per caricare il tutto nella mia Macchina Virtuale (Ubuntu) e non si vuole pasticciare con Mono.

  • Installare il ReflexIL Add-in:Visualizza -> componenti aggiuntivi -> Aggiungi
  • Aprire ReflexIL:Strumenti -> ReflexIL v0.9
  • Trovare il IsWeakKey() funzione.(Si può utilizzare Ricerca:F3)
  • Due funzioni di venire, di doubleclick per il Sistema.Di sicurezza.Crittografia.TripleDES
  • ReflexIL dovrebbe venire troppo.Nelle Istruzioni della scheda, scorrere tutta la strada fino alla linea 29 (offset 63).
  • Cambiare ldc.i4.1 di ldc.i4.0, questo significa che la funzione restituisce sempre false.

In assembly riquadro (a sinistra), è ora possibile scorrere verso l'alto e fare clic su "Common Language Runtime Library", il ReflexIL riquadro vi darà una possibilità di salvarlo.

Note importanti:

  • Eseguire il BACKUP originale assieme!(mscorlib.dll)
  • mscorlib.dll è un assembly firmato e sarà necessario il .NET SDK (sn.exe strumento) per ReflexIL per farlo saltare la verifica.Ho appena controllato il manuale, si dovrebbe già avere questo con Visual C# installato.Basta cliccare su "Registra per l'omissione della verifica (su questo computer)" quando gli viene chiesto.
  • Non credo di dire di usare solo questo sul computer di sviluppo :)

Buona fortuna!Se avete bisogno di ulteriori istruzioni, sentitevi liberi di utilizzare il commentbox.

edit2:

Mi sono confuso!

Ho rimosso completamente il IsWeakKey controllare dal set_Key funzione in mscorlib assemblea.Sono assolutamente certo che ho modificato il corretto funzionamento, e che l'ho fatto correttamente.Riflettore del disassembler non visualizza più il controllo.La cosa divertente è, però, che Visual C# ancora butta la stessa eccezione.

Questo mi porta a credere che mscorlib deve in qualche modo essere ancora in cache da qualche parte.Tuttavia, la ridenominazione mscorlib.dll per mscorlib.dll_ porta MSVC# in crash, quindi deve ancora essere dipendenti la dll originale.

Questo è molto interessante, ma credo di aver raggiunto il punto in cui non ho idea di cosa sta succedendo, semplicemente non ha alcun senso!Vedi immagine allegata.:(

edit3:

Ho notato che nella Olly, che, a differenza di gruppi come mscoree, mscorsec e mscorwks;mscorlib.dll non è in realtà si trova in:c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\

Ma, invece, in quello che sembra essere un inesistente posizione:C:\WINDOWS\assembly ativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

Penso che mi manca qualcosa qui :) per indagare ancora un po'.

edit4:

Anche dopo aver patchato il TUTTO in IsWeakKey, e suonato in giro con sia per la rimozione e la generazione di nuove immagini native (x.ni.dll) di mscorlib.dll utilizzando "ngen.exe" io sono sempre la stessa eccezione.Devo essere notato che, anche dopo aver disinstallato il nativo mscorlib immagini, è ancora utilizzando mscorlib.ni.dll...Meh.

Mi arrendo.Spero che qualcuno sarà in grado di rispondere a ciò che il diavolo sta succedendo, perché io di sicuro non lo so.:)

ho scoperto che cosa è necessario fare. Fortunatamente esiste un metodo che disponibile che crea l'ICryptoTranforms che non verifica per le chiavi deboli. È inoltre necessario fare attenzione per la classe di base, come fa anche controlli di integrità. Via riflessione è sufficiente chiamare il metodo _NewEncryptor (è necessario fare un po 'più di riflessione, ma questa è l'idea).

Per fortuna il MACTripleDES ha un campo di tipo TripleDES, quindi derivano da MACTripleDES e sostituirlo attraverso la riflessione nei costruttori. Ho fatto tutto il lavoro per voi.

Non riesco a verificare che il corretto MAC viene generato, ma senza eccezioni sono gettati. Inoltre, si potrebbe desiderare di commento di documentazione del codice e fare gestione delle eccezioni (errori di riflessione - per esempio se i campi / metodi non sono lì) - Ma questo è così; quindi non ho disturbato.

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

Sfortunatamente, il comportamento non può essere ignorata.

C'è una grande suggestione utilizzando riflessione forum MSDN

Io non sono un esperto di sicurezza, ma non uno xor tra la chiave con un altro valore di essere in grado di soddisfare il test di sanità mentale?Si potrebbe fare questo per la tua versione di debug (con la giusta IFDEF) così si può fare un corretto controllo e rimuovere per il rilascio o la versione di produzione in cui la chiave dovrebbe essere abbastanza forte.

Le soluzioni basate riflessione si ottiene intorno al problema, ma sono sporche e il male. Nessuno ha ancora parlato di un metodo molto utile: TripleDES.IsWeakKey

Ho avuto questo problema e risolto con una semplice utility che uso subito prima di impostare la chiave sul mio CryptoServiceProvider:

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

Se si chiama in qualsiasi momento si effettua una criptato o decryptor, si deve evitare che l'incidente e sempre dare una chiave sicura.

Molto semplice (Dopo aver guardato il codice da GitHub)

bool statico TripleDES.IsWeakKey (Byte [] rgbKey)

Dal momento che è statica - è facile per testare la vostra chiave contro di esso

  1. Dimensioni deve essere 16 o 24 byte (???) Perché non possono metterlo nella documentazione
  2. Il controllo codice per poche ripetizioni semplici Basta creare valori enuogh casuali

Vedere il codice in: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

Dekel

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top