Files
2026-06-17 20:43:56 +02:00

122 lines
3.9 KiB
Python

from cryptojwt.jwk.jwk import key_from_jwk_dict
from cryptojwt.jwk.rsa import new_rsa_key
from cryptojwt.jwk.ec import new_ec_key
from cryptography.hazmat.primitives import serialization
from cryptojwt.jwk.rsa import RSAKey
from cryptojwt.jwk.ec import ECKey
from cryptography.hazmat.primitives.asymmetric import rsa, ec
from django.conf import settings
from . import settings as local_settings
DEFAULT_HASH_FUNC = getattr(
settings, "DEFAULT_HASH_FUNC", local_settings.DEFAULT_HASH_FUNC
)
def create_jwk(key=None, hash_func=None, typ: str = getattr(settings, "PRIVATE_KEY_TYPE", None)):
if key:
key = key
elif typ and typ.lower() == 'ec':
key = new_ec_key(crv="P-256")
else:
key = new_rsa_key()
thumbprint = key.thumbprint(hash_function=hash_func or DEFAULT_HASH_FUNC)
jwk = key.to_dict()
jwk["kid"] = thumbprint.decode()
return jwk
def public_jwk_from_private_jwk(jwk_dict: dict):
# exports public
_k = key_from_jwk_dict(jwk_dict)
jwk = _k.serialize()
jwk["kid"] = jwk_dict['kid']
return jwk
def private_pem_from_jwk(jwk_dict: dict):
# exports private
_k = key_from_jwk_dict(jwk_dict)
pk = _k.private_key()
pem = pk.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
return pem.decode()
def public_pem_from_jwk(jwk_dict: dict):
# exports private
_k = key_from_jwk_dict(jwk_dict)
pk = _k.public_key()
cert = pk.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
return cert.decode()
def serialize_key(key, kind="public", hash_func="SHA-256"):
"""
key can be:
- cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey
- cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey
- cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey
- cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey
- str or bytes (PEM format)
"""
data = {}
# Handle RSA keys
if isinstance(key, rsa.RSAPublicKey):
data = {"pub_key": key}
elif isinstance(key, rsa.RSAPrivateKey):
data = {"priv_key": key}
# Handle EC keys
elif isinstance(key, ec.EllipticCurvePublicKey):
data = {"pub_key": key}
elif isinstance(key, ec.EllipticCurvePrivateKey):
data = {"priv_key": key}
# Handle PEM strings/bytes
elif isinstance(key, (str, bytes)):
if kind == "private":
if isinstance(key, rsa.RSAPrivateKey) or (isinstance(key, str) and "RSA" in key):
data = {"priv_key": private_jwk_from_pem(key)}
else:
data = {"priv_key": private_jwk_from_pem(key)}
else:
if isinstance(key, rsa.RSAPublicKey) or (isinstance(key, str) and "RSA" in key):
data = {"pub_key": public_jwk_from_pem(key)}
else:
data = {"pub_key": public_jwk_from_pem(key)}
# Create appropriate JWK object based on key type
if isinstance(key, (rsa.RSAPublicKey, rsa.RSAPrivateKey)) or (isinstance(key, str) and "RSA" in key):
jwk_obj = RSAKey(**data)
else:
jwk_obj = ECKey(**data)
thumbprint = jwk_obj.thumbprint(hash_function=hash_func)
jwk = jwk_obj.to_dict()
jwk["kid"] = thumbprint.hex() # Use hex() instead of decode()
return jwk
def private_jwk_from_pem(content:str, password:str = None):
content = content.encode() if isinstance(content, str) else content
key = serialization.load_pem_private_key(content, password=password)
return serialize_key(key, kind='private')
def public_jwk_from_pem(content:str, password:str = None):
content = content.encode() if isinstance(content, str) else content
key = serialization.load_pem_public_key(content)
return serialize_key(key, kind='public')