Java CipherInputStream Исключение NegativeArrayIndexException при закрытии ()

#java #encryption #aes

#java #шифрование #aes

Вопрос:

У меня проблема с простой реализацией дешифрования с использованием CipherInputStream и стандартного 128-битного AES-шифра. Код приведен ниже (переменная экземпляра buf представляет собой простой массив длиной 1024 байта, используемый в качестве буфера):

 public void decrypt(InputStream in, OutputStream out) {
    CipherInputStream cin = null;
    try {
        // Bytes read from in will be decrypted
        cin = new CipherInputStream(in, dcipher);
        // Read in the decrypted bytes and write the result to out
        int numRead = 0;
        while ((numRead = cin.read(buf)) >= 0) {
            out.write(buf, 0, numRead);
        }
    } catch (IOException e) {
        log.error("Exception in decryption of inputstream!", e);
    } finally {
        try {
            if (cin != null) cin.close();
        } catch (IOException ioe) {
            log.error("Exception in closing CipherInputStream!", ioe);
        }
    }
}
  

Кажется, что сервер, который выполнил шифрование и сохранил результат в базе данных, всегда может успешно расшифровать данные и поток. Однако, если другой сервер извлекает зашифрованные данные и пытается их расшифровать, он, похоже, работает успешно, пока не попытается закрыть CipherInputStream. Следующее исключение возникает при cin.close() .

 java.lang.NegativeArraySizeException
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
    at javax.crypto.Cipher.doFinal(DashoA13*..)
    at javax.crypto.CipherInputStream.close(DashoA13*..)
    at com.company.util.Encryptor.decrypt(Encryptor.java:104)
    ...
  

Интересно, что это происходит в doFinal, это заставило бы меня думать, что это не сделано, делая что-то до его закрытия. Я не уверен, что это значит. Мне также интересно, является ли тот факт, что он всегда работает на сервере шифрования, просто совпадением (это повторяется на разных рабочих станциях)?

Любая информация была бы полезна.

РЕДАКТИРОВАТЬ: я добавляю код для создания объектов Cipher. На самом деле ничего особенного, но мне интересно, связано ли это со статическим классом и синглтоном в контексте веб-приложения без состояния? По крайней мере, я полагаю, что это бессмысленно, поскольку этот одноэлементный служебный класс в любом случае необходимо будет повторно устанавливать при каждом запросе…

 String key = PropertyManager.getInstance().getProperty("phikey");
    try {
        ecipher = Cipher.getInstance("AES");
        dcipher = Cipher.getInstance("AES");
        byte[] raw = new BASE64Decoder().decodeBuffer(key);
        SecretKey skey = new SecretKeySpec(raw, "AES");
        ecipher.init(Cipher.ENCRYPT_MODE, skey);
        dcipher.init(Cipher.DECRYPT_MODE, skey);
    } catch (NoSuchAlgorithmException e) {
        log.error("No encryption algorithm present!", e);
    } catch (NoSuchPaddingException e) {
        log.error("No such padding for encryption!", e);
    } catch (InvalidKeyException e) {
        log.error("Invalid key exception!", e);
    } catch (IOException e) {
        log.error("Unable to decode encryption key!", e);
    }
  

Обновить:

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

Комментарии:

1. Вы уверены, что экземпляры Cipher на обоих серверах были созданы с одинаковыми именами преобразований, особенно с одинаковыми спецификациями заполнения?

2. @axtavt Я добавил больше кода и описания выше… я бы подумал, что он должен использовать тот же ключ и дополнение?

3. Хорошо, я не уверен, но, возможно, ключ имеет неправильную длину. Заменить SecretKeySpec на PBEKeySpec , поскольку первый не проверяет правильность ключа.

4. Это был бы хороший тест: сравнить raw массив на каждом сервере, а также вывод skey.getEncoded and skey.getFormat .

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