CipherOutputStream вызывает исключение IllegalBlockSizeException при получении сообщения

#java #encryption

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

Вопрос:

Я пишу серверную / клиентскую систему, которая использует AES. Следующий метод (на стороне сервера) работает нормально:

     public static byte[] encode(byte type, byte subType, String string, Cipher cipher) 
    throws NullPointerException, IOException {
        
        Objects.requireNonNull(string);
        Objects.requireNonNull(cipher);
                
        byte[] data = null;
        
        try {
            data = string.getBytes(StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e1) {};
        
        ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream();
        bytesOutput.write(type);
        bytesOutput.write(subType);
        bytesOutput.write(data);
        
        byte[] plainBytes = bytesOutput.toByteArray();
        byte[] bytes = null;
        
        try {
            bytes = cipher.doFinal(plainBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        byte[] base64Bytes = Base64.getEncoder().encode(bytes);
                
        return base64Bytes; 
    }
 

Но когда я заменил его следующим кодом, я получил исключение IllegalBlockSizeException на стороне клиента.

 public static byte[] encode(byte type, byte subType, String string, Cipher cipher) 
throws NullPointerException, EncodingException {
                
        Objects.requireNonNull(string);
        Objects.requireNonNull(cipher);
                
        byte[] data = null;
                
        try {
            data = string.getBytes(StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e1) {};

        CipherOutputStream cipherOutput = null;

        try {
            ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream();
            OutputStream base64Output = Base64.getEncoder().wrap(bytesOutput);
            cipherOutput = new CipherOutputStream(base64Output, cipher);
            cipherOutput.write(type);
            cipherOutput.write(subType);
            cipherOutput.write(data);
            cipherOutput.flush();
                    
            byte[] bytes = bytesOutput.toByteArray();
            
            return bytes;

        } catch (IllegalStateException | IOException e) {
            throw new EncodingException(e);

        } finally {

            if (cipherOutput != null)
                try {
                    cipherOutput.close();
                } catch (IOException e) {};
            }
        }
}
 

Что не так со вторым методом? Оба метода используют один и тот же шифр. На сервере ничего не изменилось, за исключением метода encode.

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

1. Вы должны закрыть CipherOutputStream, прежде чем извлекать байты из ByteOutputStream. Только в методе close() объект cipher завершается. Кроме того, поступая таким образом, вы существенно упростите обработку исключений.

2. Спасибо! Проверено — работает.

3. И если вы хотите использовать еще меньше обработки ошибок, замените UTF_8.name() на just UTF_8 .