2010-01-19 8 views
19

J'ai trouvé beaucoup d'exemples de cryptage en C#, et un couple pour Android, mais je cherche particulièrement un moyen de gérer le cryptage (en utilisant quelque chose comme AES, TripleDES, etc .) à partir d'Android, et finissent par être décryptés en C#. J'ai trouvé un example for encoding AES dans Android et encoding/decoding AES dans C# mais je ne suis pas sûr si ceux-ci sont compatibles (C# nécessite un IV, rien n'est spécifié pour cela dans l'exemple Android). En outre, une recommandation sur un bon moyen de coder la chaîne chiffrée pour la transmission sur HTTP (Base64?) Serait utile. Merci.Cryptage compatible entre Android et C#

+0

Le lien est mort. Pouvez-vous ajouter l'extrait de code que vous avez utilisé pour Android? –

Répondre

38

Vous avez obtenu de l'aide de http://oogifu.blogspot.com/2009/01/aes-in-java-and-c.html.

Voici ma classe Java:

package com.neocodenetworks.smsfwd; 

import java.security.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 
import android.util.Log; 

public class Crypto { 
    public static final String TAG = "smsfwd"; 

    private static Cipher aesCipher; 
    private static SecretKey secretKey; 
    private static IvParameterSpec ivParameterSpec; 

    private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding"; 
    private static String CIPHER_ALGORITHM = "AES"; 
    // Replace me with a 16-byte key, share between Java and C# 
    private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 

    private static String MESSAGEDIGEST_ALGORITHM = "MD5"; 

    public Crypto(String passphrase) { 
     byte[] passwordKey = encodeDigest(passphrase); 

     try { 
      aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); 
     } catch (NoSuchAlgorithmException e) { 
      Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e); 
     } catch (NoSuchPaddingException e) { 
      Log.e(TAG, "No such padding PKCS5", e); 
     } 

     secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM); 
     ivParameterSpec = new IvParameterSpec(rawSecretKey); 
    } 

    public String encryptAsBase64(byte[] clearData) { 
     byte[] encryptedData = encrypt(clearData); 
     return net.iharder.base64.Base64.encodeBytes(encryptedData); 
    } 

    public byte[] encrypt(byte[] clearData) { 
     try { 
      aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec); 
     } catch (InvalidKeyException e) { 
      Log.e(TAG, "Invalid key", e); 
      return null; 
     } catch (InvalidAlgorithmParameterException e) { 
      Log.e(TAG, "Invalid algorithm " + CIPHER_ALGORITHM, e); 
      return null; 
     } 

     byte[] encryptedData; 
     try { 
      encryptedData = aesCipher.doFinal(clearData); 
     } catch (IllegalBlockSizeException e) { 
      Log.e(TAG, "Illegal block size", e); 
      return null; 
     } catch (BadPaddingException e) { 
      Log.e(TAG, "Bad padding", e); 
      return null; 
     } 
     return encryptedData; 
    } 

    private byte[] encodeDigest(String text) { 
     MessageDigest digest; 
     try { 
      digest = MessageDigest.getInstance(MESSAGEDIGEST_ALGORITHM); 
      return digest.digest(text.getBytes()); 
     } catch (NoSuchAlgorithmException e) { 
      Log.e(TAG, "No such algorithm " + MESSAGEDIGEST_ALGORITHM, e); 
     } 

     return null; 
    } 
} 

I utilisé http://iharder.sourceforge.net/current/java/base64/ pour le codage base64.

Voici mon classe C#:

using System; 
using System.Text; 
using System.Security.Cryptography; 

namespace smsfwdClient 
{ 
    public class Crypto 
    { 
     private ICryptoTransform rijndaelDecryptor; 
     // Replace me with a 16-byte key, share between Java and C# 
     private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 

     public Crypto(string passphrase) 
     { 
      byte[] passwordKey = encodeDigest(passphrase); 
      RijndaelManaged rijndael = new RijndaelManaged(); 
      rijndaelDecryptor = rijndael.CreateDecryptor(passwordKey, rawSecretKey); 
     } 

     public string Decrypt(byte[] encryptedData) 
     { 
      byte[] newClearData = rijndaelDecryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length); 
      return Encoding.ASCII.GetString(newClearData); 
     } 

     public string DecryptFromBase64(string encryptedBase64) 
     { 
      return Decrypt(Convert.FromBase64String(encryptedBase64)); 
     } 

     private byte[] encodeDigest(string text) 
     { 
      MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider(); 
      byte[] data = Encoding.ASCII.GetBytes(text); 
      return x.ComputeHash(data); 
     } 
    } 
} 

J'espère vraiment que cela aide quelqu'un d'autre!

+7

Ouais ... J'aime quand les gens répondent à ma question technique avec un tas de "Oh, tu devrais faire ça" ou "Oh, tu devrais faire ça". Merci d'être pratique et de quitter votre implémentation de classe. – kape123

+0

J'ai crypté mon contenu de fichier avec votre code Java et enregistré le contenu crypté dans encrypted.txt. Maintenant, je voudrais le décrypter avec l'outil openssl en utilisant cette commande: openssl enc -d -a -p -aes-256-cbc -salt -in encrypted.txt -out decrypted.txt -pass pass: myPassword mais je reçois erreur: mauvais numéro magique. Une idée de ce qui ne va pas? Même si je supprime le paramètre -salt de la commande, je reçois toujours la même erreur. – uerceg

+0

@uerceg: Vous allez vouloir commencer une nouvelle question pour cela. Cette solution n'utilise pas OpenSSL donc je ne m'attends pas à ce que cela fonctionne. – Jess

1

Oui, ça devrait aller, tant que la taille des clés est la même - AES 128 bits et le bon mode de chiffrement par bloc (CBC). Vous pourriez rencontrer des problèmes de remplissage, mais cela devrait être assez facile à régler. J'ai récemment rencontré ces problèmes avec Java et Python, mais tout a fonctionné à la fin. Base64 pour l'encodage devrait être bien sur HTTP. Bonne chance!

1

Si vous implémentez correctement le même chiffre (comme AES) et le mode (comme CTR, BFC, CCM, etc.) sur les deux extrémités, le cryptogramme d'une extrémité peut être déchiffré par l'autre extrémité indépendamment de la plateforme.

L'exemple Android auquel vous avez lié semble utiliser le mode ECB et n'est donc pas sécurisé pour vos besoins. Il est extrêmement important que vous compreniez les implications du mode de blocage que vous sélectionnez. Il est très facile d'obtenir une crypto erronée à ce niveau, ce qui entraîne un système qui n'est pas aussi sécurisé que vous le pensez.

EDIT: Je le reprends, il n'utilise pas ECB, mais la façon dont il génère le IV n'est pas pratique. En tout cas, mon point sur la compréhension des implications des modes de bloc est. Vous pouvez commencer par wikipedia article. Le livre de Bruce Schneier 'Practical Cryptography' est également extrêmement précieux pour quiconque met en œuvre la sécurité cryptographique. En ce qui concerne l'encodage de la chaîne, si vous devez convertir la chaîne en texte ASCII, Base64 est aussi bon que tout, mais je vous suggère d'étudier l'utilisation de HTTP PUT ou POST pour vous épargner cette étape supplémentaire.

4

Dans l'exemple fourni code C# source, regarder cette ligne:

Encoding.ASCII.GetString(newClearData); 

UTF-8 est le codage par défaut pour Android, chaîne de sorte cryptée (en particulier les caractères non-ASCII comme le chinois) sera passé à C# en supposant UTF-8. Le texte devient brouillé s'il est décodé en chaîne en utilisant le codage ASCII. Voici un meilleur,

Encoding.UTF8.GetString(newClearData); 

Merci!

1

La plupart des exemples sur Internet sont une faible implémentation d'AES. Pour qu'une implémentation soit forte, une IV aléatoire doit être utilisée tout le temps et la clé doit être hachée.

Pour plus sûr (aléatoire IV + clé hachée) multi-plateforme (android, ios, C#) de la mise en œuvre AES voir ma réponse ici - https://stackoverflow.com/a/24561148/2480840