Ошибка расшифровки: блок Pad поврежден - PullRequest
7 голосов
/ 30 декабря 2010

У меня есть следующий код.

    byte[] input = etInput.getText().toString().getBytes();
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");

    // encryption pass
    cipher.init(Cipher.ENCRYPT_MODE, key);

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
    ctLength += cipher.doFinal(cipherText, ctLength);

    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);

    String strLength = new String(cipherText,"US-ASCII");
    byte[] byteCiphterText = strLength.getBytes("US-ASCII");
    Log.e("Decrypt", Integer.toString(byteCiphterText.length));

    etOutput.setText(new String(cipherText,"US-ASCII"));

    cipherText  = etOutput.getText().toString().getBytes("US-ASCII");
    Log.e("Decrypt", Integer.toString(cipherText.length));

    ptLength += cipher.doFinal(plainText, ptLength);
    Log.e("Decrypt", new String(plainText));
    Log.e("Decrypt", Integer.toString(ptLength));

Работает отлично. Но однажды я превращаю это в класс. В этой строке всегда встречается ошибка.

 ptLength += cipher.doFinal(plainText, ptLength);

 Error:Pad block corrupted

Я проверил, и оба кода абсолютно одинаковы. Даже значение, переданное в строке преобразования во все байты, ничем не отличается от кода выше. Есть идеи, что не так с кодом?

public String Encrypt(String strPlainText) throws Exception, NoSuchProviderException,
        NoSuchPaddingException {
    byte[] input = strPlainText.getBytes();
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");

    // encryption pass
    cipher.init(Cipher.ENCRYPT_MODE, key);

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
    ctLength += cipher.doFinal(cipherText, ctLength);

    return new String(cipherText, "US-ASCII");
}

public String Decrypt(String strCipherText) throws Exception,
        NoSuchProviderException, NoSuchPaddingException {
    byte[] cipherText = strCipherText.getBytes("US-ASCII");
    int ctLength = cipherText.length;
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");

    // decryption pass
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
    ptLength += cipher.doFinal(plainText, ptLength);

    return new String(plainText);
}

Ответы [ 3 ]

5 голосов
/ 30 декабря 2010

Как сказал Ян Рамин, использование String является ошибкой для шифрования ввода / вывода.Это двоичные данные, которые

  • могут содержать 0x00
  • и могут содержать значения, которые не определены или не соответствуют странным местам в используемой кодировке

Использовать обычныйbyte [], как в первом примере, или используйте шестнадцатеричное или base64-кодирование байта [].

// this is a quick example - dont use sun.misc inproduction
//  - go for some open source implementation
String encryptedString = new sun.misc.BASE64Encoder.encodeBuffer(encryptedBytes);

Эта строка может быть безопасно передана и преобразована обратно в байты.

EDIT

Пожалуй, самый безопасный способ справиться с проблемой длины - всегда использовать потоковую реализацию (IMHO):

Пример

static public byte[] decrypt(Cipher cipher, SecretKey key, byte[]... bytes)
        throws GeneralSecurityException, IOException {
    cipher.init(Cipher.DECRYPT_MODE, key);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    for (int i = 0; i < bytes.length; i++) {
        bos.write(cipher.update(bytes[i]));
    }
    bos.write(cipher.doFinal());
    return bos.toByteArray();
}
1 голос
/ 30 декабря 2010

Вы указали отступ PKCS7.Сохраняется ли ваш отступ при хранении в вашем объекте String?Является ли ваш строковый объект соответствием 1: 1 с байтами, выводимыми шифром?В общем случае String не подходит для передачи двоичных данных, таких как вывод шифра.

0 голосов
/ 30 декабря 2010

В вашем случае шифр использует заполнение, то есть, другими словами, входные данные будут дополняться / округляться в блоки с некоторым заранее заданным размером (который зависит от алгоритма заполнения). Допустим, вы предоставили 500 байтов для шифрования, размер блока заполнения составляет 16 байтов, поэтому зашифрованные данные будут иметь размер 512 байтов (32 блока) - 12 байтов будут дополнены.

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

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