1
votes

Chiffrement de texte AES 256 renvoyant des valeurs différentes

J'essaie de reproduire une méthode de chiffrement basée sur une autre méthode C # que j'ai trouvée.

La méthode de chiffrement C # EncryptText (mot, mot de passe ) appel à une autre méthode AES_Encrypt (byte [] bytesToBeEncrypted, byte [] passwordBytes) pour crypter du texte brut:

final static int KEY_SIZE = 256;

Utilisation de word 763059 et mot de passe 515t3ma5m15B4d35 , le résultat est le suivant:

3cHrXxxL1Djv0K2xW4HuCg ==

UPDATE:[

Maintenant, j'ai créé une Class main Java où j'essaye pour reproduire le code précédent:

KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, ITERATIONS, KEY_SIZE);

MISE À JOUR:

J'ai lu sur l'utilisation de clés 256 bits en Java, et j'ai trouvé que Je dois ajouter des extensions de cryptographie Java à autoriser 256 clés ( Parce que je travaille avec JDK7 ).

Ensuite, j'ai ajouté les bibliothèques au projet, aussi je change la ligne:

public class main {

    final static String PASSWORD = "515t3ma5m15B4d35";
    final static byte[] SALT = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
    final static int KEY_SIZE = 256;
    final static int BLOCK_SIZE = 128;
    final static int ITERATIONS = 1000;

    public static void main(String[] args) {
        System.out.println(encryptText("763059", PASSWORD));
    }

    public static String encryptText(String word, String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(password.getBytes("UTF-8"));
            password = new String(md.digest(), "UTF-8");

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec skey = new SecretKeySpec(tmp.getEncoded(), "AES");

            byte[] iv = new byte[BLOCK_SIZE / 8];
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
            ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
            byte[] result = ci.doFinal(word.getBytes("UTF-8"));

            return DatatypeConverter.printBase64Binary(result);

        } catch (NoSuchAlgorithmException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | InvalidKeySpecException ex) {
            return null;
        }
    }

}

Avec la valeur clé:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.IO;
using System.Text;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var f = EncryptText("763059", "515t3ma5m15B4d35");//(word, password)
            Console.WriteLine(f);
        }

        public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
        {
            byte[] encryptedBytes = null;
            byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }
                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }

        public static string EncryptText(string input, string password)
        {
            byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
            string result = Convert.ToBase64String(bytesEncrypted);

            return result;
        }
    }
}

Le résultat est maintenant le suivant:

J1xbKOjIeXbQ9njH + 67RNw ==

Je ne parviens toujours pas à atteindre mon objectif. Une suggestion?


7 commentaires

Peut-être ai-je mal lu, mais n'utilisez-vous pas une clé de 256 bits en c # et une clé de 128 bits en Java?


@JohnWu, Oh, vraiment? Dans quelle partie?


@TimeToCode - probablement AES.KeySize = 256; vs KeySpec spec = new PBEKeySpec (password.toCharArray (), salt, 1000, 128);


Je vous suggère de debug.log les entrées et les sorties de chaque appel cryptographique individuel afin que vous puissiez isoler le problème plus facilement.


Notez que l'utilisation de PBKDF2 avec une sortie plus grande que la taille de hachage (oui, SHA-1 par défaut) n'est pas aussi sûre qu'elle devrait l'être. 1000 est le nombre d'itérations par défaut, mais il est faible. Vous devriez utiliser un sel aléatoire, pas un sel statique - j'espère que c'est juste pour tester des raisons.


Wow, il vous manque complètement la partie où vous avez d'abord SHA-256 le mot de passe (pour une raison inconnue). Essayez-vous même? Voté contre; pourquoi ne pas commencer par faire en sorte que le code Java ressemble au moins au code C #?


Un autre problème est que les données d'un tableau d'octets (le hachage du mot de passe) sont stockées dans un tableau de caractères car PBEKeySpec attend un tableau de caractères. À l'intérieur du fournisseur PBKDF2, le tableau de caractères est reconverti en un tableau d'octets en utilisant le codage UTF-8. L'original (utilisé dans le code C #) et le tableau d'octets reconverti différeront en ce qui concerne les valeurs> = 0x80 (qui sont principalement présentes). Il en résulte des clés et des IV différentes dans les deux codes et donc, dans des données cryptées différentes. Une alternative est PKCS5S2ParametersGenerator de Bouncy Castle pour la génération de clé et IV qui attend un tableau d'octets.


3 Réponses :


0
votes

Je ne suis pas un expert C #, mais il y a quelques points à vérifier:

Lecture de la documentation sur Rfc2898DeriveBytes Je vois que la fonction utilise le hachage SHA1, alors essayez d'utiliser PBKDF2WithHmacSHA1

Sur les deux instances (Rfc2898DeriveBytes, PBEKeySpec), vous devez vous assurer que la taille de la clé est la même (256 bits), c'est sûrement une erreur dans votre code Java

Vous pouvez essayer d'encoder et d'imprimer les clés pour vraiment vous assurer qu'elles sont identiques.

Je dois ajouter des extensions de cryptographie Java pour autoriser 256 clés.

Dépend de votre version de JVM. Je crois qu'Oracle JDK depuis la version 1.8u162 contient par défaut la politique JCE Unlimited Strength. Si vous utilisez une version actuelle de JRE, vous devriez être d'accord

Supplémentaire: vous utilisez le tableau zéro (statique) IV, qui n'est pas sécurisé


0 commentaires

0
votes

Enfin, j'ai décidé d'utiliser l'API BouncyCastle pour utiliser la fonctionnalité de RijndaelEngine , ainsi que pour générer la clé de 256 bits avec PKCS5S2ParametersGenerator .

J'ai créé la classe RijndaelEncryption pour pouvoir effectuer le chiffrement comme dans le code C #:

public static void main(String[] args) {
     RijndaelEncryption s = new RijndaelEncryption();
     byte[] salt = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
     String encryptStr = s.encryptString("763059", "515t3ma5m15B4d35", salt, 1000, 256, 128);
     System.out.println("Encryptation: " + encryptStr);
}

Et j'ai testé dans main méthode:

public class RijndaelEncryption {

    public String encryptString(String word, String password, byte[] salt, int iterations, int keySize, int blockSize) {
        try {
            byte[] pswd = sha256String(password, "UTF-8");
            PKCS5S2ParametersGenerator key = keyGeneration(pswd, salt, iterations);
            ParametersWithIV iv = generateIV(key, keySize, blockSize);
            BufferedBlockCipher cipher = getCipher(true, iv);
            byte[] inputText = word.getBytes("UTF-8");
            byte[] newData = new byte[cipher.getOutputSize(inputText.length)];
            int l = cipher.processBytes(inputText, 0, inputText.length, newData, 0);
            cipher.doFinal(newData, l);
            return new String(Base64.encode(newData), "UTF-8");
        } catch (UnsupportedEncodingException | IllegalStateException | DataLengthException | InvalidCipherTextException e) {
            return null;
        }
    }

    public BufferedBlockCipher getCipher(boolean encrypt, ParametersWithIV iv) {
        RijndaelEngine rijndael = new RijndaelEngine();
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndael));
        cipher.init(encrypt, iv);
        return cipher;
    }

    public ParametersWithIV generateIV(PKCS5S2ParametersGenerator key, int keySize, int blockSize) {
        try {
            ParametersWithIV iv = null;
            iv = ((ParametersWithIV) key.generateDerivedParameters(keySize, blockSize));
            return iv;
        } catch (Exception e) {
            return null;
        }
    }

    public PKCS5S2ParametersGenerator keyGeneration(byte[] password, byte[] salt, int iterations) {
        try {
            PKCS5S2ParametersGenerator key = new PKCS5S2ParametersGenerator();
            key.init(password, salt, iterations);
            return key;
        } catch (Exception e) {
            return null;
        }
    }

    public byte[] sha256String(String password, Charset charset) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(password.getBytes(charset));
            return md.digest();
        } catch (NoSuchAlgorithmException ex) {
            return null;
        }
    }

    public byte[] sha256String(String password, String charset) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(password.getBytes(charset));
            return md.digest();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
            return null;
        }
    }
}

Pour obtenir:

Chiffrement: 3cHrXxxL1Djv0K2xW4HuCg ==


0 commentaires

0
votes

J'ai une réponse à la question initiale. Pour référence future sans château gonflable.

Vous avez eu quelques problèmes.

  1. La taille de la clé devait être de 256 + 128 (taille de bloc également)
  2. C # et Java byte [] ne fonctionnent pas de la même manière car les octets java sont toujours signés, ce qui perturbe le cryptage du mot de passe.

Ces deux morceaux de code donnent en sortie:

Code C #:

        package com.example.myapplication;

    import androidx.appcompat.app.AppCompatActivity;

    import android.os.Bundle;
    import android.util.Base64;

    import java.nio.charset.StandardCharsets;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.Key;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.spec.AlgorithmParameterSpec;
    import java.security.spec.InvalidKeySpecException;

    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            String result = encrypt("yme", "515t3ma5m15B4d35");
        }


        private static String encrypt(String word, String password) {

            byte[] salt = new byte[] { (byte)0x49, (byte)0x64, (byte)0x76, (byte)0x65, (byte)0x64, (byte)0x65, (byte)0x76, (byte)0x61, (byte)0x6e, (byte)0x20, (byte)0x4d, (byte)0x65, (byte)0x76};

            try {
                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
                PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, 1000, 256 + 128);
                Key secretKey = factory.generateSecret(pbeKeySpec);
                byte[] test = secretKey.getEncoded();
                byte[] key = new byte[32];
                byte[] iv = new byte[16];
                System.arraycopy(secretKey.getEncoded(), 0, key, 0, 32);
                System.arraycopy(secretKey.getEncoded(), 32, iv, 0, 16);


                SecretKeySpec secret = new SecretKeySpec(key, "AES");
                AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec);
   //Realise Im using UTF16 here! Maybe you need UTF8
                byte[] plaintextintobytes  =word.getBytes(StandardCharsets.UTF_16LE);
                byte[] encrypted = cipher.doFinal(plaintextintobytes);
                String encryptedInformation = Base64.encodeToString(encrypted, Base64.NO_WRAP);
                return encryptedInformation;

            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            }

            return "";
        }


    }

Code Java (cela provenait d'un projet Android bcs qui est mon cas d'utilisation mais devrait fonctionner partout):

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;

    namespace tryencryption
    {
        class Program
        {


        static void Main(string[] args)
        {
            var f = EncryptText("yme", "515t3ma5m15B4d35");//(word, password)
            Console.WriteLine(f);
            Console.ReadKey();
        }

        public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, string passwordString)
        {
            byte[] encryptedBytes = null;
            byte[] salt = new byte[] { (byte)0x49, (byte)0x64, (byte)0x76, (byte)0x65, (byte)0x64, (byte)0x65, (byte)0x76, (byte)0x61, (byte)0x6e, (byte)0x20, (byte)0x4d, (byte)0x65, (byte)0x76 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    AES.KeySize = 256;
                    AES.BlockSize = 128;

                    var key = new Rfc2898DeriveBytes(passwordString, salt, 1000);
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }
                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }

        public static string EncryptText(string input, string password)
        {
            byte[] bytesToBeEncrypted = Encoding.Unicode.GetBytes(input);

            byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, password);
            string result = Convert.ToBase64String(bytesEncrypted);

            return result;
        }


    }
}


0 commentaires