Шифрование / дешифрование Android с использованием AES [закрыто]

105

Есть ли хороший пример того, как зашифровать и расшифровать изображения и другие файлы с помощью AES на Android?

h4rd4r7c0r3
источник
7
Шифрование на Android принципиально не отличается от шифрования на любой другой платформе Java SE. И поскольку все приведенные ниже ответы небезопасны, вам нужно либо разбираться в криптографии, прежде чем приступить к реализации, либо заимствовать примеры криптографии.
Maarten Bodewes
4
Вам следует попробовать этот github.com/facebook/conceal .
Nhat Dinh

Ответы:

131

Предупреждение: этот ответ содержит код, который вы не должны использовать, поскольку он небезопасен (с использованием SHA1PRNG для получения ключа и с использованием AES в режиме ECB)

Вместо этого (по состоянию на 2016 год) используйте PBKDF2WithHmacSHA1 для получения ключа и AES в режиме CBC или GCM (GCM обеспечивает как конфиденциальность, так и целостность)

Вы можете использовать такие функции:

private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    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");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
    return decrypted;
}

И вызывайте их так:

ByteArrayOutputStream baos = new ByteArrayOutputStream();  
bm.compress(Bitmap.CompressFormat.PNG, 100, baos); // bm is the bitmap object   
byte[] b = baos.toByteArray();  

byte[] keyStart = "this is a key".getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();    

// encrypt
byte[] encryptedData = encrypt(key,b);
// decrypt
byte[] decryptedData = decrypt(key,encryptedData);

Это должно сработать, сейчас я использую аналогичный код в проекте.

Начо Л.
источник
9
Привет, это не работает для меня, я получаю исключение Badpadding при расшифровке того же.
Санат Пандей
34
ВНИМАНИЕ! Этот код использует известный плохой код из фрагментов кода Android для получения ключа. Не используйте его, если не хотите потерять данные. Заполненный ГСЧ не является хорошей функцией вывода ключа (KDF).
Maarten Bodewes
2
@IcedDante Просмотрите этот вопрос .
Maarten Bodewes 09
35
ВНИМАНИЕ! Этот код может по умолчанию использовать шифрование в режиме ECB на большинстве платформ. Использование шифрования в режиме ECB небезопасно для большинства данных, не говоря уже о изображениях. Найди пингвина !
Maarten Bodewes
10
@Maarten Bodewes Я вижу ваши предупреждения повсюду, под множеством сообщений. Не могли бы вы вместо этого предложить хорошее решение?
Яр
17

Как упоминал Nacho.L, используется производное PBKDF2WithHmacSHA1 , поскольку оно более защищено .

import android.util.Base64;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class AESEncyption {

    private static final int pswdIterations = 10;
    private static final int keySize = 128;
    private static final String cypherInstance = "AES/CBC/PKCS5Padding";
    private static final String secretKeyInstance = "PBKDF2WithHmacSHA1";
    private static final String plainText = "sampleText";
    private static final String AESSalt = "exampleSalt";
    private static final String initializationVector = "8119745113154120";

    public static String encrypt(String textToEncrypt) throws Exception {

        SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
        Cipher cipher = Cipher.getInstance(cypherInstance);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
        byte[] encrypted = cipher.doFinal(textToEncrypt.getBytes());
        return Base64.encodeToString(encrypted, Base64.DEFAULT);
    }

    public static String decrypt(String textToDecrypt) throws Exception {

        byte[] encryted_bytes = Base64.decode(textToDecrypt, Base64.DEFAULT);
        SecretKeySpec skeySpec = new SecretKeySpec(getRaw(plainText, AESSalt), "AES");
        Cipher cipher = Cipher.getInstance(cypherInstance);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(initializationVector.getBytes()));
        byte[] decrypted = cipher.doFinal(encryted_bytes);
        return new String(decrypted, "UTF-8");
    }

    private static byte[] getRaw(String plainText, String salt) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKeyInstance);
            KeySpec spec = new PBEKeySpec(plainText.toCharArray(), salt.getBytes(), pswdIterations, keySize);
            return factory.generateSecret(spec).getEncoded();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return new byte[0];
    }

}
Абиранджан
источник
3
Правда этот вывод намного лучше. Но теперь вы используете статический IV, статическую соль и слишком малое количество итераций. Таким образом, без предупреждений результат все еще ненадежен. Криптовалюта - это
настоящая
13
import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

class SecurityUtils {

  private static final byte[] salt = { (byte) 0xA4, (byte) 0x0B, (byte) 0xC8,
      (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 };

  private static int BLOCKS = 128;

  public static byte[] encryptAES(String seed, String cleartext)
      throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    return cipher.doFinal(cleartext.getBytes("UTF8"));
  }

  public static byte[] decryptAES(String seed, byte[] data) throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    return cipher.doFinal(data);
  }

  private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(BLOCKS, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
  }

  private static byte[] pad(byte[] seed) {
    byte[] nseed = new byte[BLOCKS / 8];
    for (int i = 0; i < BLOCKS / 8; i++)
      nseed[i] = 0;
    for (int i = 0; i < seed.length; i++)
      nseed[i] = seed[i];

    return nseed;
  }

  public static byte[] encryptPBE(String password, String cleartext)
      throws Exception {
    SecretKeyFactory factory = SecretKeyFactory
        .getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1024, 256);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
    return cipher.doFinal(cleartext.getBytes("UTF-8"));
  }

  public static String decryptPBE(SecretKey secret, String ciphertext,
      byte[] iv) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    return new String(cipher.doFinal(ciphertext.getBytes()), "UTF-8");
  }

}
Ашок Домадия
источник
4
Приведенный выше код вызывает исключение BadPaddingException на Android 4.2
Бриджеш Такур,
1
@BrijeshThakur - прочтите это
t0mm13b
12
ВНИМАНИЕ! Этот код использует известный плохой код из фрагментов кода Android для получения ключа. Не используйте его, если не хотите потерять данные. Заполненный ГСЧ не является хорошей функцией вывода ключа (KDF).
Maarten Bodewes
3
Более подробная информация здесь
Maarten Bodewes
9
ВНИМАНИЕ! Этот код может по умолчанию использовать шифрование в режиме ECB на большинстве платформ. Использование шифрования в режиме ECB небезопасно для большинства данных, не говоря уже о изображениях. Найди пингвина !
Maarten Bodewes
9

Старый вопрос, но я обновляю ответы, поддерживающие Android до и после публикации 4.2, и с учетом всех последних изменений, согласно блогу разработчиков Android.

Плюс я оставляю рабочий пример в моем репозитории на github .

import java.nio.charset.Charset;
import java.security.AlgorithmParameters;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;


/*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will Google be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, as long as the origin is not misrepresented.
* 
* @author: Ricardo Champa
* 
*/

public class MyCipher {

    private final static String ALGORITHM = "AES";
    private String mySecret;

    public MyCipher(String mySecret){
        this.mySecret = mySecret;
    }

    public MyCipherData encryptUTF8(String data){
        try{
            byte[] bytes = data.toString().getBytes("utf-8");
            byte[] bytesBase64 = Base64.encodeBase64(bytes);
            return encrypt(bytesBase64);
        }
        catch(Exception e){
            MyLogs.show(e.getMessage());
            return null;
        }

    }

    public String decryptUTF8(byte[] encryptedData, IvParameterSpec iv){
        try {
            byte[] decryptedData = decrypt(encryptedData, iv);
            byte[] decodedBytes = Base64.decodeBase64(decryptedData);
            String restored_data = new String(decodedBytes, Charset.forName("UTF8"));
            return restored_data;
        } catch (Exception e) {
            MyLogs.show(e.getMessage());;
            return null;
        }
    }

    //AES
    private MyCipherData encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //solved using PRNGFixes class
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] data = cipher.doFinal(clear);

        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        return new MyCipherData(data, iv);
    }

    private byte[] decrypt(byte[] raw, byte[] encrypted, IvParameterSpec iv) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, ALGORITHM);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    private byte[] getKey() throws Exception{
        byte[] keyStart = this.mySecret.getBytes("utf-8");
        KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);

        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        //      if (android.os.Build.VERSION.SDK_INT >= 17) {
        //          sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        //      } else {
        //          sr = SecureRandom.getInstance("SHA1PRNG");
        //      }
        sr.setSeed(keyStart);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] key = skey.getEncoded();
        return key;

    }
    ////////////////////////////////////////////////////////////
    private MyCipherData encrypt(byte[] data) throws Exception{
        return encrypt(getKey(),data);
    }
    private byte[] decrypt(byte[] encryptedData, IvParameterSpec iv) throws Exception{
        return decrypt(getKey(),encryptedData, iv);
    }
}
Рикардо
источник
@HammadTariqSahi? ¿
Рикардо,
Есть ли недостатки использования android.util.Base64.encode(bytes, Base64.DEFAULT)и вместо использования библиотеки кодеков Apache Commons android.util.Base64.decode(decryptedData, Base64.DEFAULT)?
ban-geoengineering
2
ВНИМАНИЕ! Этот код использует известный плохой код из фрагментов кода Android для получения ключа. Не используйте его, если не хотите потерять данные. Заполненный ГСЧ не является хорошей функцией вывода ключа (KDF). (вздох).
Maarten Bodewes
1
@MaartenBodewes, какие изменения мне следует сделать?
Рикардо
7

Если вы шифруете текстовый файл, вам может пригодиться следующий тест / образец. Он делает следующее:

  1. Создайте поток байтов,
  2. оборачивает это шифрованием AES,
  3. оберните его следующей обработкой текста
  4. и, наконец, буферизует его

    // 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");
        }
    }
SoloPilot
источник
8
ВНИМАНИЕ! Этот код использует механизм получения ключей, который использует декодирование символов по умолчанию. Не используйте это, если не хотите, чтобы у вас возникли проблемы с расшифровкой ваших данных.
Maarten Bodewes
3
@owlstead, хорошее наблюдение, было бы неплохо, если бы вы предложили исправление. Приведенный выше пример теперь обновлен, чтобы указать кодировку символов в getKey (). Дальнейшие исправления приветствуются ...
SoloPilot
9
Извините, я здесь в основном жег ответы, потому что они использовались SecureRandomдля вывода ключей. Если вы хотите узнать, как создать экземпляр шифра, проверьте ответ Эриксона здесь . Не используйте статический IV (для одного и того же ключа) и используйте PBKDF2 для преобразования пароля -> ключа. Обратите внимание, что неаутентифицированный шифр обеспечивает конфиденциальность только в том случае, если он не используется в транспортном протоколе. Если вы хотите помочь, вы можете сжечь и другие ответы (и проголосовать за мои комментарии там) :)
Maarten Bodewes
@MaartenBodewes вы "сжег" много ответов, но не предлагаете ответа. Если у вас есть правильный ответ, почему бы вам не написать его здесь?
Дика
@Dika Я думаю, что указал на ответ выше. Пожалуйста, имейте в виду, что я с очень большим отрывом - парень, который публикует больше всего ответов как по криптографии, так и по шифрованию. Также имейте в виду, что я скорее против универсальных библиотек-оболочек, которые просто побуждают людей копировать код, а не сами писать код для конкретного случая использования. API шифрования Java довольно хорошо продуман, хотя и немного громоздок. Используйте это! В шифровании изображений нет ничего особенного; это базовое шифрование файлов.
Maarten Bodewes
6

Для шифрования / дешифрования AES / CBC / PKCS7 просто скопируйте и вставьте следующий код и замените SecretKeyи IVсвоим собственным.

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

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

import android.util.Base64;


public class CryptoHandler {

    String SecretKey = "xxxxxxxxxxxxxxxxxxxx";
    String IV = "xxxxxxxxxxxxxxxx";

    private static CryptoHandler instance = null;

    public static CryptoHandler getInstance() {

        if (instance == null) {
            instance = new CryptoHandler();
        }
        return instance;
    }

    public String encrypt(String message) throws NoSuchAlgorithmException,
            NoSuchPaddingException, IllegalBlockSizeException,
            BadPaddingException, InvalidKeyException,
            UnsupportedEncodingException, InvalidAlgorithmParameterException {

        byte[] srcBuff = message.getBytes("UTF8");
        //here using substring because AES takes only 16 or 24 or 32 byte of key 
        SecretKeySpec skeySpec = new 
        SecretKeySpec(SecretKey.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new 
        IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
        byte[] dstBuff = ecipher.doFinal(srcBuff);
        String base64 = Base64.encodeToString(dstBuff, Base64.DEFAULT);
        return base64;
    }

    public String decrypt(String encrypted) throws NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException,
            BadPaddingException, UnsupportedEncodingException {

        SecretKeySpec skeySpec = new 
        SecretKeySpec(SecretKey.substring(0,32).getBytes(), "AES");
        IvParameterSpec ivSpec = new 
        IvParameterSpec(IV.substring(0,16).getBytes());
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] raw = Base64.decode(encrypted, Base64.DEFAULT);
        byte[] originalBytes = ecipher.doFinal(raw);
        String original = new String(originalBytes, "UTF8");
        return original;
    }
}
Суджит Кумар Гупта
источник
Не могли бы вы добавить функцию, которая может кодировать файл? Тип возврата будет байт []
Паритош
1
Вам просто нужно вызвать эти функции по имени класса. например. CryptoHandler.encrypt («ВАША СТРОКА, которую вы хотите зашифровать») и то же самое, что и эта, вы также можете вызвать decrypt (). И обе функции возвращают String.
Суджит Кумар Гупта
2
Предупреждение . Ключ - это не строка, ключ и IV не должны «выбираться» пользователем. IV должен быть непредсказуемым (неотличимым от случайного) для противника, чтобы CBC был безопасен. Еще одна неудачная попытка, вам больше 10 лет, чтобы не получить криптографию, но вы все еще готовы предоставить «пример». Это тоже ответ только кода, он не объясняет, какую безопасность он обеспечивает.
Maarten Bodewes
5

Шифрование / дешифрование AES в Android

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

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

функция шифрования

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);
    }

функция дешифрования

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");
    }

Шифрование / дешифрование AES в c #

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

            Console.ReadKey();
        }

функция шифрования

 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);
        }

функция дешифрования

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);
}

создать md5

 public static byte[] CalculateMD5Hash(string input)
        {
            MD5 md5 = MD5.Create();
            byte[] inputBytes = Encoding.Unicode.GetBytes(input);
            return md5.ComputeHash(inputBytes);
        }
Милад Ахмади
источник
1
MD5 не является хешем пароля или функцией вывода ключа на основе пароля. Если вы используете пароль, используйте его правильно.
Maarten Bodewes
2

Простой API для шифрования AES на Android. Это Android-аналог библиотеки AESCrypt Ruby и Obj-C (с теми же значениями по умолчанию):

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

Hardip
источник
7
Не могли бы вы немного рассказать о том, как эту библиотеку можно использовать для решения проблемы? Простое копирование описания GitHub и добавление ссылки на него не так уж и полезно, и ваш ответ может быть намного лучше с некоторыми пояснениями.
JonasCz - Восстановите Монику
1

Вот простой фрагмент кода, работающий для шифрования и дешифрования 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;
    }
}

Теперь звоните encryptMessage()или decryptMessage()по желаниюAES Операции с необходимыми параметрами.

Кроме того , обрабатывайте исключения во время AESопераций.

Надеюсь, это помогло ...

Рахул Райна
источник
1
Статическая соль и IV небезопасны.
Maarten Bodewes
0

Чтобы добавить надувной замок в проект Android: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16/1.45

Добавьте эту строку в свое Основное действие:

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);
    }
}
Мэтью Хукер
источник
Не думаю, что для этого вам понадобится Bouncy; он только гарантирует, что вы не можете использовать аппаратное ускорение и снизить производительность для больших файлов (таких как изображения). Кодировать ключ в базе 64 - плохая идея; хранить его в хранилище ключей намного лучше.
Maarten Bodewes
0

Попробуйте с приведенным ниже кодом, он работает для меня.

public static String decrypt(String encrypted) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
    byte[] key = your Key in byte array;
    byte[] input = salt in byte array;

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(input);
    Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    ecipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);

    byte[] raw = Base64.decode(encrypted, Base64.DEFAULT);
    byte[] originalBytes = ecipher.doFinal(raw);

    String original = new String(originalBytes, "UTF8");
    return original;
}
Рн Бхадани
источник
1
Крипто-код должен не просто работать, он должен быть безопасным. Можете ли вы указать, какую защиту обеспечивает ваш код (или в данном случае не обеспечивает?)
Маартен Бодевес