Криптографическое расширение Java содержит класс Cipher, который является суперклассом всех классов, имеющих отношение к шифрованию. Для создания объекта, реализующего алгоритм шифрования, используется метод getInstance():
1 2 |
Cipher cipher = Cipher.getInstance(algorithmName); Cipher cipher = Cipher.getInstance(algorithmName, providerName); |
В JDK для всех шифров используется поставщик SunJCE. Если имя поставщика не указано явно, то по умолчанию принимается имя SunJCE. Если вы хотите воспользоваться алгоритмами, которые не поддерживаются инструментами Sun, следует указать другого поставщика.
Имя алгоритма задается в виде строки, например «DES» или «DES/CBC/PKCS5Padding».Алгоритм DES(Data Encryption Standard — стандарт шифрования данных) — это один из наиболее старых алгоритмов шифрования с длинной ключа в 56 бит. В настоящее время он считается устаревшим, поскольку может взламываться путем применения метода грубой силы(пример можно найти по адресу https://w2.eff.org/Privacy/Crypto/Crypto_misc/DESCracker/).
Гораздо более эффективным вариантом является появившийся после него алгоритм AES(Advanced Encryption Standard — расширенный стандарт шифрования), подробное описание которого можете найти по ссылке http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
В рассматриваемых здесь примерах мы будет использовать алгоритм AES.
После создания реализующего алгоритм шифрования объекта его нужно инициализировать путем указания режима и ключа(то есть путем установки параметров mode и key):
1 2 3 |
int mode = ...; Key key = ...; cipher.init(mode, key); |
Параметр mode может иметь одно из следующих значений:
1 2 3 4 |
Cipher.ENCRYPT_MODE Cipher.DECRYPT_MODE Cipher.WRAP_MODE Cipher.UNWRAP_MODE |
Режимы свертки(wrap) и развертки(unwrap) применяются для шифрования одного ключа на основе другого. Пример использования таких режимов будет приведен в следующих статьях.
После этого можно повторно вызвать метод update() для выполнения шифрования всех требующихся блоков данных:
1 2 3 4 5 6 7 |
int blockSize = cipher.getBlockSize(); byte[] inBytes = new byte[blockSize]; ... // Чтение inBytes. int outputSize = cipher.getOutputSize(inLength); byte[] outBytes = new byte[outputSize]; int outLength = cipher.update(inBytes, 0, outputSize, outBytes); ... // Запись outBytes. |
По завершении нужно обязательно один раз вызвать метод doFinal(). Если доступен последний блок входных данных(меньшего, чем указанно blockSize, объема), тогда вызов должен выглядеть следующим образом:
1 |
outBytes = cipher.doFinal(inBytes, 0, inLength); |
А если были зашифрованы все входные данные, тогда этот вызов должен выглядеть так:
1 |
outBytes = cipher.doFinal(); |
Вызов метода doFinal() необходим для дополнения(padding) заключительного блока данных. Например, возьмем алгоритм шифрования DES. В этом алгоритме размер блока составляет 8 байт. Предположим, что размер последнего блока входных данных оказывается менее 8 байт. Конечно, мы можем дополнить недостающие байты нулями так, чтобы он занимал 8 байт и зашифровать его. Но тогда при расшифровке блоков результат будет содержать в конце несколько присоединенных нулей и, следовательно, немного отличаться от исходного файла входных данных.
Это может представлять проблему, и для ее устранения как раз и необходима схема дополнения(padding scheme). Одной из наиболее часто применяемых схем дополнения является схема, описанная в документе Public Key Cryptography Standard(PKCS) #5 специалистами из RSA Security Inc. Вот из ссылочка http://www.emc.com/domains/rsa/index.htm.
В этой схеме последний блок дополняется не нулями, а числами, равными недостающему количеству байтов. Другими словами, если L представляет собой последний(неполный) блок, тогда он будет дополнен следующим образом:
1 2 3 4 5 |
L 01 Если length(L) = 7 L 02 02 Если length(L) = 6 L 03 03 03 Если length(L) = 5 ... L 07 07 07 07 07 07 07 Если length(L) = 1 |
И, наконец, если длина входных данных фактически может быть поделена на 8, тогда к выходным данным присоединяется и шифруется только один такой блок:
1 |
08 08 08 08 08 08 08 08 |
При расшифровке на количество подлежащих отсечению дополнительных символов указывает самый последний байт простого текста.