ОШИБКА расшифровки AES: поврежден блок андроида

Я осмотрел стек, чтобы найти ответ на мою проблему, но пока ничего не получалось. Что я пытаюсь сделать, так это зашифровать XML-файл, который загружен в ASYNCtask, а затем расшифровать его.

Что я уже проверил:

-Произведенный ключ одинаков при шифровании и дешифровании и сохраняется в общих преференциях с Base64.

-IV то же самое, поскольку в настоящий момент он находится в статической переменной для целей тестирования.

-Cipher установлен в AES / CBC / PKCS5Padding

-Ключ установлен в AES

Ошибка появляется в decryptXml() в строке:
byte [] decrypted = cipher.doFinal (bytes);

У меня нет идей и ничего не работает. Я надеюсь, что некоторые из вас могут найти ошибку в моем коде. Спасибо за помощь!

КОД:

genetateKey ()

    SharedPreferences sharedPreferences = context.getSharedPreferences(GENERATED_KEY, Context.MODE_PRIVATE);
    String keyStr = sharedPreferences.getString(GENERATED_KEY, null);
    if (keyStr == null) {
        final int outputKeyLength = 128;
        SecureRandom secureRandom = new SecureRandom();
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(outputKeyLength, secureRandom);
        SecretKey key = keyGenerator.generateKey();
        byte[] bytes = key.getEncoded();
        keyStr = Base64.encodeToString(bytes, Base64.DEFAULT);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString(GENERATED_KEY, keyStr);
        editor.commit();
        return key.toString();
    }  else {
        return keyStr;
    }

XML-шифрование:

    connection = (HttpURLConnection) url.openConnection();
    connection.connect();
    SecretKey secretKey = getSecretKey(context);
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    spec = generateIv(cipher.getBlockSize());
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, spec);

    input = connection.getInputStream();
    cis = new CipherInputStream(input, cipher);

    String FILEPATH = context.getFilesDir().getParentFile().getPath();
    File file = new File(FILEPATH, "/download/" + id + "/");
       if (!file.exists()) {
    file.mkdirs();
    }

    xmlFile = new File(FILEPATH + "/download/" + id + "/", "xmldata.xml");
    output = new FileOutputStream(xmlFile);
    cos = new CipherOutputStream(output, cipher);
    byte data[] = new byte[4096];
    int count;
    while ((count = cis.read(data)) != -1) {
       if (isCancelled()) throw new TaskCanceledException();
          cos.write(data, 0, count);
          progress = -1;
          publishProgress();
    }
    if (isCancelled()) throw new TaskCanceledException();

Дешифрирование:

public String decryptXml() {
    String data = null;
    File file = new File(context.getFilesDir().getParentFile().getPath() + "/download/" + id + "/xmldata.xml");
    int size = (int) file.length();
    byte[] bytes = new byte[size];
 try {
        SecretKeySpec secretKeySpec = new SecretKeySpec(getSecretKey(context).getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, DownloadBookAsyncTask.spec);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        bis.read(bytes, 0, bytes.length);
        bis.close();
        byte[] decrypted = cipher.doFinal(bytes);
    }

getSecretKey ():

public SecretKey getSecretKey(Context context){
    SharedPreferences sharedPreferences = context.getSharedPreferences(DashboardFragment.GENERATED_KEY, Context.MODE_PRIVATE);
    String stringKey = sharedPreferences.getString(DashboardFragment.GENERATED_KEY, null);
    byte[] encodedKey = Base64.decode(stringKey, Base64.DEFAULT);
    return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
}

РЕДАКТИРОВАТЬ

Добавление метода генератора IV

public AlgorithmParameterSpec generateIv(int size) throws NoSuchAlgorithmException {
    AlgorithmParameterSpec ivspec;
    byte[] iv = new byte[size];
    new SecureRandom().nextBytes(iv);
    ivspec = new IvParameterSpec(iv);
    return ivspec;
}

2 ответа

Решение

Хорошо, я нашел проблему. Причина, по которой мой код не работал, состояла в том, что я использовал CipherInputStream в своем шифровании, и я не должен был этого делать. Я также переделал весь метод расшифровки, который выглядит следующим образом:

  byte[] wholeFileByte = null;
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    cipher.init(Cipher.DECRYPT_MODE, key, DownloadBookAsyncTask.ivspec);
    File file = new File(context.getFilesDir().getParentFile().getPath() + "/download/" + id + "/xmldata.xml");
    FileInputStream fis = new FileInputStream(file);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    CipherInputStream cis = new CipherInputStream(fis, cipher);
    byte data[] = new byte[4096];
    int count;
    while ((count = cis.read(data)) != -1) {
        bos.write(data, 0, count);
    }

    if(cis != null)
        cis.close();
    if(bos != null)
        bos.close();
    if(fis != null)
        fis.close();

    wholeFileByte = bos.toByteArray();
    String kk = new String(wholeFileByte, "UTF-8");

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

Спасибо @GariBN, потому что вы поставили меня на правильный путь и будете голосовать, когда мой представитель позволит мне:)

Вы создаете IV для шифрования открытого текста. Я не уверен, что вы используете тот же IV для расшифровки зашифрованного текста.

Обычно вы хотите объединить IV с зашифрованным текстом, а при расшифровке читать его (первые 16 байтов), а затем расшифровывать все остальные байты (зашифрованный текст) с помощью шифра, который был инициализирован с IV, использованным для шифрования.

Например, если вы шифруете с помощью:

cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, spec);

Сначала попробуйте расшифровать (прямо позже) с помощью:

cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, spec);
cipher.doFinal(bytes)

Если вам это удастся, то проблема, вероятно, из-за неуместного IV, и вы можете легко это исправить.

Другие вопросы по тегам