Как зашифровать и расшифровать файл в Android? - PullRequest
61 голосов
/ 25 ноября 2010

Я хочу зашифровать файл и сохранить его на SD-карте. Я хочу расшифровать этот зашифрованный файл и снова сохранить его на SD-карте. Я пытался зашифровать файл, открыв как поток файлов и шифровать, но это не работает. Мне нужна идея, как это сделать.

Ответы [ 5 ]

63 голосов
/ 07 ноября 2011

Используйте CipherOutputStream или CipherInputStream с Cipher и ваши FileInputStream / FileOutputStream .

Я бы предложил что-то вроде Cipher.getInstance("AES/CBC/PKCS5Padding") для создания класса Cipher. Режим CBC является безопасным и не имеет уязвимостей режима ECB для неслучайных открытых текстов . Он должен присутствовать в любой универсальной криптографической библиотеке, обеспечивая высокую совместимость.

Не забудьте использовать Вектор инициализации (IV), сгенерированный безопасным генератором случайных чисел , если вы хотите зашифровать несколько файлов одним и тем же ключом. Вы можете добавить префикс IV в начале зашифрованного текста. Это всегда ровно один блок (16 байт).

Если вы хотите использовать пароль, убедитесь, что вы используете хороший механизм получения ключей (посмотрите шифрование на основе пароля или получение ключа на основе пароля). PBKDF2 - наиболее часто используемая схема получения ключей на основе пароля, и она присутствует в большинстве сред выполнения Java , включая Android. Обратите внимание, что SHA-1 является немного устаревшей хеш-функцией, но она должна быть в порядке в PBKDF2 и в настоящее время предоставляет наиболее совместимый параметр.

Всегда указывайте кодировку символов при кодировании / декодировании строк, иначе у вас возникнут проблемы, если кодировка платформы отличается от предыдущей. Другими словами, не используйте String.getBytes(), но используйте String.getBytes(StandardCharsets.UTF_8).

Чтобы сделать его более безопасным, добавьте криптографическую целостность и аутентичность, добавив безопасную контрольную сумму (MAC или HMAC) поверх зашифрованного текста и IV, предпочтительно используя другой ключ. Без тега аутентификации зашифрованный текст может быть изменен таким образом, что изменение не может быть обнаружено.

Имейте в виду, что CipherInputStream может не сообщать BadPaddingException, включая BadPaddingException, сгенерированные для аутентифицированных шифров, таких как GCM. Это сделало бы потоки несовместимыми и небезопасными для таких аутентифицированных шифров.

50 голосов
/ 09 марта 2013

У меня была похожая проблема, и для шифрования / дешифрования я придумал это решение:

public static byte[] generateKey(String password) throws Exception
{
    byte[] keyStart = password.getBytes("UTF-8");

    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
    sr.setSeed(keyStart);
    kgen.init(128, sr);
    SecretKey skey = kgen.generateKey();
    return skey.getEncoded();
}

public static byte[] encodeFile(byte[] key, byte[] fileData) throws Exception
{

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(fileData);

    return encrypted;
}

public static byte[] decodeFile(byte[] key, byte[] fileData) throws Exception
{
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);

    byte[] decrypted = cipher.doFinal(fileData);

    return decrypted;
}

Чтобы сохранить зашифрованный файл в sd do:

File file = new File(Environment.getExternalStorageDirectory() + File.separator + "your_folder_on_sd", "file_name");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
byte[] yourKey = generateKey("password");
byte[] filesBytes = encodeFile(yourKey, yourByteArrayContainigDataToEncrypt);
bos.write(fileBytes);
bos.flush();
bos.close();

Для декодирования файла используйте:

byte[] yourKey = generateKey("password");
byte[] decodedData = decodeFile(yourKey, bytesOfYourFile);

Для чтения из файла в байтовый массив существует другой выход. Пример: http://examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/

0 голосов
/ 18 декабря 2015

У меня была такая же проблема, я получил решение из этого кода.

private static final String ALGO = "AES";
private static final byte[] keyValue = new byte[] { 'o', 'n', 'e', 'n','e', 't', 'e','d', 'o', 'c', 'e', 'i', 'r', 's', 'r', 'p' };
    public static String decrypt(String encryptedData){
        String decryptedValue = null;
        try{
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        decryptedValue = new String(decValue);
    }catch(Exception e){
        //LOGGER.error("In TD:" + e);
        //Teneno_StartupService.loadForConnectionFailed();
    }
    return decryptedValue;
}
private static Key generateKey(){
    Key key = new SecretKeySpec(keyValue, ALGO);
    return key;
}
0 голосов
/ 04 июня 2012

Используйте CipherOutputStream или CipherInputStream с шифром и вашим FileOutputStream / FileInputStream.

0 голосов
/ 04 июня 2012

У нас та же проблема, и она кем-то решена в моей ветке вопросов. Вы должны просто взглянуть на: CipherInputStream и CipherOutputStream. Они используются для шифрования и дешифрования потоков байтов. подробный исходный код см. в ответе Кирилла по этой ссылке: Как зашифровать файл с SD-карты с помощью AES в Android?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...