Jasypt-compatible PBE encryption and digest for Python
Project description
pysypt
Jasypt-compatible password-based encryption (PBE) and iterated-hash digest for
Python. Interoperable with Spring Boot applications that use ENC(...) encrypted
configuration values.
Port of @alt-javascript/jasypt to
Python.
Install
uv add pysypt # or: pip install pysypt
Requires Python 3.12+ and cryptography >= 42.
Quick Start
from pysypt import Jasypt
jasypt = Jasypt()
# Encrypt and decrypt
ciphertext = jasypt.encrypt("admin", "mySecretKey")
plaintext = jasypt.decrypt(ciphertext, "mySecretKey")
# plaintext == "admin"
# One-way digest
stored = jasypt.digest("admin")
jasypt.matches("admin", stored) # True
jasypt.matches("wrong", stored) # False
API
Jasypt
High-level facade. Each method constructs a fresh Encryptor or Digester
internally — the Jasypt class is stateless and thread-safe.
jasypt.encrypt(message, password, algorithm="PBEWITHMD5ANDDES", iterations=1000, salt=None)
Encrypts a plaintext string. Returns a base64-encoded ciphertext with the salt prepended.
Returns None if message is empty or None.
jasypt.encrypt("admin", "secret")
# => "nsbC5r0ymz740/aURtuRWw=="
jasypt.encrypt("admin", "secret", algorithm="PBEWITHHMACSHA256ANDAES_256")
# => "K3q8z..." (AES-256-CBC, PBKDF2-SHA256)
jasypt.decrypt(encrypted_message, password="", algorithm="PBEWITHMD5ANDDES", iterations=1000, salt=None)
Decrypts a base64-encoded ciphertext. The salt is extracted from the ciphertext automatically.
Returns None if encrypted_message is empty or None.
jasypt.decrypt("nsbC5r0ymz740/aURtuRWw==", "secret")
# => "admin"
jasypt.digest(message, salt=None, iterations=1000, algorithm="SHA-256")
Produces a one-way hash. Returns base64(salt_bytes + hash_bytes).
Returns None if message is empty or None.
stored = jasypt.digest("admin")
jasypt.matches(message, stored_digest, salt=None, iterations=1000, algorithm="SHA-256")
Verifies a plaintext message against a stored digest. Uses constant-time comparison.
Returns None if message is empty or None.
stored = jasypt.digest("admin")
jasypt.matches("admin", stored) # True
jasypt.matches("wrong", stored) # False
Encryptor
Low-level class for direct control over encryption parameters.
from pysypt import Encryptor
enc = Encryptor(
algorithm="PBEWITHHMACSHA256ANDAES_256",
iterations=10000,
)
ciphertext = enc.encrypt("admin", "secret")
plaintext = enc.decrypt(ciphertext, "secret")
Constructor
Encryptor(algorithm="PBEWITHMD5ANDDES", salt=None, iterations=1000)
| Parameter | Type | Default | Description |
|---|---|---|---|
algorithm |
str |
PBEWITHMD5ANDDES |
PBE algorithm name (see table below) |
salt |
bytes | None |
random | Salt bytes. None generates a random salt of the correct length. |
iterations |
int |
1000 |
KDF iteration count |
Methods
| Method | Description |
|---|---|
set_algorithm(algorithm) |
Change the algorithm. Raises ValueError for unsupported names. |
set_salt(salt) |
Set the salt. Accepts bytes, str (UTF-8 encoded), or None (random). Short salts are zero-padded; long salts are truncated to the required length. |
set_iterations(iterations) |
Set the iteration count. |
encrypt(payload, password, salt=None, iterations=None) |
Encrypt. Returns base64 string. |
decrypt(payload, password, iterations=None) |
Decrypt. Returns plaintext string. |
Digester
Low-level class for direct control over digest parameters.
from pysypt import Digester
d = Digester(algorithm="SHA-512", iterations=5000)
d.set_salt("fixedsalt")
stored = d.digest("admin")
is_match = d.matches("admin", stored) # True
Constructor
Digester(algorithm="SHA-256", salt=None, iterations=1000)
| Parameter | Type | Default | Description |
|---|---|---|---|
algorithm |
str |
SHA-256 |
Digest algorithm name (see table below) |
salt |
str | None |
random per digest | Fixed salt string. If None, a random 8-byte salt is generated per call. |
iterations |
int |
1000 |
Hash iteration count |
Methods
| Method | Description |
|---|---|
set_algorithm(algorithm) |
Change the algorithm. Raises ValueError for unsupported names. |
set_salt(salt) |
Set a fixed salt. |
set_iterations(iterations) |
Set the iteration count. |
digest(message, salt=None, iterations=None) |
Produce base64(salt + hash). |
matches(message, stored_digest, salt=None, iterations=None) |
Constant-time verification. |
Supported Algorithms
Encryption
| Algorithm | Type | Notes |
|---|---|---|
PBEWITHMD5ANDDES |
PBE1 | Default. EVP_BytesToKey KDF + DES-CBC. See ADR-005. |
PBEWITHMD5ANDTRIPLEDES |
PBE1 | EVP_BytesToKey KDF + 3DES-CBC |
PBEWITHSHA1ANDDESEDE |
PBE1 | EVP_BytesToKey KDF (SHA-1) + 3DES-CBC |
PBEWITHHMACSHA1ANDAES_128 |
PBE2 | PBKDF2-SHA1 + AES-128-CBC |
PBEWITHHMACSHA1ANDAES_256 |
PBE2 | PBKDF2-SHA1 + AES-256-CBC |
PBEWITHHMACSHA224ANDAES_128 |
PBE2 | PBKDF2-SHA224 + AES-128-CBC |
PBEWITHHMACSHA224ANDAES_256 |
PBE2 | PBKDF2-SHA224 + AES-256-CBC |
PBEWITHHMACSHA256ANDAES_128 |
PBE2 | PBKDF2-SHA256 + AES-128-CBC |
PBEWITHHMACSHA256ANDAES_256 |
PBE2 | PBKDF2-SHA256 + AES-256-CBC (recommended) |
PBEWITHHMACSHA384ANDAES_128 |
PBE2 | PBKDF2-SHA384 + AES-128-CBC |
PBEWITHHMACSHA384ANDAES_256 |
PBE2 | PBKDF2-SHA384 + AES-256-CBC |
PBEWITHHMACSHA512ANDAES_128 |
PBE2 | PBKDF2-SHA512 + AES-128-CBC |
PBEWITHHMACSHA512ANDAES_256 |
PBE2 | PBKDF2-SHA512 + AES-256-CBC |
PBE1 uses an iterative MD5/SHA-1 KDF (EVP_BytesToKey-style) with an 8-byte salt prepended to the ciphertext.
PBE2 uses PBKDF2 with a 16-byte salt and a random 16-byte IV, both prepended to the ciphertext.
RC2 and RC4 variants are not supported — see ADR-006.
Digest
| Algorithm | Available by default |
|---|---|
MD5 |
✅ |
SHA-1 |
✅ |
SHA-224 |
✅ |
SHA-256 |
✅ (default) |
SHA-384 |
✅ |
SHA-512 |
✅ |
SHA-512/224 |
✅ |
SHA-512/256 |
✅ |
SHA3-224 |
✅ |
SHA3-256 |
✅ |
SHA3-384 |
✅ |
SHA3-512 |
✅ |
MD2 |
Rarely available |
Digester.SUPPORTED_ALGORITHMS reflects only algorithms available in the current
OpenSSL build. Digester.set_algorithm("MD2") raises ValueError if MD2 is
unavailable.
Wire Format
Both classes produce self-describing base64 ciphertext — the salt (and IV for PBE2) is stored inline so decryption requires only the password:
PBE1: base64( salt[8] + ciphertext )
PBE2: base64( salt[16] + iv[16] + ciphertext )
Digest: base64( salt[8] + hash_bytes )
Java Interoperability
PBE2 algorithms (PBEWITHHMACSHA*ANDAES_*) are fully interoperable with Java
jasypt. If you encrypt a value in Java using PBEWITHHMACSHA256ANDAES_256 and
the same password, pysypt will decrypt it correctly.
PBE1 DES (PBEWITHMD5ANDDES) is not byte-for-byte compatible with Java due
to the TripleDES-EDE emulation (ADR-005). Use a PBE2 algorithm for cross-language
scenarios.
Troubleshooting
ValueError: Unsupported algorithm: MYALGO
The algorithm name is not in the supported list. Check spelling and case — names
must match exactly (e.g. PBEWITHHMACSHA256ANDAES_256).
Decryption produces garbled text The password or algorithm does not match what was used to encrypt. Both the encryptor and decryptor must use the same algorithm and password.
ValueError: Invalid padding bytes
The ciphertext is corrupt, truncated, or was encrypted with a different algorithm.
This can also occur if the base64 string was URL-encoded and not decoded first.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file alt_python_pysypt-1.0.1.tar.gz.
File metadata
- Download URL: alt_python_pysypt-1.0.1.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94ffb66a63611c9492ad6ae6ddfe4b2ef61fd358d5141f0e85d8dc83856b0e7b
|
|
| MD5 |
aba97fa490496c6bea88bf01c08043d5
|
|
| BLAKE2b-256 |
43d454858241ff5f05ce96d31a6e049ae1530d01f30954d55fcb1610fb60c3e5
|
File details
Details for the file alt_python_pysypt-1.0.1-py3-none-any.whl.
File metadata
- Download URL: alt_python_pysypt-1.0.1-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
031b0f1abc42f376d5db3681d5cf45aa8ee382569836bb9cbb23346250712410
|
|
| MD5 |
80c4922b15bd45766caf400253b4945a
|
|
| BLAKE2b-256 |
9f0eb72999a9d8c2574d871f46ff81ebd374ebfd90475defde2eba110e179cd7
|