Шифрование

Вы можете использовать дополнительный модуль 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.

Шифрование данных включает следующие этапы:

  1. Подготовка данных (необязательно): сжатие, перекодировка в UTF-8, преобразование концов строк.

  2. Перед данными добавляется блок случайных байтов.

  3. Добавляется хеш SHA1 случайного префикса, добавленного на предыдущем шаге, и данных.

  4. Всё, что было добавлено, шифруется вместе с данными ключом сессии и помещается в пакет данных.

 

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

0 — без сжатия, 1 — сжатие ZIP, 2 — сжатие ZLIB

compress-level

Уровень сжатия. Чем больше уровень, тем меньшего объёма результат, но длительнее процесс сжатия. Значение 0 отключает сжатие

6

0-9

convert-crlf

Определяет преобразовывать ли \n в \r\n при шифровании и \r\n в \n при дешифровании. В стандарте RFC 4880 требуется, чтобы текстовые данные хранились с переводами строк в виде \r\n. Используйте этот параметр, чтобы привести хранение данных в полное соответствие со стандартом RFC

0

0 — не преобразовывать, 1 — преобразовывать

disable-mdc

Не защищать данные хешем SHA-1. Используйте этот параметр только для поддержания совместимости со старыми продуктами PGP

0

0 — защищать данные хешем SHA-1, 1 — отключить защиту

sess-key

Использовать отдельный ключ сессии

0

0 — использовать ключ S2K в качестве ключа сессии, 1 — использует отдельный ключ сессии

s2k-mode

Алгоритм S2K

3

0 — без соли (не рекомендуется), 1 —  с солью и фиксированным числом итераций, 3 — с солью и переменным числом итераций

s2k-count

Число итераций для алгоритма S2K. Чтобы эта настройка применилась, s2k-mode должен быть равен 3

Случайное значение между 65536 и 253952

Значение между 1024 и 65011712

s2k-digest-algo

Алгоритм хеширования, который будет использоваться для вычисления S2K

sha1

md5, sha1

s2k-cipher-algo

Шифр для шифрования отдельного ключа сессии

Значение параметра cipher-algo

bf, aes, aes128, aes192, aes256

unicode-mode

Определяет, преобразовывать ли текстовые данные из внутренней кодировки базы данных в UTF-8 и обратно. Если кодировка базы уже UTF-8, перекодировка не производится, но сообщение помечается как UTF-8, без данного параметра этого не происходит

0

0 — не преобразовывать, 1 — преобразовывать

Пример:

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

Определяет преобразовывать ли \n в \r\n при шифровании и \r\n в \n при дешифровании. В стандарте RFC 4880 требуется, чтобы текстовые данные хранились с переводами строк в виде \r\n. Используйте этот параметр, чтобы привести хранение данных в полное соответствие со стандартом RFC

0

0 — не преобразовывать, 1 — преобразовывать

Пример:

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

0 — без сжатия, 1 — сжатие ZIP, 2 — сжатие ZLIB

compress-level

Уровень сжатия. Чем больше уровень, тем меньшего объёма результат, но длительнее процесс сжатия. Значение 0 отключает сжатие

6

0-9

convert-crlf

Определяет преобразовывать ли \n в \r\n при шифровании и \r\n в \n при дешифровании. В стандарте RFC 4880 требуется, чтобы текстовые данные хранились с переводами строк в виде \r\n. Используйте этот параметр, чтобы привести хранение данных в полное соответствие со стандартом RFC

0

0 — не преобразовывать, 1 — преобразовывать

unicode-mode

Определяет, преобразовывать ли текстовые данные из внутренней кодировки базы данных в UTF-8 и обратно. Если кодировка базы уже UTF-8, перекодировка не производится, но сообщение помечается как UTF-8, без данного параметра этого не происходит

0

0 — не преобразовывать, 1 — преобразовывать

Пример:

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

Определяет преобразовывать ли \n в \r\n при шифровании и \r\n в \n при дешифровании. В стандарте RFC 4880 требуется, чтобы текстовые данные хранились с переводами строк в виде \r\n. Используйте этот параметр, чтобы привести хранение данных в полное соответствие со стандартом RFC

0

0 — не преобразовывать, 1 — преобразовывать

Пример:

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_armor_headers()

pgp_armor_headers(data text, key out text, value out text) returns setof record

Функция извлекает заголовки Armor из параметра data. Она возвращает набор строк с двумя столбцами, key и value. Если в ключах или значениях оказываются символы не ASCII, они обрабатываются как UTF-8.

Генерация ключей 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: дозаполнение ]

В таблице ниже приведены возможные значения параметров.

Название Значение

алгоритм

  • bf — Blowfish;

  • aes — AES (Rijndael-128, -192 или -256).

режим

  • cbc — следующий блок зависит от предыдущего (значение по умолчанию);

  • ecb — каждый блок шифруется отдельно (только для тестирования).

дозаполнение

  • pkcs — данные могут быть любой длины (значение по умолчанию);

  • none — размер данных должен быть кратен размеру блока шифра.

Следующие вызовы функций равнозначны:

encrypt(data, 'fooz', 'bf')
encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')

Для функций encrypt_iv и decrypt_iv параметр iv задаёт начальное значение для режима CBC, для ECB он игнорируется. Это значение обрезается или дополняется нулями, если его размер не равен размеру блока. В функциях без этого параметра оно по умолчанию заполняется нулями.

Функции получения случайных данных

gen_random_bytes()

gen_random_bytes(count integer) returns bytea

Функция возвращает криптографически стойкие случайные байты в количестве count.

За один вызов можно получить максимум 1024 байт. Это ограничение предотвращает исчерпание пула генератора случайных чисел.

 

gen_random_uuid()

gen_random_uuid() returns uuid

Функция возвращает UUID версии 4 (случайный).

Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней