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 list command 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

  1. 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 ~]$
  1. 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
  1. 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.
  1. 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
  1. 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.

  1. 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:

  1. 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"
  1. 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