first commit

This commit is contained in:
linkitapps
2026-09-14 23:22:10 +09:00
commit 9f9c8fb69b
4207 changed files with 1333187 additions and 0 deletions
@@ -0,0 +1,117 @@
from .._rfc7516.models import Recipient, JWEKeyAgreement, JWEKeyWrapping, JWEEncModel
from .._rfc7518.jwe_algs import (
A128KW,
A192KW,
A256KW,
)
from .._rfc7518.ec_key import ECKey
from .._rfc7518.derive_key import (
derive_key_for_concat_kdf,
)
from .._rfc7518.jwe_encs import CBCHS2EncModel
from ..registry import HeaderParameter
from ..errors import InvalidEncryptionAlgorithmError
__all__ = ["ECDH1PUAlgModel", "register_ecdh_1pu", "JWE_ALG_MODELS"]
class ECDH1PUAlgModel(JWEKeyAgreement):
"""Key Agreement with Elliptic Curve Diffie-Hellman One-Pass Unified Model (ECDH-1PU)
https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04
"""
more_header_registry = {
"epk": HeaderParameter("Ephemeral Public Key", "jwk", True),
"apu": HeaderParameter("Agreement PartyUInfo", "str"),
"apv": HeaderParameter("Agreement PartyVInfo", "str"),
"skid": HeaderParameter("Sender Key ID", "str"),
}
key_types = ["EC", "OKP"]
tag_aware = True
def __init__(self, key_wrapping: JWEKeyWrapping | None):
if key_wrapping is None:
self.name = "ECDH-1PU"
self.description = "ECDH-1PU using one-pass KDF and CEK in the Direct Key Agreement mode"
self.key_size = None
else:
self.name = f"ECDH-1PU+{key_wrapping.name}"
self.description = f"ECDH-1PU using one-pass KDF and CEK wrapped with {key_wrapping.name}"
self.key_size = key_wrapping.key_size
self.key_wrapping = key_wrapping
def _check_enc(self, enc: JWEEncModel) -> None:
# https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04#section-2.1
# The AES_CBC_HMAC_SHA2 algorithms described in section 5.2 of [RFC7518] are compactly
# committing and can be used with ECDH-1PU in Key Agreement with Key Wrapping mode.
# Other content encryption algorithms MUST be rejected. In Direct Key Agreement
# mode, any JWE content encryption algorithm MAY be used.
if self.key_wrapping and not isinstance(enc, CBCHS2EncModel):
description = (
"In key agreement with key wrapping mode ECDH-1PU algorithm "
"only supports AES_CBC_HMAC_SHA2 family encryption algorithms"
)
raise InvalidEncryptionAlgorithmError(description)
def encrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey]) -> bytes:
self._check_enc(enc)
return self.__encrypt_agreed_upon_key(enc, recipient, None)
def encrypt_agreed_upon_key_with_tag(self, enc: JWEEncModel, recipient: Recipient[ECKey], tag: bytes) -> bytes:
self._check_enc(enc)
return self.__encrypt_agreed_upon_key(enc, recipient, tag)
def decrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey]) -> bytes:
return self.__decrypt_agreed_upon_key(enc, recipient, None)
def decrypt_agreed_upon_key_with_tag(self, enc: JWEEncModel, recipient: Recipient[ECKey], tag: bytes) -> bytes:
return self.__decrypt_agreed_upon_key(enc, recipient, tag)
def __encrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey], tag: bytes | None) -> bytes:
sender_key = recipient.sender_key
recipient_key = recipient.recipient_key
ephemeral_key = recipient.ephemeral_key
assert sender_key is not None
assert recipient_key is not None
assert ephemeral_key is not None
sender_shared_key = sender_key.exchange_derive_key(recipient_key)
ephemeral_shared_key = ephemeral_key.exchange_derive_key(recipient_key)
shared_key = ephemeral_shared_key + sender_shared_key
headers = recipient.headers()
return derive_key_for_concat_kdf(shared_key, headers, enc.cek_size, self.key_size, tag)
def __decrypt_agreed_upon_key(self, enc: JWEEncModel, recipient: Recipient[ECKey], tag: bytes | None) -> bytes:
self._check_enc(enc)
headers = recipient.headers()
assert "epk" in headers
sender_key = recipient.sender_key
recipient_key = recipient.recipient_key
assert sender_key is not None
assert recipient_key is not None
ephemeral_key = recipient_key.import_key(headers["epk"])
sender_shared_key = recipient_key.exchange_derive_key(sender_key)
ephemeral_shared_key = recipient_key.exchange_derive_key(ephemeral_key)
shared_key = ephemeral_shared_key + sender_shared_key
return derive_key_for_concat_kdf(shared_key, headers, enc.cek_size, self.key_size, tag)
JWE_ALG_MODELS = [
ECDH1PUAlgModel(None), # ECDH-1PU
ECDH1PUAlgModel(A128KW), # ECDH-1PU+A128KW
ECDH1PUAlgModel(A192KW), # ECDH-1PU+A192KW
ECDH1PUAlgModel(A256KW), # ECDH-1PU+A256KW
]
def register_ecdh_1pu() -> None:
from ..jwe import JWERegistry
from ..jwk import KeySet
for model in JWE_ALG_MODELS:
JWERegistry.register(model)
KeySet.algorithm_keys[model.name] = model.key_types