web-dev-qa-db-fra.com

Crypter en Java et décrypter en C # pour AES 256 bits

1.J'ai une fonction Java qui crypte le fichier xml et renvoie la chaîne cryptée.

/// Java Class 
import Java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.Apache.commons.codec.binary.Base64;

public class Crypt {

    public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    public static byte[] key_Array = Base64.decodeBase64(key);

    public static String encrypt(String strToEncrypt)
    {       
        try
        {   
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            //Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");      

            Key SecretKey = new SecretKeySpec(key_Array, "AES");

            Cipher _Cipher = Cipher.getInstance("AES");     
            _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey);       

            return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes()));     
        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());
        }
        return null;
    }

    public static void main(String[] args) {        
        StringBuilder sb = new StringBuilder();
        sb.append("xml file string ...");

        String EncryptedString = encrypt(sb.toString());        
        System.out.println("[EncryptedString]:"+EncryptedString);
    }
}

2.J'ai une fonction c # qui décrypte le message crypté par la fonction Java. </ Li>

/// C# Function
private static string Decrypt(string encryptedText)
{
    RijndaelManaged aesEncryption = new RijndaelManaged();            
    aesEncryption.BlockSize = 256;
    //aesEncryption.KeySize = 256;
    //aesEncryption.Mode = CipherMode.CBC;
    //aesEncryption.Padding = PaddingMode.PKCS7;

    string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    //string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";        

    byte[] keyArr = Convert.FromBase64String(keyStr);
    //byte[] ivArr = Convert.FromBase64String(ivStr);

    aesEncryption.Key = keyArr;
    //aesEncryption.IV = ivArr;

    ICryptoTransform decrypto = aesEncryption.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);  
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); /// CryptographicException: Length of the data to decrypt is invalid.    
    return ASCIIEncoding.UTF8.GetString(decryptedData); 
}

La fonction de cryptage Java fonctionne bien. Mais le problème est la fonction C #, 
quand je déchiffre je reçois un message d'erreur ci-dessous

CryptographicException: Length of the data to decrypt is invalid.

J'ai cherché des solutions en utilisant ci-dessous ref

  1. AES Encryption en Java et Decryption en C #
  2. C #/Java | AES256 chiffrer/déchiffrer
  3. Enccyption/Decryption en C # et Java

mais je suis toujours confronté à la même erreur. Quelqu'un pourrait-il me donner une suggestion s'il vous plaît?.

Mis à jour

Je viens de changer ma fonction de cryptographie C #. Ci-dessous, mes listes de modifications

  1. Taille du bloc à 128
  2. Taille de la clé à 256
  3. Taille IV à 16
  4. Taille de clé jusqu'à 32
/// Updated decrypt function
private static string Decrypt(string encryptedText)
{
    RijndaelManaged aesEncryption = new RijndaelManaged();            
    aesEncryption.BlockSize = 128;
    aesEncryption.KeySize = 256;

    //aesEncryption.Mode = CipherMode.CBC;
    aesEncryption.Padding = PaddingMode.None;

    string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";           

    byte[] ivArr = Convert.FromBase64String(ivStr);
    byte[] IVkey16BytesValue = new byte[16];
    Array.Copy(ivArr, IVkey16BytesValue, 16);

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArr32BytesValue = new byte[32];
    Array.Copy(keyArr, KeyArr32BytesValue, 32);

    aesEncryption.IV = IVkey16BytesValue;
    aesEncryption.Key = KeyArr32BytesValue; 

    ICryptoTransform decrypto = aesEncryption.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); 
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

Dans ce temps, aucune erreur ne se produit. Mais je reçois un message déchiffré que je ne peux pas lire.

g:�\0�\td��Y\\符O����\rL��W�wHm�>f�\au����%��0��\ ..........

S'il vous plaît laissez-moi recevoir votre suggestion à nouveau. 

12
Frank Myat Thu

Je crois que la taille du bloc doit être 128 et la taille de la clé 256. Le keyStr doit comporter 32 caractères et l'IVstr doit comporter 16 caractères. Cela peut aider car il explique pourquoi 128 bits doivent être utilisés pour la taille de bloc et quelles sont les tailles de clé. csrc.nist.gov/publications/fips/fips197/fips-197.pdf

Vous avez cela dans la méthode de déchiffrement. 

    aesEncryption.Padding = PaddingMode.None; 

Je crois que vous devez également mettre cela dans la méthode de chiffrement.

Aussi, pourquoi ne pas utiliser cette méthode pour la clé et IV. 

    aes.Key = ASCIIEncoding.ASCII.GetBytes(keyStr); 
    aes.IV = ASCIIEncoding.ASCII.GetBytes(ivStr);
4
deathismyfriend

Après avoir reçu des suggestions très utiles de @deathismyfriend et d’autres, j’ai découvert ce qui me manquait dans ma fonction C # Decrypt.

/// C# Error Fixed Version - CipherMode.ECB
public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

private static string Encrypt(string PlainText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    /// In Java, Same with below code
    /// Cipher _Cipher = Cipher.getInstance("AES");  // Java Code
    aes.Mode = CipherMode.ECB; 

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    aes.Key = KeyArrBytes32Value;

    ICryptoTransform encrypto = aes.CreateEncryptor();

    byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText);
    byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
    return Convert.ToBase64String(CipherText);
}

private static string Decrypt(string CipherText)
{  
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    /// In Java, Same with below code
    /// Cipher _Cipher = Cipher.getInstance("AES");  // Java Code
    aes.Mode = CipherMode.ECB;

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    aes.Key = KeyArrBytes32Value;

    ICryptoTransform decrypto = aes.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

En utilisant la fonction upper c #, je peux maintenant déchiffrer et lire le texte chiffré.
Ci-dessous se trouve ce que j'ai découvert après des erreurs répétées. 

CryptographicException: Padding is invalid and cannot be removed.

 Solution:  
_RijndaelManaged.Padding = CipherMode.xxx;    ///should toggle here
_RijndaelManaged.Padding = PaddingMode.xxx;   ///should toggle here 


CryptographicException: Length of the data to decrypt is invalid. 
CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.

Solution
1. _RijndaelManaged.BlockSize = 128; /// Must be
2. _RijndaelManaged.KeySize = 256; /// Must be
3. _RijndaelManaged.Key = Byte Array Size must be 32 in length ( more detail 32*8 = 256 KeySize )
4. _RijndaelManaged.IV = Byte Array Size must be 16 in length ( more detail 16*8 = 128 BlockSize)

Mais pour des raisons de sécurité, je pense que je ne devrais pas utiliser le mode BCE.
Selon 

  1. Le mode BCE n'est pas sécurisé
  2. Lien StackOverFlow

Donc, je le modifie à nouveau en Java et en C #.

// Java code - Cipher mode CBC version.
// CBC version need Initialization vector IV.
// Reference from https://stackoverflow.com/questions/6669181/why-does-my-aes-encryption-throws-an-invalidkeyexception/6669812#6669812

import Java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.Apache.commons.codec.binary.Base64;

public class CryptoSecurity {

    public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    public static byte[] key_Array = Base64.decodeBase64(key);

    public static String encrypt(String strToEncrypt)
    {       
        try
        {   
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");        

            // Initialization vector.   
            // It could be any value or generated using a random number generator.
            byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            Key SecretKey = new SecretKeySpec(key_Array, "AES");    
            _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey, ivspec);       

            return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes()));     
        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());
        }
        return null;
    }

    public static String decrypt(String EncryptedMessage)
    {
        try
        {
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");            

            // Initialization vector.   
            // It could be any value or generated using a random number generator.
            byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            Key SecretKey = new SecretKeySpec(key_Array, "AES");
            _Cipher.init(Cipher.DECRYPT_MODE, SecretKey, ivspec);           

            byte DecodedMessage[] = Base64.decodeBase64(EncryptedMessage);
            return new String(_Cipher.doFinal(DecodedMessage));

        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());          

        }
        return null;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        StringBuilder sb = new StringBuilder();

        sb.append("xml file string ...");

        String outputOfEncrypt = encrypt(sb.toString());        
        System.out.println("[CryptoSecurity.outputOfEncrypt]:"+outputOfEncrypt);

        String outputOfDecrypt = decrypt(outputOfEncrypt);        
        //String outputOfDecrypt = decrypt(sb.toString());        
        System.out.println("[CryptoSecurity.outputOfDecrypt]:"+outputOfDecrypt);
    }

}

En C #, je le modifie comme ci-dessous.

// C# Code, CipherMode.CBC
// CBC version need Initialization vector IV.

public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static string Encrypt(string PlainText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    // It is equal in Java 
    /// Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");    
    aes.Mode = CipherMode.CBC;  
    aes.Padding = PaddingMode.PKCS7; 

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    // Initialization vector.   
    // It could be any value or generated using a random number generator.
    byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
    byte[] IVBytes16Value = new byte[16];
    Array.Copy(ivArr, IVBytes16Value, 16);

    aes.Key = KeyArrBytes32Value;
    aes.IV = IVBytes16Value;

    ICryptoTransform encrypto = aes.CreateEncryptor();

    byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText);
    byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
    return Convert.ToBase64String(CipherText);

}

private static string Decrypt(string CipherText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    // Initialization vector.   
    // It could be any value or generated using a random number generator.
    byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };            
    byte[] IVBytes16Value = new byte[16];
    Array.Copy(ivArr, IVBytes16Value, 16);

    aes.Key = KeyArrBytes32Value;
    aes.IV = IVBytes16Value;

    ICryptoTransform decrypto = aes.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

Maintenant tout fonctionne .
Pour plus de détails sur AES, cliquez sur ce lien que @deathismyfriend m'a donné.
C'est aussi très utile.

16
Frank Myat Thu

Sur l'un de mes projets récents, j'ai été chargé de créer une URL avec une partie chiffrée à transférer sur un autre site Web. Ils ont couru Java sur leur serveur, alors que nous avons développé en c #. 

Je sais que cela ne correspond pas exactement à ce que vous avez été chargé de créer, mais j'espère que cela pourra aider d'autres personnes qui essaient de trouver des réponses :)

J'ai reçu ce qui suit de leurs développeurs pour construire notre cryptage à partir de

enter image description here

Pour accomplir cela en c # j'ai fait ce qui suit:

    public String Encrypt(String plainText, String key)
    {
        var plainBytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key)));
    }

    private RijndaelManaged GetRijndaelManaged(String secretKey)
    {
        var keyBytes = new byte[16];
        var secretKeyBytes = Encoding.ASCII.GetBytes(secretKey);
        Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
        return new RijndaelManaged
        {
            Mode = CipherMode.ECB,
            Padding = PaddingMode.PKCS7,
            KeySize = 128,
            BlockSize = 128,
            Key = keyBytes,
            IV = keyBytes

        };
    }

    private byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
    {
        return rijndaelManaged.CreateEncryptor()
            .TransformFinalBlock(plainBytes, 0, plainBytes.Length);
    }
2
A Kimmel

J'ai eu un problème avec cet algorithme (uniquement en Java) et j'ai fait quelques changements.

Diff Image

// Java code - Cipher mode CBC version.
// CBC version need Initialization vector IV.
// Reference from https://stackoverflow.com/questions/6669181/why-does-my-aes-encryption-throws-an-invalidkeyexception/6669812#6669812
public static String key = "FFClY170hLrhsDnKUEhJ4FhVOnrpNNFFClY170hLrhsDnKUE";
public static byte[] key_Array = Base64.decodeBase64(key);

public static String encrypt(String strToEncrypt) {
    try {
        //Cipher _Cipher = Cipher.getInstance("AES");
        //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

        // Initialization vector.   
        // It could be any value or generated using a random number generator.
        byte[] iv = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7};
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        key_Array = Arrays.copyOf(key_Array, 32);

        Key SecretKey = new SecretKeySpec(key_Array, "AES");
        _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey, ivspec);

        return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes()));
    } catch (Exception e) {
        System.out.println("[Exception]:" + e.getMessage());
    }
    return null;
}

public static String decrypt(String EncryptedMessage) {
    try {
        //Cipher _Cipher = Cipher.getInstance("AES");
        //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

        // Initialization vector.   
        // It could be any value or generated using a random number generator.
        byte[] iv = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7};
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        key_Array = Arrays.copyOf(key_Array, 32);

        Key SecretKey = new SecretKeySpec(key_Array, "AES");
        _Cipher.init(Cipher.DECRYPT_MODE, SecretKey, ivspec);

        byte DecodedMessage[] = Base64.decodeBase64(EncryptedMessage);
        return new String(_Cipher.doFinal(DecodedMessage));

    } catch (Exception e) {
        System.out.println("[Exception]:" + e.getMessage());

    }
    return null;
}