Skip to content

Commit 99ec142

Browse files
authored
Merge pull request #182 from blag/update-tests-aenglander
Move HMACKey, add JWE, and update and expand tests
2 parents 5ec9f48 + 581c6d7 commit 99ec142

29 files changed

+2479
-143
lines changed

.travis.yml

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
# Travis infra requires pinning dist:precise, at least as of 2017-09-01
22
# detail: https://blog.travis-ci.com/2017-06-21-trusty-updates-2017-Q2-launch
3-
dist: precise
3+
dist: bionic
44
language: python
55
install:
66
- pip install -U setuptools && pip install -U tox codecov tox-travis
77
script:
88
- tox
99
after_success:
1010
- codecov
11+
jobs:
12+
allow_failures:
13+
- python: 3.9-dev
1114
matrix:
1215
include:
1316
# Linting
@@ -47,36 +50,57 @@ matrix:
4750
- python: 3.6
4851
env: TOXENV=py36-compatibility
4952
# CPython 3.7
50-
# xenial + sudo are currently needed to get 3.7
51-
# https://github.com/travis-ci/travis-ci/issues/9815
5253
- python: 3.7
5354
env: TOXENV=py37-base
54-
dist: xenial
55-
sudo: true
5655
- python: 3.7
5756
env: TOXENV=py37-cryptography-only
58-
dist: xenial
59-
sudo: true
6057
- python: 3.7
6158
env: TOXENV=py37-pycryptodome-norsa
62-
dist: xenial
63-
sudo: true
6459
- python: 3.7
6560
env: TOXENV=py37-pycrypto-norsa
66-
dist: xenial
67-
sudo: true
6861
- python: 3.7
6962
env: TOXENV=py37-compatibility
70-
dist: xenial
71-
sudo: true
72-
# PyPy 3.5 (5.10.1?)
73-
- python: pypy3.5
63+
# CPython 3.8
64+
- python: 3.8
65+
env: TOXENV=py38-base
66+
- python: 3.8
67+
env: TOXENV=py38-cryptography-only
68+
- python: 3.8
69+
env: TOXENV=py38-pycryptodome-norsa
70+
- python: 3.8
71+
env: TOXENV=py38-pycrypto-norsa
72+
- python: 3.8
73+
env: TOXENV=py38-compatibility
74+
# CPython 3.9 - dev
75+
- python: 3.9-dev
76+
env: TOXENV=py39-base
77+
- python: 3.9-dev
78+
env: TOXENV=py39-cryptography-only
79+
- python: 3.9-dev
80+
env: TOXENV=py39-pycryptodome-norsa
81+
- python: 3.9-dev
82+
env: TOXENV=py39-pycrypto-norsa
83+
- python: 3.9-dev
84+
env: TOXENV=py39-compatibility
85+
# PyPy 2.7
86+
- python: pypy2
7487
env: TOXENV=pypy-base
75-
- python: pypy3.5
88+
- python: pypy2
7689
env: TOXENV=pypy-cryptography-only
77-
- python: pypy3.5
90+
- python: pypy2
7891
env: TOXENV=pypy-pycryptodome-norsa
79-
- python: pypy3.5
92+
- python: pypy2
8093
env: TOXENV=pypy-pycrypto-norsa
81-
- python: pypy3.5
94+
- python: pypy2
8295
env: TOXENV=pypy-compatibility
96+
# PyPy 3.x
97+
- python: pypy3
98+
env: TOXENV=pypy-base
99+
- python: pypy3
100+
env: TOXENV=pypy3-cryptography-only
101+
- python: pypy3
102+
env: TOXENV=pypy3-pycryptodome-norsa
103+
- python: pypy3
104+
env: TOXENV=pypy3-pycrypto-norsa
105+
- python: pypy3
106+
env: TOXENV=pypy3-compatibility

docs/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Contents
2424
jws/index
2525
jwt/index
2626
jwk/index
27+
jwe/index
2728

2829

2930
APIs
@@ -35,6 +36,7 @@ APIs
3536
jws/api
3637
jwt/api
3738
jwk/api
39+
jwe/api
3840

3941

4042
Principles

docs/jwe/api.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
JWE API
3+
^^^^^^^
4+
5+
.. automodule:: jose.jwe
6+
:members:

docs/jwe/index.rst

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
JSON Web Encryption
2+
===================
3+
4+
JSON Web Encryption (JWE) are used to encrypt a payload and represent it as a
5+
compact URL-safe string.
6+
7+
Supported Content Encryption Algorithms
8+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9+
10+
The following algorithms are currently supported.
11+
12+
+------------------+------------------------------------------------+
13+
| Encryption Value | Encryption Algorithm, Mode, and Auth Tag |
14+
+==================+================================================+
15+
| A128CBC_HS256 | AES w/128 bit key in CBC mode w/SHA256 HMAC |
16+
+------------------+------------------------------------------------+
17+
| A192CBC_HS384 | AES w/128 bit key in CBC mode w/SHA256 HMAC |
18+
+------------------+------------------------------------------------+
19+
| A256CBC_HS512 | AES w/128 bit key in CBC mode w/SHA256 HMAC |
20+
+------------------+------------------------------------------------+
21+
| A128GCM | AES w/128 bit key in GCM mode and GCM auth tag |
22+
+------------------+------------------------------------------------+
23+
| A192GCM | AES w/192 bit key in GCM mode and GCM auth tag |
24+
+------------------+------------------------------------------------+
25+
| A256GCM | AES w/256 bit key in GCM mode and GCM auth tag |
26+
+------------------+------------------------------------------------+
27+
28+
Supported Key Management Algorithms
29+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
The following algorithms are currently supported.
32+
33+
+-----------------+------------------------------------------------+
34+
| Algorithm Value | Key Wrap Algorithm |
35+
+=================+================================================+
36+
| DIR | Direct (no key wrap) |
37+
+-----------------+------------------------------------------------+
38+
| RSA1_5 | RSAES with PKCS1 v1.5 |
39+
+-----------------+------------------------------------------------+
40+
| RSA_OAEP | RSAES OAEP using default parameters |
41+
+-----------------+------------------------------------------------+
42+
| RSA_OAEP_256 | RSAES OAEP using SHA-256 and MGF1 with SHA-256 |
43+
+-----------------+------------------------------------------------+
44+
| A128KW | AES Key Wrap with default IV using 128-bit key |
45+
+-----------------+------------------------------------------------+
46+
| A192KW m | AES Key Wrap with default IV using 192-bit key |
47+
+-----------------+------------------------------------------------+
48+
| A256KW | AES Key Wrap with default IV using 256-bit key |
49+
+-----------------+------------------------------------------------+
50+
51+
Examples
52+
^^^^^^^^
53+
54+
Encrypting Payloads
55+
-------------------
56+
57+
.. code:: python
58+
59+
>>> from jose import jwe
60+
>>> jwe.encrypt('Hello, World!', 'asecret128bitkey', algorithm='dir', encryption='A128GCM')
61+
'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..McILMB3dYsNJSuhcDzQshA.OfX9H_mcUpHDeRM4IA.CcnTWqaqxNsjT4eCaUABSg'
62+
63+
64+
Decrypting Payloads
65+
--------------------------
66+
67+
.. code:: python
68+
69+
>>> from jose import jwe
70+
>>> jwe.decrypt('eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..McILMB3dYsNJSuhcDzQshA.OfX9H_mcUpHDeRM4IA.CcnTWqaqxNsjT4eCaUABSg', 'asecret128bitkey')
71+
'Hello, World!'

jose/backends/__init__.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,45 @@
1+
try:
2+
from jose.backends.cryptography_backend import get_random_bytes # noqa: F401
3+
except ImportError:
4+
try:
5+
from jose.backends.pycrypto_backend import get_random_bytes # noqa: F401
6+
except ImportError:
7+
from jose.backends.native import get_random_bytes # noqa: F401
18

29
try:
310
from jose.backends.cryptography_backend import CryptographyRSAKey as RSAKey # noqa: F401
411
except ImportError:
512
try:
613
from jose.backends.pycrypto_backend import RSAKey # noqa: F401
14+
15+
# time.clock was deprecated in python 3.3 in favor of time.perf_counter
16+
# and removed in python 3.8. pycrypto was never updated for this. If
17+
# time has no clock attribute, let it use perf_counter instead to work
18+
# in 3.8+
19+
# noinspection PyUnresolvedReferences
20+
import time
21+
if not hasattr(time, "clock"):
22+
time.clock = time.perf_counter
23+
724
except ImportError:
825
from jose.backends.rsa_backend import RSAKey # noqa: F401
926

1027
try:
1128
from jose.backends.cryptography_backend import CryptographyECKey as ECKey # noqa: F401
1229
except ImportError:
1330
from jose.backends.ecdsa_backend import ECDSAECKey as ECKey # noqa: F401
31+
32+
try:
33+
from jose.backends.cryptography_backend import CryptographyAESKey as AESKey # noqa: F401
34+
except ImportError:
35+
try:
36+
from jose.backends.pycrypto_backend import AESKey # noqa: F401
37+
except ImportError:
38+
AESKey = None
39+
40+
try:
41+
from jose.backends.cryptography_backend import CryptographyHMACKey as HMACKey # noqa: F401
42+
except ImportError:
43+
from jose.backends.native import HMACKey # noqa: F401
44+
45+
from .base import DIRKey # noqa: F401

jose/backends/base.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import six
2+
3+
from ..utils import base64url_encode
4+
5+
16
class Key(object):
27
"""
38
A simple interface for implementing JWK keys.
@@ -19,3 +24,67 @@ def to_pem(self):
1924

2025
def to_dict(self):
2126
raise NotImplementedError()
27+
28+
def encrypt(self, plain_text, aad=None):
29+
"""
30+
Encrypt the plain text and generate an auth tag if appropriate
31+
32+
Args:
33+
plain_text (bytes): Data to encrypt
34+
aad (bytes, optional): Authenticated Additional Data if key's algorithm supports auth mode
35+
36+
Returns:
37+
(bytes, bytes, bytes): IV, cipher text, and auth tag
38+
"""
39+
raise NotImplementedError()
40+
41+
def decrypt(self, cipher_text, iv=None, aad=None, tag=None):
42+
"""
43+
Decrypt the cipher text and validate the auth tag if present
44+
Args:
45+
cipher_text (bytes): Cipher text to decrypt
46+
iv (bytes): IV if block mode
47+
aad (bytes): Additional Authenticated Data to verify if auth mode
48+
tag (bytes): Authentication tag if auth mode
49+
50+
Returns:
51+
bytes: Decrypted value
52+
"""
53+
raise NotImplementedError()
54+
55+
def wrap_key(self, key_data):
56+
"""
57+
Wrap the the plain text key data
58+
59+
Args:
60+
key_data (bytes): Key data to wrap
61+
62+
Returns:
63+
bytes: Wrapped key
64+
"""
65+
raise NotImplementedError()
66+
67+
def unwrap_key(self, wrapped_key):
68+
"""
69+
Unwrap the the wrapped key data
70+
71+
Args:
72+
wrapped_key (bytes): Wrapped key data to unwrap
73+
74+
Returns:
75+
bytes: Unwrapped key
76+
"""
77+
raise NotImplementedError()
78+
79+
80+
class DIRKey(Key):
81+
def __init__(self, key_data, algorithm):
82+
self._key = six.ensure_binary(key_data)
83+
self._alg = algorithm
84+
85+
def to_dict(self):
86+
return {
87+
'alg': self._alg,
88+
'kty': 'oct',
89+
'k': base64url_encode(self._key),
90+
}

0 commit comments

Comments
 (0)