TripleDES :La clé spécifiée est une clé faible connue pour « TripleDES » et ne peut pas être utilisée

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

Question

J'utilise la classe .NET 3.0 System.Security.Cryptography.MACTripleDES classe pour générer une valeur MAC.Malheureusement, je travaille avec un périphérique matériel qui utilise "1111111111111111" (en hexadécimal) comme clé DES d'une seule longueur.Le System.Security.Cryptography La bibliothèque effectue une vérification d'intégrité de la clé et renvoie une exception si vous essayez d'utiliser une clé cryptographiquement faible.

Par exemple:

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

lève une exception

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

Je sais que ce n'est pas une clé sécurisée.En production, l’appareil sera flashé avec une nouvelle clé sécurisée.En attendant, existe-t-il un moyen d'empêcher la levée de cette exception ?Peut-être un app.config ou paramètre de registre ?

Modifier:La clé serait en fait 101010...en raison de l'algorithme forçant la parité impaire.Je ne sais pas si cela est universel pour l'algorithme DES ou simplement une exigence dans le travail de traitement des paiements que j'effectue.

Modifier 2 :La réponse de Daniel ci-dessous contient de très bonnes informations sur le piratage de .NET.Malheureusement, je n'ai pas pu résoudre mon problème en utilisant cette technique, mais il y a quand même des lectures intéressantes.

Était-ce utile?

La solution

Au lieu d'utiliser MACTripleDES avec la clé DES répétée à un faux-MAC DES CBC, vous pouvez simplement mettre en œuvre vous CBC-MAC au-dessus de DESCryptoServiceProvider .

<1111111111111111> est pas une faible clé DES.

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

Autres conseils

Je ne le recommanderais pas vraiment, mais vous devriez pouvoir modifier le code IL qui vérifie les clés faibles en utilisant Réflecteur et le complément RéflexIL

modifier:

Désolé, il m'a fallu un certain temps pour tout charger sur ma machine virtuelle (exécutant Ubuntu) et je ne voulais pas jouer avec Mono.

  • Installez le complément ReflexIL :Affichage -> Compléments -> Ajouter
  • Ouvrez ReflexIL :Outils -> ReflexIL v0.9
  • Recherchez la fonction IsWeakKey().(Vous pouvez utiliser la recherche :F3)
  • Deux fonctions apparaîtront, double-cliquez sur celle trouvée dans System.Security.Cryptography.TripleDES
  • ReflexIL aurait dû apparaître aussi.Dans l’onglet Instructions, faites défiler jusqu’à la ligne 29 (décalage 63).
  • Remplacez ldc.i4.1 par ldc.i4.0, cela signifie que la fonction retournera toujours false.

Dans le volet de vos assemblys (celui de gauche), vous pouvez maintenant faire défiler vers le haut et cliquer sur "Common Language Runtime Library", le volet ReflexIL vous donnera la possibilité de l'enregistrer.

Notes IMPORTANTES:

  • SAUVEGARDEZ d'abord votre assemblage d'origine !(mscorlib.dll)
  • mscorlib.dll est un assembly signé et vous aurez besoin du SDK .NET (outil sn.exe) pour ReflexIL afin qu'il ignore la vérification.Je viens de vérifier cela moi-même, vous devriez déjà l'avoir avec Visual C# installé.Cliquez simplement sur « Enregistrez-le pour ignorer la vérification (sur cet ordinateur) » lorsque vous y êtes invité.
  • Je ne pense pas devoir vous dire de l'utiliser uniquement sur votre machine de développement :)

Bonne chance!Si vous avez besoin d'instructions supplémentaires, n'hésitez pas à utiliser la zone de commentaires.

edit2 :

Je suis confus!

J'ai complètement supprimé la vérification IsWeakKey de la fonction set_Key dans l'assembly mscorlib.Je suis absolument certain d'avoir modifié la bonne fonction et de l'avoir fait correctement.Le désassembleur du réflecteur n'affiche plus le contrôle.Ce qui est drôle, c'est que Visual C# renvoie toujours la même exception.

Cela m'amène à croire que mscorlib doit toujours être mis en cache quelque part.Cependant, renommer mscorlib.dll en mscorlib.dll_ entraîne le crash de MSVC#, il doit donc toujours dépendre de la DLL d'origine.

C'est un truc assez intéressant, mais je pense que j'ai atteint le point où je n'ai aucune idée de ce qui se passe, ça n'a tout simplement aucun sens !Voir l'image ci-jointe.:(

edit3 :

Je remarque dans Olly que contrairement aux assemblys tels que mscoree, mscorsec et mscorwks ;mscorlib.dll ne se trouve pas réellement dans :c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\

Mais au lieu de cela, dans ce qui semble être un endroit inexistant :C:\WINDOWS\assembly ativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll

Je pense qu'il me manque quelque chose ici :) Je vais enquêter davantage sur cela.

modifier4 :

Même après avoir TOUT corrigé dans IsWeakKey et joué avec la suppression et la génération de nouvelles images natives (x.ni.dll) de mscorlib.dll en utilisant "ngen.exe", j'obtiens la même exception.Je dois noter que même après avoir désinstallé les images mscorlib natives, il utilise toujours mscorlib.ni.dll...Meh.

J'abandonne.J'espère que quelqu'un pourra répondre à ce qui se passe parce que je ne sais certainement pas.:)

J'ai trouvé ce que vous devez faire. Heureusement, il existe une méthode qui est disponible qui crée les ICryptoTranforms qui ne vérifie pas les clés faibles. Vous devez également faire attention à la classe de base comme il le fait également des contrôles de santé mentale. Via la réflexion appelez simplement la méthode _NewEncryptor (vous devez faire un peu plus de réflexion, mais c'est l'idée).

Heureusement, le MACTripleDES possède un champ de type TripleDES, de sorte dérivent de MACTripleDES et de le remplacer par réflexion dans les constructeurs. Je l'ai fait tout le travail pour vous.

Je ne peux pas vérifier que le bon MAC est généré, mais sans exception sont jetés. De plus, vous pouvez commenter doc le code et faire la gestion des exceptions (échecs de réflexion - par exemple si les champs / méthodes ne sont pas là) - mais il en est ainsi; donc je ne l'ai pas pris la peine.

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

Malheureusement, le comportement ne peut pas être surchargée.

Il y a une grande suggestion en utilisant réflexion dans les forums MSDN

Je ne suis pas un expert en sécurité, mais ne XOR votre clé avec une autre valeur suffisante pour satisfaire la vérification de la santé mentale? Vous pouvez le faire pour votre version de débogage (avec IFDEF approprié) afin que vous puissiez faire une vérification correcte et retirez-le pour votre version ou une version de production où la clé serait assez forte.

Les solutions de réflexion vous contourner le problème, mais ils sont sales et le mal. Personne n'a encore parlé d'une méthode très utile: TripleDES.IsWeakKey

Je l'ai eu ce problème et résolu avec un utilitaire très simple que je l'utilise immédiatement avant que je définir la clé de mon CryptoServiceProvider:

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

Si vous appelez quand vous faites un chiffreur ou décrypteur, il faut éviter l'accident et vous donner toujours une clé sécurisée.

Assez simple (Après avoir regardé le code de GitHub)

bool TripleDES.IsWeakKey statique (byte [] rgbKey)

Comme il est statique - il est facile de tester votre clé contre

  1. La taille doit être 16 ou 24 octets (???) Pourquoi ne peuvent-ils le mettre dans la documentation
  2. Le contrôle de code pour quelques répétitions simples Il suffit de créer des valeurs de enuogh aléatoires

Voir le code à: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

Dekel

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top