Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more convenience methods #22

Merged
merged 9 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
Expand All @@ -21,20 +21,18 @@ repos:
- --in-place
- --wrap-summaries=100
- --wrap-descriptions=100
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/asottile/blacken-docs
rev: 1.16.0
hooks:
- id: blacken-docs
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
rev: v0.1.11
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.8.0
hooks:
- id: mypy
args:
Expand All @@ -48,3 +46,4 @@ repos:
- pytest-mypy==0.10.3
- binapy==0.7.0
- freezegun==1.2.2
- jwcrypto==1.5.0
52 changes: 29 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@ from jwskate import Jwk

# Let's generate a random private key, to use with alg 'RS256'.
# Based on that alg, jwskate knows it must be an RSA key.
# RSA keys can be of variable size, so let's pass the requested key size as parameter
# RSA keys can be of any size, so let's pass the requested key size as parameter
rsa_private_jwk = Jwk.generate(alg="RS256", key_size=2048)

data = b"Signing is easy!" # we will sign this
signature = rsa_private_jwk.sign(data) # done!

print(signature)
# b'-\xe89\x81\xc4\xb9.G\x11\xa6\x93/dm\xf0\xc8\x0f\xd....'

# now extract the public key, and verify the signature with it
rsa_public_jwk = rsa_private_jwk.public_jwk()
assert rsa_public_jwk.verify(data, signature)

# let's see what a Jwk looks like:
assert isinstance(rsa_private_jwk, dict) # Jwk are dict
# let's see what a `Jwk` looks like:
assert isinstance(rsa_private_jwk, dict) # Jwk are dict subclasses

print(rsa_private_jwk.with_usage_parameters())
```
Expand Down Expand Up @@ -98,13 +101,13 @@ assert jwt.verify_signature(private_jwk.public_jwk(), alg="ES256")
# or with `alg` or `algs` params, and will ignore the 'alg' that is set in the JWT, for security reasons.
```

Now let's sign a JWT with the standardised lifetime, subject, audience and ID claims, plus arbitrary custom claims:
Now let's sign a JWT with the standardized lifetime, subject, audience and ID claims, plus arbitrary custom claims:

```python
from jwskate import Jwk, JwtSigner

private_jwk = Jwk.generate(alg="ES256")
signer = JwtSigner(issuer="https://myissuer.com", jwk=private_jwk)
signer = JwtSigner(issuer="https://myissuer.com", key=private_jwk)
jwt = signer.sign(
subject="some_sub",
audience="some_aud",
Expand All @@ -114,7 +117,7 @@ jwt = signer.sign(
print(jwt.claims)
```

The generated JWT will include the standardised claims (`iss`, `aud`, `sub`, `iat`, `exp` and `jti`),
The generated JWT will include the standardized claims (`iss`, `aud`, `sub`, `iat`, `exp` and `jti`),
together with the `extra_claims` provided to `.sign()`:

```
Expand Down Expand Up @@ -163,18 +166,31 @@ together with the `extra_claims` provided to `.sign()`:
| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `RSA` | [RFC7518, Section 3.3] | |
| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `RSA` | [RFC7518, Section 3.3] | |
| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `RSA` | [RFC7518, Section 3.3] | |
| `ES256` | ECDSA using P-256 and SHA-256 | `EC` | [RFC7518, Section 3.4] | |
| `ES384` | ECDSA using P-384 and SHA-384 | `EC` | [RFC7518, Section 3.4] | |
| `ES512` | ECDSA using P-521 and SHA-512 | `EC` | [RFC7518, Section 3.4] | |
| `PS256` | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 | `RSA` | [RFC7518, Section 3.5] | |
| `PS384` | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 | `RSA` | [RFC7518, Section 3.5] | |
| `PS512` | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 | `RSA` | [RFC7518, Section 3.5] | |
| `EdDSA` | EdDSA signature algorithms | `OKP` | [RFC8037, Section 3.1] | Ed2219 and Ed448 are supported |
| `ES256` | ECDSA using P-256 and SHA-256 | `EC` | [RFC7518, Section 3.4] | |
| `ES384` | ECDSA using P-384 and SHA-384 | `EC` | [RFC7518, Section 3.4] | |
| `ES512` | ECDSA using P-521 and SHA-512 | `EC` | [RFC7518, Section 3.4] | |
| `ES256K` | ECDSA using secp256k1 curve and SHA-256 | `EC` | [RFC8812, Section 3.2] | |
| `EdDSA` | EdDSA signature algorithms | `OKP` | [RFC8037, Section 3.1] | Ed2219 and Ed448 are supported |
| `HS1` | HMAC using SHA-1 | `oct` | https://www.w3.org/TR/WebCryptoAPI | Validation Only |
| `RS1` | RSASSA-PKCS1-v1_5 with SHA-1 | `oct` | https://www.w3.org/TR/WebCryptoAPI | Validation Only |
| `RS1` | RSASSA-PKCS1-v1_5 with SHA-1 | `RSA` | https://www.w3.org/TR/WebCryptoAPI | Validation Only |
| `none` | No digital signature or MAC performed | | [RFC7518, Section 3.6] | Not usable by mistake |

### Supported Encryption algorithms


| Signature Alg | Description | Reference |
|-----------------|-------------------------------------------------------------|--------------------------|
| `A128CBC-HS256` | AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm | [RFC7518, Section 5.2.3] |
| `A192CBC-HS384` | AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm | [RFC7518, Section 5.2.4] |
| `A256CBC-HS512` | AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm | [RFC7518, Section 5.2.5] |
| `A128GCM` | AES GCM using 128-bit key | [RFC7518, Section 5.3] |
| `A192GCM` | AES GCM using 192-bit key | [RFC7518, Section 5.3] |
| `A256GCM` | AES GCM using 256-bit key | [RFC7518, Section 5.3] |


### Supported Key Management algorithms


Expand All @@ -200,18 +216,8 @@ together with the `extra_claims` provided to `.sign()`:
| `PBES2-HS384+A192KW` | PBES2 with HMAC SHA-384 and "A192KW" wrapping | `password` | [RFC7518, Section 4.8] | |
| `PBES2-HS512+A256KW` | PBES2 with HMAC SHA-512 and "A256KW" wrapping | `password` | [RFC7518, Section 4.8] | |

### Supported Encryption algorithms


| Signature Alg | Description | Reference |
| ------------- | ----------------------------------------------------------- | ------------------------ |
| `A128CBC-HS256` | AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm | [RFC7518, Section 5.2.3] |
| `A192CBC-HS384` | AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm | [RFC7518, Section 5.2.4] |
| `A256CBC-HS512` | AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm | [RFC7518, Section 5.2.5] |
| `A128GCM` | AES GCM using 128-bit key | [RFC7518, Section 5.3] |
| `A192GCM` | AES GCM using 192-bit key | [RFC7518, Section 5.3] |
| `A256GCM` | AES GCM using 256-bit key | [RFC7518, Section 5.3] |

### Supported Elliptic Curves


Expand All @@ -220,13 +226,13 @@ together with the `extra_claims` provided to `.sign()`:
| `P-256` | P-256 Curve | `EC` | signature, encryption | [RFC7518, Section 6.2.1.1] |
| `P-384` | P-384 Curve | `EC` | signature, encryption | [RFC7518, Section 6.2.1.1] |
| `P-521` | P-521 Curve | `EC` | signature, encryption | [RFC7518, Section 6.2.1.1] |
| `secp256k1` | SECG secp256k1 curve | `EC` | signature, encryption | [RFC8812, Section 3.1] |
| `Ed25519` | Ed25519 signature algorithm key pairs | `OKP` | signature | [RFC8037, Section 3.1] |
| `Ed448` | Ed448 signature algorithm key pairs | `OKP` | signature | [RFC8037, Section 3.1] |
| `X25519` | X25519 function key pairs | `OKP` | encryption | [RFC8037, Section 3.2] |
| `X448` | X448 function key pairs | `OKP` | encryption | [RFC8037, Section 3.2] |
| `secp256k1` | SECG secp256k1 curve | `EC` | signature, encryption | [RFC8812, Section 3.1] |

## Why a new lib ?
## Why a new lib?

There are already multiple modules implementing JOSE and Json Web Crypto related specifications in Python. However, I
have been dissatisfied by all of them so far, so I decided to come up with my own module.
Expand Down
4 changes: 2 additions & 2 deletions jwskate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
provides a set of convenient wrappers around the `cryptography` module.

"""

from __future__ import annotations

__author__ = """Guillaume Pujol"""
Expand Down Expand Up @@ -97,12 +98,11 @@
select_alg_classes,
to_jwk,
)
from .jws import InvalidJws, JwsCompact, JwsJsonFlat, JwsJsonGeneral, JwsSignature
from .jws import InvalidJws, InvalidSignature, JwsCompact, JwsJsonFlat, JwsJsonGeneral, JwsSignature
from .jwt import (
ExpiredJwt,
InvalidClaim,
InvalidJwt,
InvalidSignature,
Jwt,
JwtSigner,
JwtVerifier,
Expand Down
1 change: 1 addition & 0 deletions jwskate/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
See [IANA JOSE](https://www.iana.org/assignments/jose/jose.xhtml).

"""

from __future__ import annotations


Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
[RFC7518]: https://www.rfc-editor.org/rfc/rfc7518

"""

from __future__ import annotations

from .base import (
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implement base classes for the algorithms defined in JWA."""

from __future__ import annotations

from contextlib import contextmanager
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/ec.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module contains classes that describe Elliptic Curves as described in RFC7518."""

from __future__ import annotations

from dataclasses import dataclass
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/encryption/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module exposes the Encryption algorithms that are available in `jwskate`."""

from __future__ import annotations

from .aescbchmac import A128CBC_HS256, A192CBC_HS384, A256CBC_HS512
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/encryption/aescbchmac.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements AES-CBC with HMAC-SHA based Encryption algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/encryption/aesgcm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements AES-GCM based encryption algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module exposes all Key Management algorithms available in `jwskate`."""

from __future__ import annotations

from .aesgcmkw import A128GCMKW, A192GCMKW, A256GCMKW, BaseAesGcmKeyWrap
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/aesgcmkw.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements AES-GCM based Key Management algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/aeskw.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements AES based Key Management algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/dir.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements direct use of a shared symmetric key as Key Management algorithm."""

from __future__ import annotations

from binapy import BinaPy
Expand Down
17 changes: 9 additions & 8 deletions jwskate/jwa/key_mgmt/ecdh.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements Elliptic Curve Diffie-Hellman based Key Management algorithms."""

from __future__ import annotations

from typing import Any, SupportsBytes, Union
Expand Down Expand Up @@ -65,8 +66,8 @@ def otherinfo(cls, alg: str, apu: bytes, apv: bytes, key_size: int) -> BinaPy:
@classmethod
def ecdh(
cls,
private_key: (ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey),
public_key: (ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey),
private_key: ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey,
public_key: ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey,
) -> BinaPy:
"""Perform an Elliptic Curve Diffie-Hellman key exchange.

Expand Down Expand Up @@ -104,8 +105,8 @@ def ecdh(
def derive(
cls,
*,
private_key: (ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey),
public_key: (ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey),
private_key: ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey,
public_key: ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey,
otherinfo: bytes,
key_size: int,
) -> BinaPy:
Expand Down Expand Up @@ -143,7 +144,7 @@ def generate_ephemeral_key(

def sender_key(
self,
ephemeral_private_key: (ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey),
ephemeral_private_key: ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey,
*,
alg: str,
key_size: int,
Expand Down Expand Up @@ -175,7 +176,7 @@ def sender_key(

def recipient_key(
self,
ephemeral_public_key: (ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey),
ephemeral_public_key: ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey,
*,
alg: str,
key_size: int,
Expand Down Expand Up @@ -214,7 +215,7 @@ class BaseEcdhEs_AesKw(EcdhEs): # noqa: N801
def wrap_key_with_epk(
self,
plainkey: bytes,
ephemeral_private_key: (ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey),
ephemeral_private_key: ec.EllipticCurvePrivateKey | x25519.X25519PrivateKey | x448.X448PrivateKey,
**headers: Any,
) -> BinaPy:
"""Wrap a key for content encryption.
Expand All @@ -234,7 +235,7 @@ def wrap_key_with_epk(
def unwrap_key_with_epk(
self,
cipherkey: bytes | SupportsBytes,
ephemeral_public_key: (ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey),
ephemeral_public_key: ec.EllipticCurvePublicKey | x25519.X25519PublicKey | x448.X448PublicKey,
**headers: Any,
) -> BinaPy:
"""Unwrap a key for content decryption.
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/pbes2.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements password-based Key Management Algorithms relying on PBES2."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/key_mgmt/rsa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements RSA based Key Management algorithms."""

from __future__ import annotations

from typing import Any, SupportsBytes
Expand Down
7 changes: 5 additions & 2 deletions jwskate/jwa/okp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
: https: //www.rfc-editor.org/rfc/rfc8037.html

"""

from __future__ import annotations

from dataclasses import dataclass
Expand All @@ -22,7 +23,8 @@ def public_bytes( # noqa: D102
self,
encoding: serialization.Encoding,
format: serialization.PublicFormat, # noqa: A002
) -> bytes: ...
) -> bytes:
...


@runtime_checkable
Expand All @@ -34,7 +36,8 @@ def private_bytes( # noqa: D102
encoding: serialization.Encoding,
format: serialization.PrivateFormat, # noqa: A002
encryption_algorithm: serialization.KeySerializationEncryption,
) -> bytes: ...
) -> bytes:
...

def public_key(self) -> PublicKeyProtocol: # noqa: D102
...
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/signature/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module exposes all the Signature algorithms available from `jwskate`."""

from __future__ import annotations

from .ec import ES256, ES256K, ES384, ES512, BaseECSignatureAlg
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/signature/ec.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implement Elliptic Curve signature algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/signature/eddsa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements the Edwards-curve Digital Signature Algorithm (EdDSA)."""

from __future__ import annotations

from typing import SupportsBytes, Union
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/signature/hmac.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements HMAC based signature algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwa/signature/rsa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""This module implements RSA signature algorithms."""

from __future__ import annotations

from typing import SupportsBytes
Expand Down
1 change: 1 addition & 0 deletions jwskate/jwe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
: https: //www.rfc-editor.org/rfc/rfc7516

"""

from __future__ import annotations

from .compact import InvalidJwe, JweCompact
Expand Down
Loading