Cryptage AES en Java et décryptage en C #

Bonjour, j’ai chiffré une chaîne hexadécimale et une clé chiffrée à l’aide de l’algorithme AES standard. Code:

final Ssortingng key = "=abcd!#Axd*G!pxP"; final javax.crypto.spec.SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); final javax.crypto.Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte [] encryptedValue = cipher.doFinal(input.getBytes()); return new Ssortingng(org.apache.commons.codec.binary.Hex.encodeHex(encryptedValue)); 

Maintenant, j’essaie de le déchiffrer en utilisant le code C #:

  RijndaelManaged rijndaelCipher = new RijndaelManaged(); // Assumed Mode and padding values. rijndaelCipher.Mode = CipherMode.ECB; rijndaelCipher.Padding = PaddingMode.None; // AssumedKeySize and BlockSize values. rijndaelCipher.KeySize = 0x80; rijndaelCipher.BlockSize = 0x80; // Convert Hex keys to byte Array. byte[] encryptedData = hexSsortingngToByteArray(textToDecrypt); byte[] pwdBytes = Encoding.Unicode.GetBytes(key); byte[] keyBytes = new byte[0x10]; int len = pwdBytes.Length; if (len > keyBytes.Length) { len = keyBytes.Length; } Array.Copy(pwdBytes, keyBytes, len); rijndaelCipher.Key = keyBytes; rijndaelCipher.IV = keyBytes; // Decrypt data byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length); str = Encoding.UTF8.GetSsortingng(plainText); 

et

  static private byte[] HexToBytes(ssortingng str) { if (str.Length == 0 || str.Length % 2 != 0) return new byte[0]; byte[] buffer = new byte[str.Length / 2]; char c; for (int bx = 0, sx = 0; bx  '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) < '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')); } return buffer; } 

mais la sortie n’est pas comme prévu. S’il vous plaît indiquer où je vais mal?

Votre code a un gros problème: Il mélange les encodages de caractères!

En Java, vous appelez key.getBytes() , sans argument. Cette méthode renvoie les données codées UTF-8 ou CP1252 / ISO 8859-1 en fonction de votre système d’exploitation et du jeu de caractères par défaut en Java.

Du côté C #, vous utilisez Encoding.Unicode.GetBytes(key) – “Unicode” dans .Net est un synonyme de caractères à double octet alias UTF-16 (Little-Endian) . Par conséquent, vous utilisez une clé différente en C #.

Vous devriez pouvoir voir la différence en comparant le nombre d’octets en Java et en C #:

Java: "=abcd!#Axd*G!pxP".getBytes().length = 16

C #: Encoding.Unicode.GetBytes("=abcd!#Axd*G!pxP").Length = 32

Je vous recommande fortement d’utiliser des tableaux d’octets au lieu de chaînes pour définir une clé cryptographique.

Mise à jour: une autre différence est que vous définissez un vecteur d’initialisation (IV) en C #, ce que vous ne faites pas en Java. Comme vous utilisez la BCE, le IV ne devrait pas être utilisé, mais si vous passez à CBC par exemple, cela fait une grande différence.

J’avais besoin de quelque chose non seulement pour C # mais aussi pour Silverlight et compatible Windows Phone 7. Et j’en ai vraiment marre du manque d’exemples complets de quelque chose d’acceptable à la fois en Java et en C # (et basé sur Base64).

Le code n’a rien d’extraordinaire, mais fonctionne. N’hésitez pas à l’améliorer, car je l’ai marqué comme étant un wiki de communauté, mais assurez-vous de le tester avant de soumettre toute modification.

Voici le code C #:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.IO; //Author: Doguhan Uluca //Website: www.deceivingarts.com namespace DeceivingArts.Common { public class Encryptor { private ssortingng _seed = ""; public Encryptor(ssortingng seed) { _seed = seed; } public ssortingng Encrypt(ssortingng input) where TSymmesortingcAlgorithm : SymmesortingcAlgorithm, new() { var pwdBytes = Encoding.UTF8.GetBytes(_seed); using(TSymmesortingcAlgorithm sa = new TSymmesortingcAlgorithm()) { ICryptoTransform saEnc = sa.CreateEncryptor(pwdBytes, pwdBytes); var encBytes = Encoding.UTF8.GetBytes(input); var resultBytes = saEnc.TransformFinalBlock(encBytes, 0, encBytes.Length); return Convert.ToBase64Ssortingng(resultBytes); } } public ssortingng Decrypt(ssortingng input) where TSymmesortingcAlgorithm : SymmesortingcAlgorithm, new() { var pwdBytes = Encoding.UTF8.GetBytes(_seed); using(TSymmesortingcAlgorithm sa = new TSymmesortingcAlgorithm()) { ICryptoTransform saDec = sa.CreateDecryptor(pwdBytes, pwdBytes); var encBytes = Convert.FromBase64Ssortingng(input); var resultBytes = saDec.TransformFinalBlock(encBytes, 0, encBytes.Length); return Encoding.UTF8.GetSsortingng(resultBytes); } } } } 

Voici le code Java compatible Android:

 import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * Usage: * 
 * Ssortingng crypto = SimpleCrypto.encrypt(masterpassword, cleartext) * ... * Ssortingng cleartext = SimpleCrypto.decrypt(masterpassword, crypto) * 

* @author ferenc.hechler * @author Doguhan Uluca */ public class Encryptor { public static Ssortingng encrypt(Ssortingng seed, Ssortingng cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toBase64(result); } public static Ssortingng decrypt(Ssortingng seed, Ssortingng encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = fromBase64(encrypted); byte[] result = decrypt(rawKey, enc); return new Ssortingng(result); } private static byte[] getRawKey(byte[] seed) throws Exception { SecretKey skey = new SecretKeySpec(seed, "AES"); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(raw); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(raw); cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static Ssortingng toBase64(byte[] buf) { return Base64.encodeBytes(buf); } public static byte[] fromBase64(Ssortingng str) throws Exception { return Base64.decode(str); } }

Pour la conversion en Base64, veuillez consulter l’excellente mise en œuvre à l’ adresse http://iharder.net/base64 .

J’espère que cela fait gagner du temps aux gens.

Essayez cette combinaison:

 aesAlg.Mode = CipherMode.ECB; aesAlg.Padding = PaddingMode.PKCS7; //aesAlg.IV; - use default (not assign) 

Je suppose que l’erreur est que vous ne spécifiez pas de remplissage ou de mode de fonctionnement du côté Java de cette équation. Je ne suis pas sûr de la valeur par défaut de l’implémentation AES de Java, mais je commencerais par spécifier les deux lorsque vous obtenez le chiffrement. Par exemple:

 Cipher.getInstance("//"); 

Vous devez rechercher les schémas de remplissage et les modes de fonctionnement pris en charge pour AES en Java, puis vous assurer de configurer votre code C # pour utiliser exactement la même configuration.