109 votes

Cryptage/décryptage d'images à l'aide de chiffrement par blocs symétriques AES256

Existe-t-il un bon exemple de la façon dont crypter et décrypter image et autres fichiers avec AES sur Android ?

7 votes

Le chiffrement sur Android n'est pas fondamentalement différent de celui de toute autre plate-forme Java SE. Et comme toutes les réponses ci-dessous ne sont pas sécurisées, il faut soit comprendre la cryptographie avant de commencer à l'implémenter, soit emprunter des exemples de cryptographie.

4 votes

Vous devriez essayer ceci github.com/facebook/conceal .

7voto

SoloPilot Points 319

Si vous cryptez un fichier texte, le test/échantillon suivant peut être utile. Il effectue les opérations suivantes :

  1. Créer un flux d'octets,
  2. l'enveloppe avec un cryptage AES,
  3. l'emballer ensuite avec le traitement de texte
  4. et enfin le met en mémoire tampon

    // AESdemo
    
    public class AESdemo extends Activity {
        boolean encryptionIsOn = true;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_aesdemo);
            // needs <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
            String homeDirName = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/" + getPackageName();
            File file = new File(homeDirName, "test.txt");
            byte[] keyBytes = getKey("password");
    
            try {
                File dir = new File(homeDirName);
                if (!dir.exists())
                    dir.mkdirs();
                if (!file.exists())
                    file.createNewFile();
    
                OutputStreamWriter osw;
    
                if (encryptionIsOn) {
                    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
                    IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
                    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    
                    FileOutputStream fos = new FileOutputStream(file);
                    CipherOutputStream cos = new CipherOutputStream(fos, cipher);
                    osw = new OutputStreamWriter(cos, "UTF-8");
                }
                else    // not encryptionIsOn
                    osw = new FileWriter(file);
    
                BufferedWriter out = new BufferedWriter(osw);
                out.write("This is a test\n");
                out.close();
            }
            catch (Exception e) {
                System.out.println("Encryption Exception "+e);
            }
    
            ///////////////////////////////////
            try {
                InputStreamReader isr;
    
                if (encryptionIsOn) {
                    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
                    IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
                    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
    
                    FileInputStream fis = new FileInputStream(file);
                    CipherInputStream cis = new CipherInputStream(fis, cipher);
                    isr = new InputStreamReader(cis, "UTF-8");
                }
                else
                    isr = new FileReader(file);
    
                BufferedReader in = new BufferedReader(isr);
                String line = in.readLine();
                System.out.println("Text read: <"+line+">");
                in.close();
            }
            catch (Exception e) {
                System.out.println("Decryption Exception "+e);
            }
        }
    
        private byte[] getKey(String password) throws UnsupportedEncodingException {
            String key = "";
            while (key.length() < 16)
                key += password;
            return key.substring(0, 16).getBytes("UTF-8");
        }
    }

8 votes

AVERTISSEMENT Ce code utilise un mécanisme de dérivation de clé qui utilise le décodage de caractères par défaut. Ne l'utilisez pas si vous voulez avoir des problèmes pour décrypter vos données.

3 votes

@owlstead, bonne observation, il aurait été bien que vous suggériez la correction. L'exemple ci-dessus a maintenant été mis à jour pour spécifier un encodage de caractères dans getKey(). D'autres corrections sont les bienvenues...

9 votes

Désolé, je voulais surtout brûler les réponses ici, parce qu'ils ont utilisé SecureRandom pour la dérivation des clés. Si vous voulez savoir comment instancier un chiffrement, consultez la réponse d'ericksons ici . N'utilisez pas un IV statique (pour la même clé), et utilisez PBKDF2 pour la conversion mot de passe -> clé. Notez qu'un chiffrement non authentifié ne fournit que la confidentialité, et seulement s'il n'est pas utilisé dans un protocole de transport. Si vous voulez aider, vous pouvez brûler les autres réponses aussi (et voter mes commentaires là) :)

4voto

MiladAhmadi Points 355

Cryptage/décryptage AES dans Android

String encData= encrypt("keykey".getBytes("UTF-16LE"), ("0123000000000215").getBytes("UTF-16LE"));

String decData= decrypt("keykey",Base64.decode(encData.getBytes("UTF-16LE"), Base64.DEFAULT));

fonction de cryptage

private static String encrypt(byte[] key, byte[] clear) throws Exception
    {
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key);

        SecretKeySpec skeySpec = new SecretKeySpec(digestOfPassword, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return Base64.encodeToString(encrypted,Base64.DEFAULT);
    }

fonction de décryptage

private static String decrypt(String key, byte[] encrypted) throws Exception
    {
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));

        SecretKeySpec skeySpec = new SecretKeySpec(digestOfPassword, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, "UTF-16LE");
    }

Cryptage/décryptage AES en c#

 static void Main(string[] args)
        {
            string enc = encryptAES("0123000000000215", "keykey");
            string dec = decryptAES(enc, "keykey");

            Console.ReadKey();
        }

fonction de cryptage

 public static string encryptAES(string input, string key)
        {
            var plain = Encoding.Unicode.GetBytes(input);

            // 128 bits
            AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
            provider.KeySize = 128;
            provider.Mode = CipherMode.ECB;
            provider.Padding = PaddingMode.PKCS7;

            provider.Key = CalculateMD5Hash(key);

            var enc = provider.CreateEncryptor().TransformFinalBlock(plain, 0, plain.Length);
            return Convert.ToBase64String(enc);
        }

fonction de décryptage

public static string decryptAES(string encryptText, string key)
{
    byte[] enc = Convert.FromBase64String(encryptText);
    // 128 bits
    AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
    provider.KeySize = 128;
    provider.Mode = CipherMode.ECB;
    provider.Padding = PaddingMode.PKCS7;

    provider.Key = CalculateMD5Hash(key);

    var dec = provider.CreateDecryptor().TransformFinalBlock(enc, 0, enc.Length);
    return Encoding.Unicode.GetString(dec);
}

créer un md5

 public static byte[] CalculateMD5Hash(string input)
        {
            MD5 md5 = MD5.Create();
            byte[] inputBytes = Encoding.Unicode.GetBytes(input);
            return md5.ComputeHash(inputBytes);
        }

1 votes

MD5 n'est pas une fonction de hachage de mot de passe ou de dérivation de clé basée sur un mot de passe. Si vous utilisez un mot de passe, utilisez-le correctement.

2voto

Hardip Points 289

API simple pour effectuer un chiffrement AES sur Android. Il s'agit de la contrepartie Android de la bibliothèque AESCrypt de Ruby et Obj-C (avec les mêmes valeurs par défaut) :

https://github.com/scottyab/AESCrypt-Android

7 votes

Pourriez-vous nous expliquer comment cette bibliothèque peut être utilisée pour résoudre le problème ? Se contenter de copier la description GitHub et d'ajouter un lien vers elle n'est pas très utile, et votre réponse pourrait être bien meilleure avec quelques explications.

1voto

Rahul Raina Points 2863

Voici un extrait de code simple fonctionnant pour le cryptage et le décryptage AES.

import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

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

public class AESEncryptionClass {

    private static String INIT_VECTOR_PARAM = "#####";
    private static String PASSWORD = "#####";
    private static String SALT_KEY = "#####";

    private static SecretKeySpec generateAESKey() throws NoSuchAlgorithmException, InvalidKeySpecException {

        // Prepare password and salt key.
        char[] password = new String(Base64.decode(PASSWORD, Base64.DEFAULT)).toCharArray();
        byte[] salt = new String(Base64.decode(SALT_KEY, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        // Create object of  [Password Based Encryption Key Specification] with required iteration count and key length.
        KeySpec spec = new PBEKeySpec(password, salt, 64, 256);

        // Now create AES Key using required hashing algorithm.
        SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);

        // Get encoded bytes of secret key.
        byte[] bytesSecretKey = key.getEncoded();

        // Create specification for AES Key.
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytesSecretKey, "AES");
        return secretKeySpec;
    }

    /**
     * Call this method to encrypt the readable plain text and get Base64 of encrypted bytes.
     */
    public static String encryptMessage(String message) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {

        byte[] initVectorParamBytes = new String(Base64.decode(INIT_VECTOR_PARAM, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        Cipher encryptionCipherBlock = Cipher.getInstance("AES/CBC/PKCS5Padding");
        encryptionCipherBlock.init(Cipher.ENCRYPT_MODE, generateAESKey(), new IvParameterSpec(initVectorParamBytes));

        byte[] messageBytes = message.getBytes();
        byte[] cipherTextBytes = encryptionCipherBlock.doFinal(messageBytes);
        String encryptedText = Base64.encodeToString(cipherTextBytes, Base64.DEFAULT);
        return encryptedText;
    }

    /**
     * Call this method to decrypt the Base64 of encrypted message and get readable plain text.
     */
    public static String decryptMessage(String base64Cipher) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {

        byte[] initVectorParamBytes = new String(Base64.decode(INIT_VECTOR_PARAM, Base64.DEFAULT)).getBytes(StandardCharsets.UTF_8);

        Cipher decryptionCipherBlock = Cipher.getInstance("AES/CBC/PKCS5Padding");
        decryptionCipherBlock.init(Cipher.DECRYPT_MODE, generateAESKey(), new IvParameterSpec(initVectorParamBytes));

        byte[] cipherBytes = Base64.decode(base64Cipher, Base64.DEFAULT);
        byte[] messageBytes = decryptionCipherBlock.doFinal(cipherBytes);
        String plainText = new String(messageBytes);
        return plainText;
    }
}

Maintenant appel encryptMessage() ou decryptMessage() pour le désir AES Fonctionnement avec les paramètres requis.

Aussi gérer les exceptions pendant AES opérations.

J'espère que ça a aidé...

1 votes

Un sel statique et un IV ne sont pas sécurisés.

0voto

Matthew Hooker Points 89

Pour ajouter un château gonflable au projet Android : https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16/1.45

Ajoutez cette ligne dans votre activité principale :

static {
    Security.addProvider(new BouncyCastleProvider());
}

public class AESHelper {

    private static final String TAG = "AESHelper";

    public static byte[] encrypt(byte[] data, String initVector, String key) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            SecretKeySpec k = new SecretKeySpec(Base64.decode(key, Base64.DEFAULT), "AES");
            c.init(Cipher.ENCRYPT_MODE, k, iv);
            return c.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static byte[] decrypt(byte[] data, String initVector, String key) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            SecretKeySpec k = new SecretKeySpec(Base64.decode(key, Base64.DEFAULT), "AES");
            c.init(Cipher.DECRYPT_MODE, k, iv);
            return c.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String keyGenerator() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(192);

        return Base64.encodeToString(keyGenerator.generateKey().getEncoded(),
                Base64.DEFAULT);
    }
}

0 votes

0 votes

Je ne pense pas que vous ayez besoin de Bouncy pour cela ; il va seulement s'assurer que vous ne pouvez pas utiliser l'accélération matérielle et tuer les performances pour les gros fichiers (comme les images). Encoder la clé en base 64 est une mauvaise idée ; la stocker dans un magasin de clés est bien mieux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X