pydlock
Description
pydlock is a dead-simple tool for password-encrypting and decrypting files. Lock a file with one command, unlock it with another — that is the whole product. It can be used from the command line or imported as a Python package.
As of 2.0 your password is protected with a salted, memory-hard scrypt key derivation, files of any kind (including binaries and Windows executables) round-trip losslessly, and writes are atomic — an interrupted lock or unlock never leaves a truncated or half-written file (see Security boundaries for the precise durability and integrity guarantees).
Problems this solves
Reach for pydlock if you are trying to:
- Password-encrypt a file from the command line — one command to lock, one to unlock, nothing else to configure.
- Encrypt and decrypt a file in Python with a two-function API
(
pydlock.lock/pydlock.unlock) instead of wiring up a crypto library yourself. - Protect a file with a strong password-derived key without designing your own scheme — pydlock uses salted, memory-hard scrypt and authenticated Fernet (AES-128-CBC + HMAC-SHA256), and adds no custom cryptography.
- Encrypt binaries safely — files of any kind round-trip byte-for-byte, and writes are atomic (a fresh file is prepared and swapped into place, so an interrupted operation never truncates your data).
Installation
pydlock is available on the Python Package Index (PyPI) at
https://pypi.org/project/pydlock. Install it with pip:
pip install pydlock
Quick start
Encrypt a file in place:
pydlock lock secret.txt
Decrypt it again:
pydlock unlock secret.txt
That is the entire everyday workflow. You are prompted for a password (twice when locking); nothing else is required.
Usage
From the command line
The pydlock console command (installed with the package) and
python -m pydlock are equivalent:
user@computer:~$ pydlock -h
usage: pydlock [-h] [--version] [--encoding ENCODING] {lock,unlock,encrypt,decrypt} file
positional arguments:
{lock,unlock,encrypt,decrypt}
file
options:
-h, --help show this help message and exit
--version show the version and exit
--encoding ENCODING
Supported operations:
lock— encrypt a file in place.unlock— decrypt a file in place.encrypt— alias forlock.decrypt— alias forunlock.
A short example:
user@computer:~$ cat secret.txt
Shh! It's a secret!
user@computer:~$ pydlock lock secret.txt
Enter password:
Re-enter password:
user@computer:~$ pydlock unlock secret.txt
Enter password:
user@computer:~$ cat secret.txt
Shh! It's a secret!
An entered-but-wrong password fails cleanly — pydlock prints
Could not decrypt (wrong password or corrupt file). and leaves the encrypted
file untouched. Other expected problems (a missing file, a symlink or
hard-linked target, a permission error) print a one-line pydlock: … diagnostic
and exit non-zero, without a traceback.
In other Python modules
import pydlock
filename = "secret.txt"
with open(filename, "wb") as file:
file.write(b"Shh! It's a secret!")
pydlock.lock(filename) # prompts for a password, then encrypts in place
pydlock.unlock(filename) # prompts for the password, then decrypts
What's new in 2.0
Version 2.0 is a breaking change to the on-disk format. Files are now written
as a small self-identifying envelope — a PYDLOCK magic marker, a JSON header
carrying the key-derivation parameters and a per-file random salt, and then the
encrypted token — instead of a bare token.
Highlights:
- Stronger password protection. The key is derived with a salted, memory-hard scrypt KDF (see below), replacing the previous unsalted single-pass SHA-256 derivation.
- Binary files are safe. Files are read and written as raw bytes, so binary files and Windows executables round-trip losslessly. Earlier versions corrupted them; that bug is fixed.
- Atomic writes. Locking and unlocking write to a temporary file and atomically replace the original, so an interrupted operation can never leave a truncated or half-written file. On POSIX the file and its parent directory are fsynced so the replacement is also durable across a power loss; see Security boundaries for the per-platform guarantee.
encrypt/decryptaliases forlock/unlock.pythonandrunremoved. The old decrypt-and-execute subcommands were a security footgun (arbitrary code execution) and outside the scope of a file-encryption tool; they have been removed.
Migrating from v1
You do not need to do anything special. Files locked with pydlock 1.x are detected automatically and decrypted transparently:
user@computer:~$ pydlock unlock old_v1_file.txt
Enter password:
Re-locking an unlocked file rewrites it in the new v2 format, so a file is upgraded simply by unlocking and locking it again.
If you ever need the old behavior explicitly, the final 1.x release remains installable as a documented fallback:
pip install 'pydlock<2'
How your password is protected
When you lock a file, pydlock generates a fresh 16-byte random salt and derives
the encryption key from your password with scrypt (parameters n = 32768,
r = 8, p = 1), a memory-hard function designed to make brute-force and
hardware-accelerated guessing expensive. The salt and parameters are stored in
the file's header so the key can be re-derived when you unlock it — a different
salt each time means locking the same file twice never produces the same
ciphertext.
The file itself is encrypted with
Fernet (AES-128 in CBC mode with an
HMAC-SHA256 authentication tag) from the well-vetted cryptography library.
Because the token is authenticated, a wrong password, a corrupted token, or any
modification of the encrypted contents is detected and rejected — pydlock never
returns silently-wrong plaintext. pydlock adds no custom cryptography of its own.
Use a strong passphrase: scrypt makes guessing expensive, but it cannot add entropy to a weak or empty one. pydlock refuses to encrypt with an empty password.
Security boundaries
pydlock is deliberately small. Knowing exactly what it does and does not guarantee lets you use it safely.
- What is authenticated. The plaintext and the ciphertext are authenticated by Fernet's HMAC, and the v2 envelope is parsed strictly (exact framing, canonical base64, the promised salt length), so a wrong password or a modified token/header is rejected rather than returning wrong plaintext. This is not a byte-for-byte signature over an arbitrary presentation of the file: Fernet has no additional-authenticated-data channel, so pydlock authenticates the plaintext and ciphertext and validates the envelope grammar, rather than claiming every possible byte layout is signed.
- Regular files only; no aliases.
lockandunlockoperate only on an existing, singly-linked regular file. A symlink, a hard-linked file (st_nlink != 1), or a non-regular file (directory, device, FIFO) is rejected with a non-zero exit, because pydlock replaces a file by renaming a new inode over the path — which would encrypt one name while leaving the plaintext reachable through the other. Resolve the symlink yourself and pass the real target if that is what you meant. - Concurrent edits are not clobbered. pydlock snapshots the file's identity when it reads it and revalidates immediately before replacing it. If the file changed on disk in between (a concurrent writer, or a path swap), the operation aborts without overwriting the newer contents. A small time window between the check and the replace is unavoidable; pydlock is not a substitute for a file lock in a heavily concurrent workflow.
- Atomic everywhere; durable on POSIX. The replace is atomic on every platform (no truncated/partial file). Full power-loss durability additionally requires fsyncing the parent directory, which pydlock does on POSIX; on Windows and on filesystems that do not support directory fsync, only atomic replacement is guaranteed, not durability across a sudden power loss.
- Metadata Fernet exposes. A Fernet token embeds the creation timestamp in cleartext (it is authenticated, not hidden), so an observer can read when a file was locked. The ciphertext length also reveals the approximate plaintext size. pydlock does not pad or hide either.
- Whole-file, in-memory. pydlock reads the entire file into memory and Fernet requires the whole message at once, so inputs must fit comfortably in RAM. Fernet is not intended for very large files; a streaming format is explicitly out of scope for pydlock.
Copyright and License
Pydlock - A Python file encryption tool.
Copyright (c) 2020 of Erick Edward Shepherd, all rights reserved.
Released under the MIT License. See the LICENSE file for the full text. Built by
Erick Shepherd.
Metadata
Release files for pydlock 2.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pydlock-2.0.7.tar.gz | 39.2 kB | With provenance | Details for pydlock-2.0.7.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pydlock-2.0.7-py3-none-any.whl | Python 3 | none | any | Details for pydlock-2.0.7-py3-none-any.whl |
Total release size: 60.2 kB
Release files / pydlock-2.0.7.tar.gz
| Download URL | pydlock-2.0.7.tar.gz |
|---|---|
| Size | 39.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6e7e85dbac45c25edd2034b09a2de071d6f59704291d4ec09af2ff8e1ae3ae8f
|
|
BLAKE2b-256 checksum How to use checksums |
17237d53f4bf3193767ae384c162d105bd624225ab9c5e3f15dfe14f420dcce6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logRelease files / pydlock-2.0.7-py3-none-any.whl
| Download URL | pydlock-2.0.7-py3-none-any.whl |
|---|---|
| Size | 21.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a03a4f73ada8fe6ff7298491f23e7c281f0789d514a1d1ebf68f339e36f5fbf0
|
|
BLAKE2b-256 checksum How to use checksums |
ad97ef4d1962d84c339b50ecc9141cd9268eca9f5337464b02ec28035b02b25d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logSecurity for pydlock 2.0.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for pydlock-2.0.7.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.