purejks
A pure-Python Java KeyStore file parser, including private/secret key decryption. Can read JKS, JCEKS, BKS and UBER (BouncyCastle) key stores.
purejks is a fork of pyjks that installs
without a C compiler. pyjks depends on the twofish
package, which is only published as a source distribution containing a C extension:
installing pyjks therefore requires cc, which is often missing from slim Docker images
and CI runners. Moreover, that package uses the imp module, removed in Python 3.12, so
reading UBER keystores with pyjks fails on recent Pythons.
purejks replaces it with a bundled, pure-Python Twofish implementation (derived from
K-Czaplicki/TwoFish and optimized), and ships
as a universal py3-none-any wheel. All other dependencies provide wheels or are pure Python.
The import name is unchanged (import jks), so purejks is a drop-in replacement:
uninstall pyjks and install purejks (do not install both, they provide the same module).
pip uninstall pyjks
pip install purejks
The best way to utilize a certificate stored in a jks file up to this point has been to use the java keytool command to transform to pkcs12, and then openssl to transform to pem.
This is better:
- no security concerns in passwords going into command line arguments, or unencrypted files being left around
- no dependency on a JVM
- no compiler needed to install it
Requirements:
- Python 3.9+
- pyasn1 0.3.5+
- pyasn1_modules
- javaobj-py3
- pycryptodomex
Development
The project uses uv, ruff and ty:
uv sync
uv run pytest
uv run ruff check . && uv run ruff format --check .
uv run ty check
Releases are published to PyPI by GitHub Actions (trusted publishing) when a
GitHub release is published; the tag must match the version in pyproject.toml (v1.0.0).
Usage examples:
Reading a JKS or JCEKS keystore and dumping out its contents in the PEM format:
import sys, base64, textwrap
import jks
def print_pem(der_bytes, type):
print("-----BEGIN %s-----" % type)
print("\r\n".join(textwrap.wrap(base64.b64encode(der_bytes).decode("ascii"), 64)))
print("-----END %s-----" % type)
ks = jks.KeyStore.load("keystore.jks", "XXXXXXXX")
# if any of the keys in the store use a password that is not the same as the store password:
# ks.entries["key1"].decrypt("key_password")
for alias, pk in ks.private_keys.items():
print("Private key: %s" % pk.alias)
if pk.algorithm_oid == jks.util.RSA_ENCRYPTION_OID:
print_pem(pk.pkey, "RSA PRIVATE KEY")
else:
print_pem(pk.pkey_pkcs8, "PRIVATE KEY")
for c in pk.cert_chain:
print_pem(c[1], "CERTIFICATE")
print()
for alias, c in ks.certs.items():
print("Certificate: %s" % c.alias)
print_pem(c.cert, "CERTIFICATE")
print()
for alias, sk in ks.secret_keys.items():
print("Secret key: %s" % sk.alias)
print(" Algorithm: %s" % sk.algorithm)
print(" Key size: %d bits" % sk.key_size)
print(" Key: %s" % "".join("{:02x}".format(b) for b in bytearray(sk.key)))
print()
Transforming an encrypted JKS/JCEKS file into an OpenSSL context:
import OpenSSL
import jks
_ASN1 = OpenSSL.crypto.FILETYPE_ASN1
def jksfile2context(jks_file, passphrase, key_alias, key_password=None):
keystore = jks.KeyStore.load(jks_file, passphrase)
pk_entry = keystore.private_keys[key_alias]
# if the key could not be decrypted using the store password, decrypt with a custom password now
if not pk_entry.is_decrypted():
pk_entry.decrypt(key_password)
pkey = OpenSSL.crypto.load_privatekey(_ASN1, pk_entry.pkey)
public_cert = OpenSSL.crypto.load_certificate(_ASN1, pk_entry.cert_chain[0][1])
trusted_certs = [OpenSSL.crypto.load_certificate(_ASN1, cert.cert) for alias, cert in keystore.certs]
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
ctx.use_privatekey(pkey)
ctx.use_certificate(public_cert)
ctx.check_privatekey() # want to know ASAP if there is a problem
cert_store = ctx.get_cert_store()
for cert in trusted_certs:
cert_store.add_cert(cert)
return ctx
Metadata
Release files for purejks 1.0.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 | |
|---|---|---|---|
| purejks-1.0.0.tar.gz | 27.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| purejks-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.4 kB
Release files / purejks-1.0.0.tar.gz
| Download URL | purejks-1.0.0.tar.gz |
|---|---|
| Size | 27.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f032fefec818f286093054f8b092cebb0b7c5f8ff69165647725917fa89cb01f
|
|
BLAKE2b-256 checksum How to use checksums |
fc16655b06b870d96de9f08b5539dba9e80002c675364f0eb31ab874aad9ad0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Sep 23, 2026.
Transparency logRelease files / purejks-1.0.0-py3-none-any.whl
| Download URL | purejks-1.0.0-py3-none-any.whl |
|---|---|
| Size | 31.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4933b871db11801b85528597b54ec9b04f4856125f6fd7a64dab163001cdeed3
|
|
BLAKE2b-256 checksum How to use checksums |
296fae2634887c6d56eb89b22414e11cd4e61ca03cdbc837c7677883c46363f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Sep 23, 2026.
Transparency log