SOFTWARE
Changelog
Changes that affect how you use STRCrypt or what it produces, by release. Internal test and build tooling changes and documentation corrections are not listed.
Security notice: database install permissions fixed in 0.3.1 2026-09-27
If you installed the SQL functions in Oracle or PostgreSQL from a STRCrypt 0.3.0 or earlier database bundle, every account that can connect to the database can execute the decryption functions. Even though the key stays outside SQL, permission to decrypt means access to plaintext. The search examples in the guides used an unkeyed SHA-256 hash of national ID and card numbers, which can be reversed by hashing candidate values.
Actions
- Run
revoke_public.sqlfrom the 0.3.1 bundle to revoke thePUBLICgrants, then grant access only to the roles that need it. For Oracle, runrevoke_public.sqlor re-runinstall.sql; for PostgreSQL, runALTER EXTENSION pg_strcrypt UPDATEorsql/revoke_public.sql. - If you created search columns with an unkeyed hash, recompute them with the search index function
strcrypt_search_indexand drop the hash columns. Backups and replicas from that period still contain the hash values. - MySQL and MariaDB cannot restrict UDF execution with database privileges. Restrict decryption through read access to the ciphertext tables and by limiting who gets database accounts.
Contact us through the contact form with the inquiry type "Security Vulnerability".
0.3.1 2026-09-27
Ciphertext, encrypted files, and wrapped data keys created with 0.3.0 still decrypt as before. Existing function names and arguments and the SQL functions are unchanged, and a search index function has been added. The Oracle and PostgreSQL install scripts no longer grant the encryption and decryption functions to PUBLIC, so database accounts that called them through PUBLIC on 0.3.0 or earlier installations must be granted access explicitly.
Added
- Search index: a deterministic index (64 hex characters) for exact-match lookup on encrypted columns. SQL
strcrypt_search_index(OracleSTRCRYPT_SEARCH_INDEX), Pythonsearch_index, and Node.js and JavasearchIndexproduce the same value. Equal values share an index, so matches and frequencies are visible - Wheels for each Python version from 3.9 to 3.14 (Linux and Windows)
- PostgreSQL extension 1.1, and
revoke_public.sqlthat revokes only thePUBLICgrants of earlier installations (Oracle and PostgreSQL) - Third-party license notices
LICENSE-THIRD-PARTYand source archives
Changed
- Operating mode name
korean-standardadded. The former namekcmvp-approvedis deprecated. Code that compares error messages as strings needs to use the new name - Parallel batch encryption in the default mode now scales with the thread count (output format unchanged)
- The error message for a missing key and the CLI help point to a mode 0600 key file (
STRCRYPT_KEY_FILE) first - Node.js string arguments containing an unpaired surrogate are rejected with
RangeError
Security
- Oracle and PostgreSQL installations opened the encryption and decryption functions to
PUBLIC, so every account that could connect to the database could decrypt - The search column examples in the install guides used an unkeyed SHA-256 hash, which lets guessable values be recovered by trying candidates. Replaced with the search index
Fixed
- Oracle
STRCRYPT_ENCRYPTandSTRCRYPT_ENCRYPT_ALGOdropped everything after a NUL (CHR(0)) in the value and encrypted only the first part. They now reject it with ORA-20502 - A child process forked while another thread was loading the key for the first time could hang
Known limitations
- MySQL and MariaDB UDFs have no per-function execute privilege, so every account that can connect can call the encryption, decryption, and search index UDFs. Restrict access through read privileges on ciphertext tables and the scope of database accounts
0.3.0 2026-09-25
Ciphertext and encrypted files created with 0.2.0 still decrypt as before. Names, arguments, and return types of the Python, Node.js, and Java functions, and the existing C shared library functions, are unchanged. Changes to existing behavior are listed under "Changed" below; most of them concern how error cases are handled.
Added
- Data key (DEK) management functions: per-subject data keys (per customer, user, and so on) are stored only in wrapped form under the master key. Generate with
generate_wrapped_dek, rewrap for master key rotation withrewrap_dek, inspect withwrapped_dek_info. No function returns a plaintext data key EncryptionContext: an object that encrypts and decrypts with a wrapped data key or a key supplied by an external key management system (KMS), including batch encryption and decryption with per-record AAD (sequential and parallel). Available in Python, Node.js, and Java (Node.js and Java use names such asgenerateWrappedDek)- Nine C shared library functions providing the same features (existing SQL functions unchanged)
- Type stubs (
.pyi,py.typed) included in the Python wheel
Changed
- Example classes removed from the Java JAR (public API classes unchanged)
- Native failures in Java
generatePbeSalt,hardwareInfo,supportedAlgorithms, andversionnow throwIllegalStateExceptioninstead ofStrCryptException - CLI option combinations where one option was ignored (
-cwith-q,-cwith-o, a Base64 argument with-ffordecrypt, and others) are now usage errors (exit code 2) - CLI
--modevalues are parsed the same way asSTRCRYPT_MODE:KcmvpApprovedis accepted, values with leading or trailing spaces are rejected - If interactive CLI input ends immediately (EOF), the CLI exits with an input error (exit code 1). Previously it encrypted an empty string and overwrote the default output file
- The CLI is integrity-checked against the
.hmacfile next to the executable even when run from PATH. Replace the.hmacfile whenever you replace the executable - The CLI writes logs to standard error when
RUST_LOGis set - Supported platforms stated explicitly: release builds for Linux x86_64 and Windows x64, source builds for Linux aarch64, Windows arm64 not supported
Security
- AES-256-GCM encryption plaintext limit reduced to the NIST SP 800-38D limit (2^36-32 bytes). Lengths near the old limit reused keystream. The decryption limit is unchanged
- CLI
encrypt-fileanddecrypt-filecreate output files with mode 0600. In directories with a default ACL, decrypted plaintext files could be readable by other users - The C shared library logged unknown algorithm names verbatim, so calling it with swapped arguments put plaintext in the log
- Race between the key file permission check and the read, where the path could be swapped, is closed
- Integrity checks were skipped for libraries placed in directories with certain names (such as
deps) - Removed paths that left key file contents, file and batch decryption plaintext, and string copies in the Java and Node.js bindings in memory that was not wiped
- Key statistics removed from the weak key warning log
Fixed
- Parallel file encryption and decryption hung (deadlock) when another thread switched the operating mode
- Java strings containing an unpaired surrogate were encrypted with emoji and similar characters replaced by U+FFFD. They are now rejected with
StrCryptException - CLI
decrypt -faborted the process when it could not allocate memory for the file size. It now reports an I/O error - Missing return value (undefined behavior) in the Oracle bulk processing C wrapper
Known limitations
- The global functions use only the first 16 bytes of the master key for SEED-128-GCM, LEA-128-GCM, AEGIS-128L, and ASCON-128. Generate the full 32-byte master key randomly. File encryption and wrapped data keys are not affected
- Record ciphertext is not key-committing. Pass only keys from a trusted KMS to
from_raw_key, and record a data key identifier with each record - Per-key usage counters live only in process memory. Totals across restarts and multiple processes must be tracked by the caller
- The new functions in the bindings and the C shared library have not been run and tested on Windows
- The SQL functions and global functions that encrypt every row with one master key are limited to 2^32 encryptions per key (summed across all processes and re-encryption). Rotate the key before the total reaches 2^31
0.2.0 2026-09-17
Added
- Bulk byte batch encryption and decryption with per-record AAD in Python, Node.js, and Java. Splits work by record count and byte limits, and reports the index of the failed record
- CLI
encrypt-batchanddecrypt-batch: one record per line (Base64, or data and AAD as TSV), with exit codes 0 to 4 by error type - C shared library bulk batch functions and return code constants
- Oracle bulk processing package
STRCRYPT_BULK: collection procedures and pipelined functions, sharing the ciphertext format of the scalar functions - Windows 10 and 11 x64 releases: CLI, C shared library, Python wheel, Node.js addon, and Java JNI library. No VC++ redistributable required
Changed
- String batch decryption detects the header per element, so arrays mixing header and legacy ciphertext decrypt in one call
- Fixed a mode mismatch when the CLI is run with
STRCRYPT_MODEbut no--mode. Runs withSTRCRYPT_MODE=non-approvednow default to AEGIS-128L, so ciphertext they create does not decrypt in a default-mode process. Existing ARIA-256-GCM ciphertext decrypts in both modes - CLI plaintext read from standard input keeps leading and trailing spaces (only the final line break is removed). Decrypting the same input gives a different result from earlier versions
- CLI output format changed: banner and separator lines removed, results printed as aligned
Label: valuelines. Scripts that parse the output need updating - Exit code for unknown CLI
-a,--mode, andmigrate-file -tvalues changed from 1 to 2 - AES-256-GCM and AES-256-GCM-SIV report oversized input as
PlaintextTooLongorAadTooLonginstead of an authentication failure - MySQL and MariaDB UDFs: key and algorithm problems now end the statement with an error (ERROR 1123) instead of returning NULL for every row. A row-level failure returns NULL for that row only. Strings containing a NUL byte return NULL
- Oracle error numbers changed from ORA-29501 and ORA-29502 to ORA-20502 and ORA-20503. PL/SQL exception handlers catching the old numbers need updating
- Python raises
MemoryErrorwhen result allocation fails; Java rejects null list elements withNullPointerException - macOS support dropped
Security
- On Unix, a forked child process could generate the same nonces as its parent
- CLI output is written to a temporary file (mode 0600) and then swapped in, so the existing file is kept if the write fails. Decrypted plaintext files were previously created with the default umask permissions (usually 0644)
- If a CLI output path is a symbolic link, FIFO, or device, the CLI no longer writes through it and exits with a save error (exit code 1). Usage such as
-o /dev/stdoutis no longer possible - Non-UTF-8 values of
STRCRYPT_KEY_FILEorSTRCRYPT_KEYwere treated as unset, and another key was used for encryption. The CLI and libraries now stop with an error - Removed paths where the bindings and cipher code freed copies of keys, passwords, and plaintext without wiping them
Fixed
- Parallel work in a forked child process waited forever
- With
STRCRYPT_MODE=non-approved, depending on the first function called, keys shorter than 16 bytes were rejected and all later encryption and decryption failed - With
STRCRYPT_MODE=non-approved, authentication failed when the first call decrypted legacy AES-256-GCM ciphertext - MySQL and MariaDB UDFs truncated values over about 49 KB in UNION and DISTINCT queries. Truncated ciphertext cannot be decrypted
- Reinstalling the PostgreSQL integration dropped views, column defaults, and constraints that used the extension functions
- Declaration error that left the six SQL functions INVALID (PLS-00249, PLS-00251) on Oracle 19c, and the install SQL stopping to wait for input
- File encryption and decryption failed for output file names longer than about 232 bytes
- The CLI exited with a panic message when its output went to a closed pipe
- CLI
infoshowed the key source as "not set" when only a key file was configured - JNI local references accumulated during Java batch calls with large lists
Known limitations
- No SQL batch functions for PostgreSQL, MySQL, or MariaDB. Use the CLI or a binding for bulk processing
- Oracle bulk processing was verified on 19c Enterprise Edition single instance. RAC and other setups are not verified, and if the database character set is not AL32UTF8, a single non-ASCII record fails the whole chunk
0.1.2 2026-07-17
Security
- Stricter policy checks for operating mode switches and cipher operations
- A failed file decryption no longer leaves partial plaintext at the final output path
- Stronger input validation, panic containment, and secret wiping in the bindings and the C shared library
Changed
- Default algorithm in Python, Node.js, and Java aligned with the operating mode
- Java release shipped as an archive bundling the JAR and per-platform JNI libraries
0.1.1 2026-04-23
Added
- First integrated release with the Korean standard algorithms and the Python, Node.js, and Java bindings