rclone-crypt-python
Pure-Python reader/writer for rclone crypt files and names.
The PyPI distribution is rclone-crypt-python; Python imports remain
rclone_crypt.
Background
This tool was written with three goals in mind:
- Proof of concept: I wanted to demonstrate that the rclone crypt format is sufficiently documented to be re-implemented, originally without the help of AI but later with it. And I wanted to demonstrate that this can be a standard used intraoperatively.
- Real utility: I wanted to work with rclone crypt without having to subprocess rclone each time.
- AI Coding Assistant Playground: When I first made this (Jan 2026, posted much later), I was new to AI coding assistants and it was a fun way to learn more.
Features
- Streamed read/write of rclone crypt files (very large files supported)
- Filename encryption/decryption (base32, base64, base32768)
- Decrypt encrypted rclone config and reveal obscured passwords
- Explicit, composable APIs for secrets, names, and file IO
Start here
Common entry points (all available from top-level rclone_crypt):
RcloneConfig: load config and derive secretsRcloneCrypt: high-level path-like interface bound to a local crypt rootCryptSecrets: explicit passwords (plain or obscured)NameCipher: encrypt/decrypt names and pathsCryptFile: stream file read/writecrypt_ls: list entries with decrypted names
Quick distinction: RcloneCrypt always works in decrypted names (it handles name
encryption for you), while CryptFile expects the encrypted on-disk path and
only handles file content encryption/decryption.
Typical flow (primary interface):
from rclone_crypt import RcloneConfig, RcloneCrypt
cfg = RcloneConfig.from_path("~/.config/rclone/rclone.conf", allow_prompt=False)
crypt = RcloneCrypt.from_config(cfg, "crypt")
path = crypt / "dir" / "file.txt"
For more examples using the high-level interface, see the high-level guide.
If you need lower-level control (config parsing, name encryption without a root, or streaming file IO), the guide also includes a mapping of high-level and low-level APIs. For advanced workflows, see advanced usage.
Non-goals
- Cloud backend implementations
- Calling rclone at runtime (tests only)
Why use this tool
- You want to inspect or manipulate rclone crypt data directly from Python.
- You need streaming read/write support without shelling out to rclone.
- You want explicit, testable crypt operations inside your own tooling.
Requirements
- Python 3.10+
- Dependencies:
cryptography,pynacl
Install
Install the latest published release from PyPI:
python -m pip install rclone-crypt-python
From a local clone:
python -m pip install -e '.[test]'
For runtime-only installs, drop the [test] extra:
python -m pip install -e .
The PyPI distribution is named rclone-crypt-python; import it as
rclone_crypt.
Quickstart
High-level interface
from rclone_crypt import RcloneConfig, RcloneCrypt
cfg = RcloneConfig.from_path("~/.config/rclone/rclone.conf", allow_prompt=False)
crypt = RcloneCrypt.from_config(cfg, "crypt")
path = crypt / "dir" / "file.txt"
path.write_text("hello", overwrite=False)
print(path.read_text())
print(crypt.ls())
Secrets
from rclone_crypt import CryptSecrets
secrets = CryptSecrets.from_passwords("password", "password2")
Or from obscured config values:
from rclone_crypt import CryptSecrets
secrets = CryptSecrets.from_obscured(
"vENjtZL-E-6OQ77fGY6H4WwF57s",
"DJrXvTm8658avycmzDjpASEMuiI",
)
Obscure / reveal
from rclone_crypt import obscure, reveal
obscured = obscure("password")
plaintext = reveal(obscured)
Decrypt rclone config
from rclone_crypt import RcloneConfig
cfg = RcloneConfig.from_path(
"~/.config/rclone/rclone.conf",
password=None,
allow_prompt=True,
)
# Convenience aliases:
cfg = RcloneConfig("~/.config/rclone/rclone.conf", allow_prompt=True)
cfg = RcloneConfig.load("~/.config/rclone/rclone.conf", allow_prompt=True)
section = cfg.section("crypt")
To encrypt config content:
from rclone_crypt import encrypt_config
data = b"[remote]\ntype = crypt\n"
encrypted = encrypt_config(data, "config-password")
Password sourcing order:
- Explicit
passwordargument password_commandargument orRCLONE_PASSWORD_COMMANDRCLONE_CONFIG_PASS- Prompt (if
allow_prompt=True)
By default, config passwords are treated as obscured (rclone's default):
secrets = cfg.get_crypt_secrets("crypt", passwords_are_obscured=True)
secrets = cfg.get_crypt_secrets("crypt") # defaults to obscured
Build a name cipher directly from the config section:
name_cipher = cfg.get_name_cipher("crypt", passwords_are_obscured=True)
Or get both secrets and name cipher together:
bundle = cfg.get_crypt_remote("crypt", passwords_are_obscured=True)
secrets = bundle.secrets
name_cipher = bundle.name_cipher
Password source examples:
export RCLONE_CONFIG_PASS="my-config-password"
export RCLONE_PASSWORD_COMMAND="pass show rclone/config"
cfg = RcloneConfig.from_path("~/.config/rclone/rclone.conf", password="my-config-password")
cfg = RcloneConfig.from_path("~/.config/rclone/rclone.conf", allow_prompt=True)
Filename encryption
from rclone_crypt import CryptSecrets, NameCipher
secrets = CryptSecrets.from_passwords("password", "password2")
name_cipher = NameCipher(
secrets,
filename_encryption="standard",
directory_name_encryption=True,
filename_encoding="base32",
)
encrypted = name_cipher.encrypt_path("dir/file.txt")
decrypted = name_cipher.decrypt_path(encrypted)
File encryption/decryption
from rclone_crypt import CryptFile, CryptSecrets
secrets = CryptSecrets.from_passwords("password", "password2")
with CryptFile.open_write("encrypted.bin", secrets=secrets) as writer:
writer.write(b"hello")
with CryptFile.open_read("encrypted.bin", secrets=secrets) as reader:
data = reader.read()
You can also use standard file-like modes:
with CryptFile.open("encrypted.bin", "rt", secrets=secrets) as reader:
text = reader.read()
Decrypted listing helper
from rclone_crypt import crypt_ls
for entry in crypt_ls("encrypted_dir", name_cipher):
print(entry.name, entry.path)
Tutorial
See the tutorial for step-by-step user stories, including writing new files with correct name encoding, reading by plaintext name, and listing directories.
Additional docs
Testing
Unit tests:
scripts/test_unit.sh
Interop tests (requires rclone in PATH):
scripts/test_interop.sh
Security notes
- rclone "obscure" is not strong encryption; it only deters casual viewing.
- Config encryption uses NaCl secretbox with a SHA-256 derived key.
Troubleshooting and common pitfalls
- Config password confusion: rclone config encryption password is different
from remote passwords. Make sure you use the config password for
RcloneConfig.from_path. - Hidden password command: if
RCLONE_PASSWORD_COMMANDis set in your shell, it will be used unless you provide an explicit password. - Name options mismatch:
filename_encryption,directory_name_encryption,filename_encoding, andsuffixmust match your rclone remote settings. - Append mode not supported: encrypted files cannot be appended without rewriting the last block. Use write mode and rewrite the file if needed.
- Logging: the library emits extensive debug logging in core modules
(names, files, config, and high-level paths). By default nothing is shown
unless you configure logging (e.g.,
logging.basicConfig(level=logging.DEBUG)).
References
- rclone crypt docs: https://rclone.org/crypt/
- rclone obscure docs: https://rclone.org/commands/rclone_obscure/
- rclone source (crypt backend): https://github.com/rclone/rclone/tree/master/backend/crypt
## AI/LLM Disclosure
As noted in the motivation, a substantial portion of this code was produced with the assistance of large language models (LLMs), primarily various versions of ChatGPT 5+ used through Codex. For all intents and purposes, it was “vibe coded.” This disclosure is intentional: I am not attempting to present the implementation as primarily human-written or to obscure the extent of LLM involvement.
The resulting code has nevertheless been exercised through both LLM-generated test cases and real-world use in complex settings. While LLMs were heavily involved in its implementation, the software has been evaluated based on its observed behavior rather than assumed correctness.
Release files for rclone-crypt-python 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rclone_crypt_python-0.2.0.tar.gz | 29.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rclone_crypt_python-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.0 kB
Release files / rclone_crypt_python-0.2.0.tar.gz
| Download URL | rclone_crypt_python-0.2.0.tar.gz |
|---|---|
| Size | 29.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd9fb9c0984f6a42411525180c5dd81d2bed8d57b181df9a95526e6e00b7a7e2
|
|
BLAKE2b-256 checksum How to use checksums |
929505464b6a9510940c8131dc050300ebb3acf86531e367e11d12ad422e3d95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / rclone_crypt_python-0.2.0-py3-none-any.whl
| Download URL | rclone_crypt_python-0.2.0-py3-none-any.whl |
|---|---|
| Size | 28.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cb3ff67bb3fe883d7e70dfa305371ccee8c73cde53c27a3afdd627ab405900d4
|
|
BLAKE2b-256 checksum How to use checksums |
8e6d3e3d9216b08561bceba15d63691b077ef81c22e72fb9291bc387b270885d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|