User Guide for Cold Re-Encryption of QHB Database Objects
Cold re-encryption of database objects is the process of changing encryption keys for previously encrypted tables, indexes, and other database objects, performed with the DBMS stopped. Re-encryption may be required for security reasons or when the current key expires. The operation is performed using the qhb_recrypt utility, which is included in the QHB package. This utility works in conjunction with QSS (Quantum Security Server), which manages encryption keys.
Prerequisites
Installed components:
- QHB;
- QSS.
Configuration:
- Initialized database with encrypted tables;
- File <PGDATA>/qss2_config.toml must be readable (where <PGDATA> is the actual path to the data directory);
- Availability of several (at least two) active encryption keys in QSS. It
is checked using the
key listcommand of the qss-admin utility.
Example output of the qss-admin command (run as a privileged user):
# qss-admin admin
Enter the password for the administrator "admin":
info: Connection to QSS is successful.
admin@qss-admin:# key list
info: Received a list of working keys (4 items):
№ ID Valid until: Days: Status: Type: Name:
0 0x2D6CEC4F86EE42FF 2026-09-10T00:53:18+03:00 449 Разблокирован kuznyechik foo
1 0x2A66E47E9219B490 2026-09-10T00:53:24+03:00 449 Разблокирован kuznyechik bar
2 0x359E3F40F10F47E2 2026-09-10T00:54:40+03:00 449 Разблокирован tc26_2012_256b ec256
3 0x4C4FCCC245945E92 2026-09-11T07:19:21+03:00 450 Разблокирован kuznyechik baz
Example of configuration file <PGDATA>/qss2_config.toml:
active_key = "bar"
provider = "compressed-append"
socket_address = "/run/qss/client.socket"
Example of creating and filling an encrypted table:
CREATE TABLE test (
id SERIAL PRIMARY KEY,
title TEXT,
author_id INT,
created DATE
) USING qss;
INSERT INTO test (title, author_id, created)
SELECT md5(random()::text), (100*random())::int, NOW() - '1 day'::interval * (random()::int * 100 + 100)
FROM generate_series(1, 10);
Steps for Re-Encryption
- Changing user to qhb.
Checking login capability:
id qhb
If the user exists, the command will return their UID, GID, and groups, for example:
uid=1001(qhb) gid=1001(qhb) groups=1001(qhb).
Checking for shell in /etc/passwd:
grep '^qhb' /etc/passwd
Expected output, for example: qhb:x:1001:1001::/usr/local/qhb:/bin/bash. If
the shell is /bin/false or /sbin/nologin, login is not possible. To enable
login change the shell (as root):
usermod -s /bin/bash qhb
Checking user privileges for home directory:
ls -ld ~qhb
Expected output, for example: drwxr-xr-x 2 qhb qhb 4096 Jun 23 2025 /home/qhb.
You need to make sure that the directory is owned by qhb and has write
permissions (for example, drwxr-xr-x or 700). If you don't have the permissions,
you need to fix it by running the commands as root:
chown qhb:qhb /usr/local/qhb
chmod 700 /usr/local/qhb
Checking ability to write:
su - qhb -c "touch ~/testfile && echo 'Writing possible' || echo 'Writing impossible'"
Note
If necessary, replace /usr/local/qhb with the current home directory specified in /etc/passwd.
Switching to user qhb as root:
su - qhb
Result: login to user qhb session. The command string will change, for example, to:
[qhb@dba03 ~]$
- Preparing a list of files for re-encryption.
For the program to operate, you need to create a settings file with parameters
and a list of database files that will be re-encrypted. The list of files is a
list of encrypted database objects (tables, indexes, etc.) stored on the disk.
Settings are created using the prepare-list command.
/usr/local/qhb/bin/qhb_recrypt prepare-list --encrypt-key baz --dbname qhb
Parameters:
- --encrypt-key: name of the new encryption key (e.g., baz);
- --dbname: database name (e.g., qhb).
As a result, two files will be created in the /usr/local/qhb/.qhb_recrypt directory.
# ls /usr/local/qhb/.qhb_recrypt
config.toml file_list.txt
# cat /usr/local/qhb/.qhb_recrypt/config.toml
active_key = "baz"
socket_address = "/run/qss/client.socket"
shmem = true
tail_file = "/qhb/qhb-qss/data/global/qss2_compressed_tails.bin"
# cat /usr/local/qhb/.qhb_recrypt/file_list.txt
/qhb/qhb-qss/data/base/5/16400
/qhb/qhb-qss/data/base/5/16406
- Stopping the DBMS.
The DBMS server must be stopped to avoid file access conflicts. (In the following command, <PGDATA> must be replaced with the actual path to the data directory.)
/usr/local/qhb/bin/qhb_ctl -D <PGDATA>/data stop
Parameters:
- -D: path to the DBMS data directory.
- Performing re-encryption.
The recryption process that uses a prepared list of files is started by the
recrypt command.
/usr/local/qhb/bin/qhb_recrypt recrypt
The utility will re-encrypt the specified files with a new key.
[qhb@dba03 ~]$ /usr/local/qhb/bin/qhb_recrypt recrypt
[INFO] Done recrypting /qhb/qhb-qss/data/base/5/16400
[INFO] Done recrypting /qhb/qhb-qss/data/base/5/16406
- Configuration update.
To ensure that new tables are encrypted with the new key, you need to update the active_key parameter in the <PGDATA>/qss2_config.toml file using a text editor.
- Running the DBMS.
You need to start the DBMS server after re-encryption. (In the following command, you must replace <PGDATA> with the actual path to the data directory.)
/usr/local/qhb/bin/qhb_ctl -D <PGDATA>/data -l <PGDATA>/logfile start
Parameters:
- -D: path to the DBMS data directory;
- -l: path to the log file.
Checking access to a table via psql:
/usr/local/qhb/bin/psql qhb
select * from test limit 10;
The result will be the same data as before re-encryption.
Estimation of time costs
The utility allows you to estimate the time spent on re-encrypting data. To do this, you need to:
- Check if the path to the QHB binaries is specified:
$echo $PATH
/usr/share/Modules/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
If the path is missing, add it using the following command:
export PATH="/usr/local/qhb/bin:$PATH"
- Determine the required time for re-encryption.
Call the utility with the estimate command, specifying the name of the database
to be re-encrypted:
$ /usr/local/qhb/bin/qhb_recrypt estimate --dbname qhb
[INFO] Temp directory for test objects: /tmp/qhb-estimate-recrypt-SCrMzb
[INFO] Using DBMS data directory: /qhb/qhb-qss/data
[INFO] Running recrypt command...
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ qhb │
├──────────┬────────────┬──────────────────────┬────────────────────────────────┬──────────┬──────────────────┤
│ rel_kind │ rel_schema │ rel_name │ file_path │ bytes │ recrypt_duration │
├──────────┼────────────┼──────────────────────┼────────────────────────────────┼──────────┼──────────────────┤
│ index │ public │ encripted_table_pkey │ /qhb/qhb-qss/data/base/5/16406 │ 16.0 kiB │ 6ms │
├──────────┼────────────┼──────────────────────┼────────────────────────────────┼──────────┼──────────────────┤
│ table │ public │ encripted_table │ /qhb/qhb-qss/data/base/5/16400 │ 8.0 kiB │ 3ms │
├──────────┼────────────┼──────────────────────┼────────────────────────────────┼──────────┼──────────────────┤
│ │ │ │ │ 24.0 kiB │ 9ms │
└──────────┴────────────┴──────────────────────┴────────────────────────────────┴──────────┴──────────────────┘
Test object size: 16.0 kiB
Test object re-encryption time: 6ms
Total size of all databases: 24.0 kiB
Estimated re-encryption time for all databases: 9ms