Как создать ключ AES с помощью AES / CBC / PKCS5Padding для шифрования и дешифрования - PullRequest
1 голос
/ 29 октября 2019

Я пытаюсь создать ключ AES с этим кодом

    public static SecretKey generateSecretKey() {

        KeyGenerator generator;
        try {

            generator = KeyGenerator.getInstance(StaticHandler.AES_KEY_MODE); // Is "AES"
            generator.init(StaticHandler.AES_KEY_SIZE); // The AES key size in number of bits // Is "128"

            return generator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

, однако, используя этот код для шифрования / дешифрования


    public static String encrypt(String data, SecretKey secret, Charset charset) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secret);

            return new String(cipher.doFinal(data.getBytes()), charset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static String decrypt(String data, @NonNull SecretKey secret, Charset charset) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secret);

            return new String(cipher.doFinal(data.getBytes()), charset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

выдает ошибку java.security.InvalidKeyException: Parameters missing

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

Редактировать: просто подумав, стоит ли использовать шифрование GCM или CBC, если я отправляю пакеты черезсеть? Помните, что я использую случайно сгенерированные ключи и не собираюсь хранить их для сессий, сгенерированных случайным образом для каждого сеанса клиента и сервера.

1 Ответ

1 голос
/ 29 октября 2019

Нет, вам не нужна соль, и ваш ключ в порядке. Режим CBC требует IV (вектор инициализации), см. Википедию , и IV должен быть разным для каждого зашифрованного фрагмента данных, но для каждого дешифрования должно использоваться то же значение, что и для соответствующего шифрования,(добавлено) Для Си-би-си, хотя и не для некоторых других режимов, для безопасности также важно, чтобы противник не предсказывал IV;Самый простой и наиболее распространенный способ достижения как уникальности, так и непредсказуемости - это использовать безопасный генератор случайных чисел (он же бит), такой как Java SecureRandom. Если вы хотите узнать о других методах, это не является проблемой программирования и лучше подходит для crypto.SX или security.SX, где уже есть несколько Qs.

Вы можете либо сгенерировать IV явно и указать его для шифрования и дешифрования, либо разрешить операции шифрования генерировать сам IV, извлечь его из зашифрованного шифра и указать его для дешифрования шифра. В любом случае шифровщик должен предоставить значение, которое будет использовать расшифровщик;Обычный подход состоит в том, чтобы просто объединить IV с зашифрованным текстом (что позволяет очень легко поддерживать их соответствие), но опять же есть другие подходы, обсуждаемые в области криптографии и безопасности. См. https://docs.oracle.com/en/java/javase/11/security/java-cryptography-architecture-jca-reference-guide.html в разделах «Инициализация объекта шифрования» (два абзаца сразу после блока описаний методов в штучной упаковке) и «Управление параметрами алгоритма».


Также не храните зашифрованный текст в String. Java String предназначена для обработки допустимых символов, а не произвольных байтов. «Декодирование» зашифрованного текста в строку и «кодирование» его обратно в двоичный код почти всегда приведет к потере или изменению некоторых данных, особенно если вы позволите Charset различаться на двух концах, а в современной криптографии - любое изменение в зашифрованном тексте. уничтожит все или большую часть ваших данных. Поскольку зашифрованный текст составляет байт, лучше всего обрабатывать его как byte[];если это невозможно, потому что вы хотите поместить его в то, что равно символам, таким как URL, используйте одну из многих схем, разработанных для кодирования произвольных байтов в текст, чтобы их можно было правильно восстановить: base64 (3или 4 основных варианта, плюс много второстепенных), base32, шестнадцатеричное / base16, кодирование URL-адреса в процентах, MIME, цитируемый для печати, yencode, Kermit, PPP и т. д. j8 + java.util.Base64 предоставляет более новую base64варианты (т. е. не uuencode).

И наоборот, хотя «открытый текст» в современной криптографии действительно может быть любой формой данных, если ваш действительно текст и принадлежит к String, вам следуетзакодируйте его с помощью подходящего Charset перед шифрованием и декодируйте, используя то же самое Charset после расшифровки, то есть

 byte[] ctext = encCipher.doFinal (input.getBytes(charset));
 ...
 String output = new String (decCipher.doFinal (ctext), charset);

Хотя «лучший» Charset может отличаться в зависимости от ваших данных, если вы неНе знаю, какими будут данные, или не хотите их анализировать, UTF-8 достаточно хорош для большинства текстовых данных и очень популярен и стандартен.

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