Шифрование с помощью pgcrypto
Вы можете использовать дополнительный модуль pgcrypto, который предоставляет криптографические функции в Postgres для шифрования определенных полей базы данных. Этот подход применяется, если часть данных является конфиденциальной. Pgcrypto содержит хеширующие и криптографические функции, позволяющие шифровать данные с помощью криптографических алгоритмов с симметричным и открытым ключом, хешировать пароли и получать случайные данные.
Ограничения безопасности
Все функции pgcrypto выполняются на сервере базы данных. Данные и пароли передаются между pgcrypto и клиентскими приложениями открытым текстом, поэтому следует подключаться локально или использовать SSL-подключения. Если это невозможно, лучше произвести шифрование внутри клиентского приложения.
Обратите внимание, что защита данных с помощью pgcrypto уязвима для атак по сторонним каналам.
Согласно стандарту SQL, все функции pgcrypto возвращают NULL, если любой из аргументов равен NULL. Это может привести к угрозе безопасности при неосторожном использовании.
Установка pgcrypto
Pgcrypto входит в расширение contrib, которое предустановлено в ADPG. За дополнительной информацией обратитесь к статье Работа с расширениями.
Модуль pgcrypto является доверенным, пользователи с привилегией CREATE в текущей базе данных могут установить этот модуль.
Следующая команда устанавливает pgcrypto:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
Поддерживаемые алгоритмы
Поддерживаются следующие алгоритмы:
-
MD5;
-
SHA1;
-
SHA224/256/384/512;
-
другие алгоритмы хеширования, поддерживаемые OpenSSL, за исключением шифров, которые должны поддерживаться явно;
-
Blowfish;
-
AES;
-
DES/3DES/CAST5;
-
шифрование низкого уровня;
-
PGP-шифрование с симметричным ключом;
-
PGP-шифрование с открытым ключом.
Функции pgcrypto
Модуль pgcrypto включает криптографические функции. Вы можете использовать их для хеширования данных, хеширования паролей, криптографической защиты данных с помощью симметричных и открытых ключей (PGP) и алгоритмов шифрования низкого уровня, получения случайных данных.
Стандартные функции хеширования
digest()
digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea
Функция вычисляет двоичный хеш данных.
Параметр type
определяет используемый алгоритм. Стандартными алгоритмами являются md5
, sha1
, sha224
, sha256
, sha384
и sha512
. Вы также можете использовать любой поддерживаемый алгоритм. В приведенном ниже примере digest
генерирует двоичный хеш поля key_code
.
CREATE TABLE table1( key_code text, hash bytea );
CREATE OR REPLACE FUNCTION update_table1() RETURNS trigger AS $$
BEGIN
NEW.hash = digest(NEW.key_code, 'sha256');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER table1_hash_insert
BEFORE INSERT ON table1
FOR EACH ROW
EXECUTE PROCEDURE update_table1();
CREATE TRIGGER table1_hash_update
BEFORE UPDATE ON table1
FOR EACH ROW
WHEN ( NEW.key_code IS DISTINCT FROM OLD.key_code )
EXECUTE PROCEDURE update_table1();
Вы можете использовать функцию encode
для преобразования двоичной строки в шестнадцатеричную:
SELECT encode(digest('MyPassword','sha256'),'hex');
hmac()
hmac(data text, key text, type text) returns bytea
hmac(data bytea, key bytea, type text) returns bytea
Функция вычисляет имитовставку (message authentication code) для данных параметра data
с ключом, указанным в параметре key
. Параметр type
определяет используемый алгоритм.
Hmac
похожа на digest
, но вычислить хеш с ней можно, только зная ключ. Это защищает от сценария подмены данных вместе с хешем.
SELECT hmac('MyPassword', 'My_key', 'sha256');
Если размер ключа больше размера блока хеша, он сначала хешируется, а затем используется в качестве ключа хеширования данных.
Функции хеширования паролей
Функции crypt
и gen_salt
разработаны специально для хеширования паролей. Функция crypt
выполняет хеширование, а gen_salt
подготавливает параметры для нее.
Алгоритмы в crypt
отличаются от обычных алгоритмов хеширования MD5 и SHA1 и имеют следующие особенности:
-
Они медленные. Так как объем данных небольшой, это единственный способ усложнить подбор пароля методом перебора.
-
Они используют случайное значение, называемое соль (salt), чтобы у пользователей с одинаковыми паролями хеши паролей были разными.
-
Они включают в результат тип алгоритма, что допускает сосуществование паролей, хешированных разными алгоритмами.
-
Некоторые из них являются адаптируемыми — их алгоритмы можно настроить так, чтобы они стали медленнее, если производительность компьютера возросла. При этом сохраняется совместимость с существующими паролями.
В таблице ниже перечислены поддерживаемые алгоритмы.
Название | Максимальная длина пароля | Адаптивность | Размер соли (бит) | Размер результата | Описание |
---|---|---|---|---|---|
bf |
72 |
да |
128 |
60 |
На базе Blowfish, вариация 2a |
md5 |
Без ограничений |
нет |
48 |
34 |
На базе MD5 |
xdes |
8 |
да |
24 |
20 |
Расширенный DES |
des |
8 |
нет |
12 |
13 |
Изначальный crypt из UNIX |
crypt()
crypt(password text, salt text) returns text
Функция вычисляет хеш пароля, передаваемого как параметр password
в стиле crypt(3). Используйте gen_salt
для генерации значения соли при сохранении пароля. В следующем примере показано, как установить новый пароль с использованием функции crypt
:
UPDATE table1 SET password_hash = crypt('new_password', gen_salt('md5'));
Запрос, приведенный ниже, извлекает данные для аутентификации и возвращает true
, если введенный пароль правильный:
SELECT (password_hash = crypt('entered_password', password_hash)) AS password_match FROM table1;
gen_salt()
gen_salt(type text [, iter_count integer ]) returns text
Эта функция генерирует новую случайную строку соли для использования в crypt
. Строка соли также определяет какой алгоритм будет использовать crypt
. Параметр type
определяет алгоритм хеширования. Возможные значения: des
, xdes
, md5
и bf
.
Параметр iter_count
указывает количество итераций для алгоритмов xdes и bf. Чем больше значение, тем больше времени требуется для хеширования пароля и тем больше времени потребуется для его взлома. При слишком большом значении время расчета может составлять несколько лет. Если параметр iter_count
опущен, используется значение по умолчанию. В приведенной ниже таблице содержатся допустимые значения для iter_count
. Алгоритм xdes имеет дополнительное ограничение — число итераций должно быть нечетным.
Алгоритм | Значение по умолчанию | Минимум | Максимум |
---|---|---|---|
xdes |
725 |
1 |
16777215 |
bf |
6 |
4 |
31 |
Функции шифрования PGP
Функции шифрования PGP реализуют часть стандарта OpenPGP (RFC 4880), относящуюся к шифрованию. Они поддерживают шифрование как с симметричным, так и с открытым ключом.
Зашифрованное сообщение PGP состоит из 2 частей или пакетов (packets):
-
Пакет, содержащий ключ сессии (симметричный или открытый ключ).
-
Пакет, содержащий данные, зашифрованные ключом сессии.
Когда шифрование выполняется с помощью симметричного ключа (пароля), для хеширования пароля используется алгоритм String2Key (S2K). S2K похож на алгоритмы шифрования, он намеренно замедленный и добавляет случайное значение соли. S2K создает на выходе полноразмерный двоичный ключ. Если запрашивается отдельный ключ сессии, генерируется новый случайный ключ. Если не запрашивается, в качестве ключа сессии используется ключ S2K. Если ключ S2K является ключом сессии, пакет ключа сессии содержит только параметры S2K. В противном случае ключ сессии шифруется ключом S2K и помещается в пакет ключа сессии.
Когда шифрование выполняется с помощью открытого ключа, генерируется новый случайный ключ сессии. Ключ сессии шифруется открытым ключом и помещается в пакет ключа сессии. Генерация ключей шифрования PGP описана в разделе Генерация ключей PGP с применением GnuPG.
Шифрование данных включает следующие этапы:
-
Подготовка данных (необязательно): сжатие, перекодировка в UTF-8, преобразование концов строк.
-
Перед данными добавляется блок случайных байтов.
-
Добавляется хеш SHA1 случайного префикса, добавленного на предыдущем шаге, и данных.
-
Все, что было добавлено, шифруется вместе с данными ключом сессии и помещается в пакет данных.
pgp_sym_encrypt()
pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea
Функция шифрует данные симметричным ключом PGP. Параметр data
— данные для шифрования, psw
— симметричный ключ PGP. Параметр options
содержит опции настройки, разделенные запятыми. В таблице ниже перечислены доступные опции.
Название | Описание | Значение по умолчанию | Допустимые значения |
---|---|---|---|
cipher-algo |
Алгоритм шифрования |
aes128 |
bf, aes128, aes192, aes256; только для openSSL: 3des, cast5 |
compress-algo |
Алгоритм сжатия |
0 |
|
compress-level |
Уровень сжатия. Чем больше уровень, тем меньшего объема результат, но длительнее процесс сжатия. Значение |
6 |
0-9 |
convert-crlf |
Определяет преобразовывать ли |
0 |
|
disable-mdc |
Не защищать данные хешем SHA-1. Используйте этот параметр только для поддержания совместимости со старыми продуктами PGP |
0 |
|
sess-key |
Использовать отдельный ключ сессии |
0 |
|
s2k-mode |
Алгоритм S2K |
3 |
|
s2k-count |
Число итераций для алгоритма S2K. Чтобы эта настройка применилась, |
Случайное значение между 65536 и 253952 |
Значение между 1024 и 65011712 |
s2k-digest-algo |
Алгоритм хеширования, который будет использоваться для вычисления S2K |
sha1 |
md5, sha1 |
s2k-cipher-algo |
Шифр для шифрования отдельного ключа сессии |
Значение параметра |
bf, aes, aes128, aes192, aes256 |
unicode-mode |
Определяет, преобразовывать ли текстовые данные из внутренней кодировки базы данных в UTF-8 и обратно. Если кодировка базы уже UTF-8, перекодировка не производится, но сообщение помечается как UTF-8, без данного параметра этого не происходит |
0 |
|
Пример:
CREATE TABLE users (user_id serial PRIMARY KEY, username VARCHAR(50), password TEXT);
INSERT INTO users (username, password) VALUES ('Robert',pgp_sym_encrypt('password', 'aes_key', 'compress-algo=1, cipher-algo=aes256'));
pgp_sym_decrypt()
pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea
Функция расшифровывает сообщение PGP, зашифрованное с помощью симметричного ключа. Параметр msg
— сообщение для расшифровки, psw
— симметричный ключ PGP. Параметр options
содержит опции настройки. В таблице ниже перечислены доступные опции.
Название | Описание | Значение по умолчанию | Допустимые значения |
---|---|---|---|
convert-crlf |
Определяет преобразовывать ли |
0 |
|
Пример:
SELECT username, pgp_sym_decrypt(password::bytea, 'aes_key') as password
FROM users WHERE (username LIKE '%Robert%');
pgp_pub_encrypt()
pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea
Функция шифрует данные с помощью открытого ключа PGP. Если передать этой функции секретный ключ, произойдет ошибка. Используйте функцию pgp_sym_decrypt_bytea
для шифрования данных bytea. Вы также можете использовать pgp_pub_encrypt_bytea
для шифрования текстовых данных.
Параметр data
— данные для шифрования, key
— открытый ключ PGP. Параметр options
содержит опции настройки, разделенные запятыми. В таблице ниже перечислены доступные опции.
Название | Описание | Значение по умолчанию | Допустимые значения |
---|---|---|---|
cipher-algo |
Алгоритм шифрования |
aes128 |
bf, aes128, aes192, aes256; только для openSSL: 3des, cast5 |
compress-algo |
Алгоритм сжатия |
0 |
|
compress-level |
Уровень сжатия. Чем больше уровень, тем меньшего объема результат, но длительнее процесс сжатия. Значение |
6 |
0-9 |
convert-crlf |
Определяет преобразовывать ли |
0 |
|
unicode-mode |
Определяет, преобразовывать ли текстовые данные из внутренней кодировки базы данных в UTF-8 и обратно. Если кодировка базы уже UTF-8, перекодировка не производится, но сообщение помечается как UTF-8, без данного параметра этого не происходит |
0 |
|
Пример:
INSERT INTO users (username, password) VALUES ('Robert',pgp_pub_encrypt('password', dearmor('-----BEGIN PGP PUBLIC KEY BLOCK-----XXX-----END PGP PUBLIC KEY BLOCK-----')));
В этом примере функция dearmor переводит двоичные данные из формата PGP ASCII-armor.
pgp_pub_decrypt()
pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea
Функция расшифровывает сообщение, зашифрованное с помощью открытого ключа. Используйте функцию pgp_pub_decrypt_bytea
для расшифровки данных bytea. Вы также можете использовать pgp_pub_decrypt_bytea
для расшифровки текстовых данных.
Параметр msg
— сообщение для расшифровки, key
содержит секретный ключ, соответствующий открытому ключу, используемому для шифрования. Если секретный ключ защищен паролем, передайте пароль в качестве параметра psw
. Если пароля нет, но необходимо указать опции, используйте пустой пароль. Параметр options
содержит настройки опций. В таблице ниже перечислены доступные опции.
Название | Описание | Значение по умолчанию | Допустимые значения |
---|---|---|---|
convert-crlf |
Определяет преобразовывать ли |
0 |
|
Пример:
SELECT pgp_pub_decrypt(password::bytea,dearmor('-----BEGIN PGP PRIVATE KEY BLOCK-----XXXX-----END PGP PRIVATE KEY BLOCK-----'),'PRIVATE-KEY-PASSWORD') AS password FROM users;
В этом примере функция dearmor переводит двоичные данные из формата PGP ASCII-armor.
pgp_key_id()
pgp_key_id(bytea) returns text
Функция возвращает идентификатор открытого или секретного ключа PGP. Она также извлекает идентификатор ключа, который используется для шифрования данных, если в качестве параметра передается зашифрованное сообщение.
Pgp_key_id
может возвращать два специальных идентификатора ключа:
-
SYMKEY
— сообщение зашифровано симметричным ключом. -
ANYKEY
— сообщение зашифровано открытом ключом, но идентификатор ключа удален.
Разные ключи могут иметь одинаковый идентификатор. В таком случае клиентское приложение должно пытаться расшифровать данные с каждым доступным ключом, пока не найдет подходящий.
armor(), dearmor()
armor(data bytea [ , keys text[], values text[] ]) returns text
dearmor(data text) returns bytea
Функции переводят двоичные данные в/из формата PGP "ASCII Armor", представляющего собой кодировку Base64 с контрольными суммами и дополнительным форматированием.
Если задаются массивы keys
и values
, для каждой пары ключ/значение добавляется заголовок Armor. Оба массива должны быть одномерными и иметь одинаковую длину. Задаваемые ключи и значения могут содержать только символы ASCII.
Генерация ключей PGP с применением GnuPG
Вы можете использовать инструмент GnuPG для создания ключей PGP. Выполните следующую команду, чтобы сгенерировать новый ключ:
gpg --gen-key
Терминал предложит выбрать тип ключа:
Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) Your selection?
Предпочтительный тип ключа — DSA и Elgamal
. Для шифрования RSA необходимо создать ключ DSA (sign only)
или RSA (sign only)
в качестве главного, а затем добавить подключ для шифрования с помощью команды gpg --edit-key
.
Выполните следующую команду, чтобы получить список ключей:
gpg --list-secret-keys
Экспорт открытого ключа в формате "ASCII Armor":
gpg -a --export KEYID > public.key
Экспорт закрытого ключа в формате "ASCII Armor":
gpg -a --export-secret-keys KEYID > secret.key
Примените функцию dearmor для этих ключей, прежде чем передавать их функциям PGP. Если вы можете обрабатывать двоичные данные, вы также можете опустить параметр -a
в команде gpg
.
Низкоуровневые функции шифрования
Эти функции выполняют только шифрование данных и не предоставляют дополнительных возможностей шифрования PGP. Таким образом, с ними связаны следующие проблемы:
-
Использование ключа пользователя в качестве ключа шифрования.
-
Отсутствие проверки целостности, которая должна выявлять модификацию зашифрованных данных.
-
Пользователи должны управлять всеми параметрами шифрования самостоятельно, включая вектор инициализации.
-
Функции не работают с текстовыми данными.
ВНИМАНИЕ
Использование низкоуровневых функций шифрования не рекомендуется. Используйте
функции шифрования PGP вместо них.
|
Низкоуровневые функции зашифровывают и расшифровывают данные, применяя метод шифрования, заданный параметром type
.
encrypt(data bytea, key bytea, type text) returns bytea
decrypt(data bytea, key bytea, type text) returns bytea
encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
Строка type
имеет следующий формат:
алгоритм [ - режим ] [ /pad: дозаполнение ]
В таблице ниже приведены возможные значения параметров.
Название | Значение |
---|---|
алгоритм |
|
режим |
|
дозаполнение |
|
Следующие вызовы функций равнозначны:
encrypt(data, 'fooz', 'bf')
encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
Для функций encrypt_iv
и decrypt_iv
параметр iv
задает начальное значение для режима CBC, для ECB он игнорируется. Это значение обрезается или дополняется нулями, если его размер не равен размеру блока. В функциях без этого параметра оно по умолчанию заполняется нулями.