Skip to main content

pysypt

Language Python License: MIT

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 alt-python-pysypt        # or: pip install alt-python-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.

Metadata

Release files for alt-python-pysypt 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for alt-python-pysypt 1.1.1
File Size Uploaded Provenance
alt_python_pysypt-1.1.1.tar.gz 9.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for alt-python-pysypt 1.1.1
File Interpreter ABI Platform
alt_python_pysypt-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 19.1 kB

Release files / alt_python_pysypt-1.1.1.tar.gz

Download URL alt_python_pysypt-1.1.1.tar.gz
Size 9.1 kB
Tags Source
SHA-256 checksum
How to use checksums
84fefd84deb59ee8cf30a5e12a571b59ab11533bd6a975c3904d06f5e5b944ee
BLAKE2b-256 checksum
How to use checksums
865991db6f1df9c33f9dda43cc99726207092f9e777268c7b3d36d279b4ce516
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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}

Release files / alt_python_pysypt-1.1.1-py3-none-any.whl

Download URL alt_python_pysypt-1.1.1-py3-none-any.whl
Size 9.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
60ce01c7af47091536f797c974de9fe9707aba62af2585c569b3ae98fadfbfd6
BLAKE2b-256 checksum
How to use checksums
2a45e10d77ebf8a23cfdc5729a43d153bfbdeeb3e529abece4a1b5c26ed91de5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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}

Security for alt-python-pysypt 1.1.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page