Skip to content

encsearch

Experimental encrypted text search using AEAD ciphers and keyed blind indexes

Overview

PackageVersionCategoryLicenseLanguage
encsearch0.1.1SECPostgreSQLRust
IDExtensionBinLibLoadCreateTrustRelocSchema
7035encsearchNoYesYesYesNoNo-

Early release 0.1.1 changes PGXN status to stable without code changes from 0.1.0; PG17 tested, other Cargo PG14-18 targets untested. Session preload must precede key settings; blind indexes leak equality and token frequency.

Version

TypeRepoVersionPG VerPackageDeps
EXTPIGSTY0.1.11817161514encsearch-
RPMPIGSTY0.1.11817161514encsearch_$v-
OS / PGPG18PG17PG16PG15PG14
el8.x86_64N/AN/AN/AN/A
el8.aarch64N/AN/AN/AN/A
el9.x86_64N/AN/AN/AN/A
el9.aarch64N/AN/AN/AN/A
el10.x86_64N/AN/AN/AN/A
el10.aarch64N/AN/AN/AN/A
d12.x86_64N/AN/AN/AN/AN/A
d12.aarch64N/AN/AN/AN/AN/A
d13.x86_64N/AN/AN/AN/AN/A
d13.aarch64N/AN/AN/AN/AN/A
u22.x86_64N/AN/AN/AN/AN/A
u22.aarch64N/AN/AN/AN/AN/A
u24.x86_64N/AN/AN/AN/AN/A
u24.aarch64N/AN/AN/AN/AN/A
u26.x86_64N/AN/AN/AN/AN/A
u26.aarch64N/AN/AN/AN/AN/A

Build

You can build the RPM packages for encsearch using pig build:

pig build pkg encsearch         # build RPM packages

Install

You can install encsearch directly. First, make sure the PGDG and PIGSTY repositories are added and enabled:

pig repo add pgsql -u          # Add repo and update cache

Install the extension using pig or apt/yum/dnf:

Install
pig install encsearch;          # Install for current active PG version
pig
pig ext install -y encsearch -v 17  # PG 17
dnf
dnf install -y encsearch_17       # PG 17

Preload:

shared_preload_libraries = 'encsearch';

Create Extension:

CREATE EXTENSION encsearch;

Usage

Sources:

encsearch stores encrypted text alongside keyed search tokens in an int8[] column. Its experimental 0.1.0 release supports exact, word and pattern searches through a GIN index. Upstream has tested PostgreSQL 17; the other Cargo feature targets are untested.

Core Workflow

session_preload_libraries = 'encsearch'
CREATE EXTENSION encsearch;
CREATE TABLE encrypted_notes (id bigint GENERATED ALWAYS AS IDENTITY, body bytea, idx int8[]);
CREATE INDEX encrypted_notes_tokens ON encrypted_notes USING gin (idx);
INSERT INTO encrypted_notes (body, idx)
VALUES (enc_encrypt('Patient has diabetes'), enc_index('Patient has diabetes'));
SELECT enc_decrypt(body) FROM encrypted_notes
WHERE enc_like(body, idx, '%diab%');

Operational Boundaries

An administrator installs this untrusted extension. Configure session_preload_libraries before opening client sessions and before setting encsearch.key; otherwise an early key setting remains an unregistered setting visible to other roles. Supply a securely retained key of at least 32 characters to the session or explicit-key function overloads before running the data example. enc_gen_key() generates a 64-character key. Losing the key loses access to the plaintext.

enc_encrypt and enc_decrypt handle text and ciphertext. enc_index creates stored tokens; enc_like, enc_ilike and enc_eq filter candidates and check decrypted values. enc_has_words tests token containment without decrypting; enc_q_like, enc_q_exact and enc_q_words expose raw query tokens. enc_algorithm and enc_algorithms inspect available ciphers.

encsearch.algorithm defaults to aes-256-gcm; deterministic aes-256-siv reveals duplicate plaintext. Keep encsearch.token_hash identical when building and querying tokens: hmac-sha256 is the default and blake3 is the alternative. Changing the token hash requires regenerating tokens; changing keys requires decrypting with the old key and rebuilding ciphertext and tokens with the new key.

Blind indexes reveal shared values, words and character chunks and their frequency. Keys reach the database server and may appear in statement or parameter logs. This is an experimental privacy/performance tradeoff, not protection against a server that has the key.

Was this page helpful?