
The Problem: Encrypting One File at a Time Does Not Scale
If you need to encrypt a single file, opening a terminal and running one command is easy. But organizations do not deal with single files. A mid-size company might generate hundreds of reports per day. A hospital produces thousands of patient records. A software team builds release artifacts every hour. A law firm handles tens of thousands of documents per case.
Encrypting each of these files by hand would take a human operator all day, every day. Even worse, manual processes create mistakes: someone forgets to encrypt a file, uses a weak password, or leaves the unencrypted original sitting on a shared drive. NIST SP 800-57 (Recommendation for Key Management) emphasizes that cryptographic key management must be systematic and repeatable. Manual processes are neither.
Batch encryption solves this. You tell QNSQY "encrypt all of these files at once," and it handles the rest: parallel processing, consistent key management, and a complete audit trail of what was encrypted, when, and by whom.
How QNSQY Batch Encryption Works
The qnsqy batch command takes a list of files and encrypts them all in one operation. Think of it like a factory assembly line: instead of a craftsman working on one item at a time, you feed hundreds of items into the line and they all come out encrypted on the other side.
Behind the scenes, QNSQY splits the work across multiple CPU cores. If your server has 8 cores, it can encrypt 8 files simultaneously. Each file gets its own unique encryption key derived from the shared password or recipient key, so compromising one file does not compromise the others.
The three batch operations are:
- batch encrypt: Encrypt multiple files at once
- batch decrypt: Decrypt multiple .qs files at once
- batch verify: Verify the signatures on multiple files at once
All three are Pro tier features. The Free tier supports single-file operations only.
Batch Encrypt: The Basic Command
The simplest batch encrypt command takes a file glob (a pattern like *.pdf) and an output directory:
qnsqy batch encrypt *.pdf -o ./encrypted/
This encrypts every PDF file in the current directory and writes the encrypted versions to the ./encrypted/ folder. Each output file keeps its original name with .qs appended: report.pdf becomes encrypted/report.pdf.qs.
QNSQY will prompt for a password once, then reuse it for all files in the batch. You do not need to type the password 500 times for 500 files.
Parallel Processing with -j
By default, QNSQY encrypts files sequentially (one at a time). For large batches, you can use the -j flag to specify how many files to process in parallel:
qnsqy batch encrypt /data/*.csv -j 8 -o ./encrypted/
This uses 8 CPU cores simultaneously. On an 8-core machine, this is roughly 8 times faster than sequential processing. The actual speedup depends on your disk speed: if your hard drive or SSD is the bottleneck, adding more CPU cores will not help.
A good rule of thumb: set -j to the number of CPU cores on your machine, or half the number if you need to leave resources for other processes.
Encrypting Directories
QNSQY encrypts files, not directories. To encrypt an entire folder, first bundle it into a single archive, then encrypt that archive:
tar -cf reports.tar /data/reports/
qnsqy encrypt -i reports.tar -o /encrypted/reports.tar.qs
This creates one encrypted file containing the entire directory tree. To get the files back later, decrypt and then extract:
qnsqy decrypt -i /encrypted/reports.tar.qs -o /tmp/reports.tar
tar -xf /tmp/reports.tar
Batch Decrypt
Decrypting a batch works the same way. Provide a glob of .qs files and an output directory:
qnsqy batch decrypt ./encrypted/*.qs -o ./decrypted/
QNSQY prompts for the password once and decrypts all files. If different files were encrypted with different passwords, you will need to decrypt them in separate batches grouped by password.
For recipient-based encryption (where files were encrypted to a public key), provide the private key:
qnsqy batch decrypt ./encrypted/*.qs --key finance_private -o ./decrypted/
Batch Verify
If your workflow involves signed files, batch verify checks all signatures at once:
qnsqy batch verify ./signed/*.pdf -k signer.pub
This verifies that every PDF in the directory was signed by the holder of signer.pub and has not been modified. Any file that fails verification is flagged immediately. This is essential for compliance workflows where you need to prove document integrity.
Scripting and Automation
Batch commands are designed for automation. The key feature that makes this work is --password-stdin, which reads the password from standard input instead of an interactive prompt. This lets you pipe a password from a file or environment variable.
Using a Password File
cat /etc/qnsqy/backup.key | qnsqy batch encrypt /data/*.csv --password-stdin -o ./encrypted/
The password file should contain only the password text, with no trailing newline if possible. Protect this file aggressively:
chmod 400 /etc/qnsqy/backup.key
chown root:root /etc/qnsqy/backup.key
The 400 permission means only the file owner (root) can read it. No one else on the system can access it.
Using Environment Variables
echo -e "$ENCRYPTION_KEY\n$ENCRYPTION_KEY" | qnsqy encrypt --password-stdin -i file.txt
The password is echoed twice (separated by a newline) because QNSQY expects a password and a confirmation, even in stdin mode. The environment variable ENCRYPTION_KEY should be set as a secret in your CI/CD system, not hardcoded in scripts.
CI/CD Integration
Modern software teams use continuous integration and continuous deployment (CI/CD) pipelines to build, test, and release software automatically. Adding encryption to these pipelines protects build artifacts, release packages, and sensitive configuration files.
GitHub Actions
Store your encryption password as a GitHub Actions secret (Settings > Secrets and variables > Actions), then reference it in your workflow:
- name: Encrypt release artifacts
env:
ENCRYPTION_KEY: ${{ secrets.QNSQY_KEY }}
run: |
echo -e "$ENCRYPTION_KEY\n$ENCRYPTION_KEY" | \
qnsqy encrypt --password-stdin \
-i ./build/release.zip \
-o ./encrypted/release.zip.qs
The secret is masked in logs: GitHub replaces the actual value with *** in any output. The encrypted artifact can then be uploaded to your release server or artifact storage.
Jenkins Pipeline
stage('Encrypt') {
steps {
withCredentials([string(credentialsId: 'qnsqy-key', variable: 'KEY')]) {
sh 'echo -e "$KEY\n$KEY" | qnsqy batch encrypt ./artifacts/* --password-stdin -o ./encrypted/'
}
}
}
The withCredentials block ensures the password is injected from Jenkins' credential store and never appears in plaintext in the pipeline definition or build logs.
GitLab CI
encrypt_artifacts:
stage: deploy
script:
- echo -e "$QNSQY_KEY\n$QNSQY_KEY" | qnsqy batch encrypt ./build/* --password-stdin -o ./encrypted/
artifacts:
paths:
- encrypted/
Store QNSQY_KEY as a protected variable in your GitLab project settings (Settings > CI/CD > Variables). Mark it as "masked" and "protected" so it only runs on protected branches.
Scheduled Backup Encryption
One of the most common batch encryption use cases is nightly backup encryption. The idea is simple: your backup system creates backup files every night, and immediately after, a scheduled job encrypts them.
Cron Job (Linux/macOS)
# Encrypt backups every night at 2 AM
0 2 * * * tar -cf /tmp/backup.tar /backups/daily/ && \
cat /etc/qnsqy/backup.key | /usr/local/bin/qnsqy encrypt --password-stdin \
-i /tmp/backup.tar -o /encrypted/backup-$(date +\%Y\%m\%d).qs && \
/usr/local/bin/qnsqy shred /tmp/backup.tar -f
This cron job runs at 2:00 AM every day. It creates a tar archive of the backup directory, encrypts it with the password from the key file, saves it with today's date in the filename, and then securely shreds the unencrypted temporary archive. The result is a dated encrypted backup that can be safely stored on remote servers or cloud storage.
Task Scheduler (Windows)
tar -cf C:\Temp\backup.tar C:\Backups\Daily
type C:\Secure\backup.key | qnsqy encrypt --password-stdin ^
-i C:\Temp\backup.tar ^
-o C:\Encrypted\backup-%date:~-4,4%%date:~-7,2%%date:~-10,2%.qs
Create a batch file (.bat) with these commands and schedule it using Windows Task Scheduler. The %date% variables extract year, month, and day from the system date to create a dated filename.
Integration with Backup Workflows
Encryption should be the last step before backups leave your local environment. Whether you use rsync, Veeam, Bacula, or a cloud backup service, the pattern is the same:
- Backup software creates an unencrypted backup file
- QNSQY encrypts the backup file
- Shred the unencrypted backup file
- Transfer the encrypted file to offsite storage (cloud, tape, remote server)
This way, even if the offsite storage is compromised, the attacker only gets encrypted data. Without the password or private key, the backups are useless to them. This is especially important for HIPAA compliance (healthcare), PCI DSS (payment card data), and GDPR (European personal data), all of which require encryption of data at rest and in transit.
Department-Based Key Management
Large organizations need different departments to have different encryption keys. The finance team should not be able to decrypt HR records, and HR should not be able to decrypt legal documents. QNSQY handles this with recipient-based encryption using public/private key pairs.
First, generate a key pair for each department:
qnsqy keygen-enc -o finance -n "Finance Department"
qnsqy keygen-enc -o hr -n "Human Resources"
qnsqy keygen-enc -o legal -n "Legal Department"
Distribute the public keys (finance.pub, hr.pub, legal.pub) to the systems that encrypt data. Keep the private keys (finance, hr, legal) secure and only give them to the people who need to decrypt.
qnsqy batch encrypt /finance/*.xlsx --recipient finance.pub -o ./encrypted/
qnsqy batch encrypt /hr/*.docx --recipient hr.pub -o ./encrypted/
qnsqy batch encrypt /legal/*.pdf --recipient legal.pub -o ./encrypted/
Only the finance team (with the finance private key) can decrypt finance files. HR files require the hr private key. This is called "separation of duties" and is a core principle of NIST SP 800-57 key management.
Audit Logging for Compliance
Every batch operation generates audit log entries. The audit log records:
- Which files were encrypted or decrypted
- When the operation occurred (timestamp)
- Which algorithm was used
- Whether the operation succeeded or failed
- The machine identity (for tracking which workstation performed the operation)
You can view the audit log with:
qnsqy audit
For organizations that use Security Information and Event Management (SIEM) platforms like Splunk, Elastic, or Microsoft Sentinel, the Business tier supports streaming audit events directly to your SIEM. This gives your security operations center (SOC) real-time visibility into all encryption activity across the organization.
Performance Considerations
Batch encryption performance depends on three factors:
- CPU speed and core count: More cores means more parallel encryption. The actual AES-256-GCM encryption runs at several hundred megabytes per second per core on modern hardware.
- Disk speed: If your files are on a spinning hard drive (HDD), the disk becomes the bottleneck long before the CPU does. SSDs and NVMe drives are significantly faster.
- Password hashing cost: Argon2id runs once per batch operation (not once per file). The Free tier uses 128 MB of RAM for this step, Pro uses 256 MB, and Business uses 512 MB. This takes 1 to 3 seconds depending on your hardware, but it only happens once.
As a rough benchmark: on an 8-core machine with an NVMe SSD, encrypting 1,000 files totaling 25 GB with -j 8 takes approximately 30 seconds. The same operation with a spinning hard drive takes closer to 3 minutes because the disk read/write speed is the limiting factor.
Encrypt-Then-Shred: Cleaning Up Originals
After encrypting files, you often want to securely delete the unencrypted originals. This is a two-step process:
qnsqy batch encrypt /sensitive/*.csv -o ./encrypted/ && \
for f in /sensitive/*.csv; do qnsqy shred "$f" -f; done
The && ensures the shred step only runs if the encryption succeeded. If encryption fails for any reason, the originals are preserved so you do not lose data.
Security Best Practices for Batch Operations
- Never hardcode passwords in scripts. Use environment variables from a secrets manager or password files with restricted permissions. A password sitting in a shell script is a password anyone with read access to that script can see.
- Protect password files with strict permissions. Use
chmod 400(owner read only) andchown root:rootso only the root user can read them. - Rotate encryption keys regularly. NIST SP 800-57 recommends reviewing key validity periods based on your risk assessment. At minimum, rotate keys annually and re-encrypt active data with the new keys using the
qnsqy rekeycommand (Pro+). - Monitor your audit logs. If a batch job fails silently, unencrypted files might be sitting on disk. Set up alerts for failed encryption operations.
- Test your decryption process regularly. Backups are worthless if you cannot decrypt them when you need to. Schedule monthly test restores to verify your passwords and keys work correctly.
Rekeying: Rotating Encryption Keys Without Re-Encrypting from Scratch
Key rotation is a standard security practice recommended by NIST SP 800-57. The idea is simple: even if an encryption key is compromised, limiting its lifetime limits the damage. If you rotate keys annually, a compromised key only exposes one year of data, not everything you have ever encrypted.
QNSQY's rekey command (Pro+) changes the password on an encrypted file without decrypting it to disk first:
qnsqy rekey -i archive.qs
You enter the old password and then the new password. QNSQY decrypts the internal key material, re-encrypts it under the new password, and writes the updated file. The file contents themselves are not re-encrypted (they do not need to be, since only the key wrapping changes), so the operation is fast even on large files.
For batch rekeying across many files, you can script it:
for f in /encrypted/*.qs; do
echo -e "$OLD_PASSWORD\n$NEW_PASSWORD\n$NEW_PASSWORD" | qnsqy rekey --password-stdin -i "$f"
done
Schedule this annually (or more frequently for high-security environments) to stay compliant with key management policies.
Advanced: M-of-N Threshold Encryption (Business)
For the most sensitive data, the Business tier supports threshold encryption. This means that decryption requires multiple people to cooperate. For example, you can configure "3-of-5" threshold encryption, where five people each hold a key share, and any three of them must combine their shares to decrypt.
This prevents any single person (including system administrators) from accessing the data alone. It is commonly used for encryption key escrow, executive financial records, and classified government documents.
qnsqy threshold-encrypt -i sensitive_archive.tar \
-m 3 -r cfo.pub coo.pub cto.pub auditor.pub counsel.pub
Decryption requires any 3 of the 5 recipients to provide their private keys. Even if two key holders are unavailable or compromised, the remaining three can still recover the data. Conversely, two colluding insiders cannot access the data without a third participant.
Error Handling and Monitoring
In production environments, you need to know when batch operations fail. Silent failures are dangerous: if a nightly backup encryption fails and nobody notices for three months, you have three months of unencrypted backups sitting on disk or in cloud storage.
QNSQY batch commands return standard exit codes: 0 for success, non-zero for failure. Use these in your scripts:
qnsqy batch encrypt /data/*.csv -o ./encrypted/ || \
mail -s "ALERT: Batch encryption failed" ops@example.com < /dev/null
The || operator runs the mail command only if the encryption command fails. Combine this with the audit log for a complete picture of what happened and why.
Sources
- NIST SP 800-57 Part 1 Rev. 5: Recommendation for Key Management - https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final
- NIST FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM) - https://csrc.nist.gov/pubs/fips/203/final
- NIST SP 800-38D: Recommendation for Block Cipher Modes of Operation: GCM - https://csrc.nist.gov/pubs/sp/800/38/d/final
- RFC 9106: Argon2 Memory-Hard Function for Password Hashing - https://www.rfc-editor.org/rfc/rfc9106
Related Articles
Originally published at quantumsequrity.com/blog/batch-encryption-enterprise.