Git Product home page Git Product logo

python-jws's Introduction

python-jws

๐Ÿšจ This is Unmaintained ๐Ÿšจ

This library is unmaintained and you should probably use https://github.com/latchset/jwcrypto instead.

For historical purposes, here are the docs

A Python implementation of JSON Web Signatures draft 02

Also now works on Python 3.3+ as well as Python 2.7+. However, it's a naive conversion to support both Python 2 and Python 3 so there may well be hidden bugs.

Installing

$ pip install jws

Algorithms

The JWS spec reserves several algorithms for cryptographic signing. Out of the 9, this library currently supports 7:

HMAC โ€“ native

  • HS256 โ€“ HMAC using SHA-256 hash algorithm
  • HS384 โ€“ HMAC using SHA-384 hash algorithm
  • HS512 โ€“ HMAC using SHA-512 hash algorithm

RSA โ€“ requires pycrypto >= 2.5: pip install pycrypto

  • RS256 โ€“ RSA using SHA-256 hash algorithm

ECDSA โ€“ requires ecdsa lib: pip install ecdsa

  • ES256 โ€“ ECDSA using P-256 curve and SHA-256 hash algorithm
  • ES384 โ€“ ECDSA using P-384 curve and SHA-384 hash algorithm
  • ES512 โ€“ ECDSA using P-521 curve and SHA-512 hash algorithm

There is also a mechanism for extending functionality by adding your own algorithms without cracking open the whole codebase. See the advanced usage section for an example.

For RSA and ECDSA, all crypto libraries are lazily loaded so you won't need the dependencies unless you try to use the functionality.

Usage

Let's check out some examples.

>>> import jws
>>> header  = { 'alg': 'HS256' }
>>> payload = { 'claim': 'JSON is the raddest.', 'iss': 'brianb' }
>>> signature = jws.sign(header, payload, 'secret')
>>> jws.verify(header, payload, signature, 'secret')
True
>>> jws.verify(header, payload, signature, 'badbadbad')
Traceback (most recent call last):
...
jws.exceptions.SignatureError: Could not validate signature

Now with a real key!

>>> import ecdsa
>>> sk256 = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p)
>>> vk = sk256.get_verifying_key()
>>> header = { 'alg': 'ES256' }
>>> sig = jws.sign(header, payload, sk256)
>>> jws.verify(header, payload, sig, vk)
True

Advanced Usage

Make this file

# file: sillycrypto.py
import jws
from jws.algos import AlgorithmBase, SignatureError
class FXUY(AlgorithmBase):
    def __init__(self, x, y):
        self.x = int(x)
        self.y = int(y)
    def sign(self, msg, key):
        return 'verysecure' * self.x + key * self.y

    def verify(self, msg, sig, key):
        if sig != self.sign(msg, key):
            raise SignatureError('nope')
        return True

jws.algos.CUSTOM += [
   # a regular expression with two named matching groups. (x and y)
    # named groups will be sent to the class constructor
    (r'^F(?P<x>\d)U(?P<y>\d{2})$',  FXUY),
]

And in an interpreter:

>>> import jws
>>> header = { 'alg': 'F7U12' }
>>> payload = { 'claim': 'wutt' }
>>> sig = jws.sign(header, payload, '<trollface>')
Traceback (most recent call last):
  ....
jws.exceptions.AlgorithmNotImplemented: "F7U12" not implemented.
>>>
>>> import sillycrypto
>>> sig = jws.sign(header, payload, '<trollface>')
>>> jws.verify(header, payload, sig, '<trollface>')
True
>>> jws.verify(header, payload, sig, 'y u no verify?')
Traceback (most recent call last):
....
jws.exceptions.SignatureError: nope

Other Stuff

Check out https://github.com/brianloveswords/python-jws/blob/master/examples/minijwt.py for a 14-line implemention of JWT.

See https://github.com/brianloveswords/python-jws/blob/master/examples/ragecrypto.py for a rage-comic inspired cryptography extension.

TODO

  • Write about all the rad stuff that can be done around headers (as extensible as crypto algos)
  • Pull in JWK support

Tests

use nosetests

License

MIT

python-jws's People

Contributors

ajkavanagh avatar alex-hofsteede avatar brianloveswords avatar davedoesdev avatar hdknr avatar mark-adams avatar progrium avatar tgs avatar wehlutyk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

python-jws's Issues

Doesn't work with pycryptodome

pycrypto is dead. pycryptodome is a drop-in replacement.
However, python-jws uses a private member (_RSAobj) of pycrypto:

https://github.com/brianloveswords/python-jws/blob/master/jws/algos.py#L87

which pycryptodome doesn't have.

But pycryptodome does have the RsaKey member in the same place.

So a change something like https://github.com/mpdavis/python-jose/pull/8/files#diff-f5aa2743c17dabc292333673fe591c30R20 is required where the presence of each member is checked for.

Signature differs from Python 2 to 3

Hi,
I try the exemple :

import jws
header = { 'alg': 'HS256' }
payload = { 'claim': 'JSON is the raddest.', 'iss': 'brianb' }
signature = jws.sign(header, payload, 'secret')

With Python 2.7.9 et 3.4.3, I get 2 signatures different : 9CG_vCmpr-UFKbkTtelFS2o9hJm1groP5vqUUKeV84c (3) and jn0z1avR1-tKtXjuEEVsGeBWHVx5E6YjzHEWmrkAdCY (2).
Python 2 seems to be ok (same as another language).

Error signing with RS256

>>> import jws
>>> header = {'alg': 'RS256'}
>>> payload = { 'claim': 'JSON is the raddest.', 'iss': 'brianb' }
>>> signature = jws.sign(header, payload, 'secret')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Python/2.7/site-packages/jws/__init__.py", line 29, in sign
    signature = signer(_signing_input(head, payload, is_json), key)
  File "/Library/Python/2.7/site-packages/jws/algos.py", line 74, in sign
    return self.padder.new(key).sign(self.hashm)             # pycrypto 2.5
  File "build/bdist.macosx-10.10-intel/egg/Crypto/Signature/PKCS1_v1_5.py", line 106, in sign
AttributeError: 'str' object has no attribute 'n'

I couldn't find anything related to this issue.
I have pycrypto 2.6.1

Thanks.

Python 3 support

Please, support Python 3, and document supported versions in PYPI.

Cannot install in windows

While I tried to install this package via 'pip install jws' in Windows 10 (python 3.7),
'UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 500: illegal multibyte sequence' occured.
I end up modifying 'setup.py' file (add parameter "encoding='UTF8'" in open function in line 5).

Add to Python Package Index

I'd like to try your software, but couldn't find it in the python package index at http://pypi.python.org/ โ€” could you submit it there ?

You probably want to change name = "python-jws" in setup.py to "jws" (still available!) or "json-web-signatures" before submitting, because the "python-" prefix is kind of redundant on PyPI.

unit tests fail for python3

The constant time function from django source code fails on python3

D:\TEMP\python-jws>python3 -m unittest --verbose jws.tests.TestJWS_hmac
test_invalid_hmac (jws.tests.TestJWS_hmac) ... ok
test_valid_hmac256 (jws.tests.TestJWS_hmac) ... ERROR
test_valid_hmac384 (jws.tests.TestJWS_hmac) ... ERROR
test_valid_hmac512 (jws.tests.TestJWS_hmac) ... ERROR

======================================================================
ERROR: test_valid_hmac256 (jws.tests.TestJWS_hmac)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\TEMP\python-jws\jws\tests.py", line 128, in test_valid_hmac256
    self.assertTrue(jws.verify(header, self.payload, sig, 'secret'))
  File "C:\TEMP\python-jws\jws\__init__.py", line 48, in verify
    return verifier(_signing_input(head, payload, is_json), signature, key)
  File "C:\TEMP\python-jws\jws\algos.py", line 46, in verify
    if not constant_time_compare(self.sign(msg, key), crypto):
  File "C:\TEMP\python-jws\jws\utils.py", line 54, in constant_time_compare
    result |= ord(x) ^ ord(y)
TypeError: ord() expected string of length 1, but int found

======================================================================
ERROR: test_valid_hmac384 (jws.tests.TestJWS_hmac)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\TEMP\python-jws\jws\tests.py", line 134, in test_valid_hmac384
    self.assertTrue(jws.verify(header, self.payload, sig, 'secret'))
  File "C:\TEMP\python-jws\jws\__init__.py", line 48, in verify
    return verifier(_signing_input(head, payload, is_json), signature, key)
  File "C:\TEMP\python-jws\jws\algos.py", line 46, in verify
    if not constant_time_compare(self.sign(msg, key), crypto):
  File "C:\TEMP\python-jws\jws\utils.py", line 54, in constant_time_compare
    result |= ord(x) ^ ord(y)
TypeError: ord() expected string of length 1, but int found

======================================================================
ERROR: test_valid_hmac512 (jws.tests.TestJWS_hmac)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\TEMP\python-jws\jws\tests.py", line 140, in test_valid_hmac512
    self.assertTrue(jws.verify(header, self.payload, sig, 'secret'))
  File "C:\TEMP\python-jws\jws\__init__.py", line 48, in verify
    return verifier(_signing_input(head, payload, is_json), signature, key)
  File "C:\TEMP\python-jws\jws\algos.py", line 46, in verify
    if not constant_time_compare(self.sign(msg, key), crypto):
  File "C:\TEMP\python-jws\jws\utils.py", line 54, in constant_time_compare
    result |= ord(x) ^ ord(y)
TypeError: ord() expected string of length 1, but int found

----------------------------------------------------------------------
Ran 4 tests in 0.031s

verify should verify the utf-8 json

it will fail if the sender sorted their keys differently than the recipient. it should verify against the utf-8 bytes of the transmitted json, not against a re-serialization.

jws.utils.encode and key order

I use python-jws for JWT.

The jws.utils.encode function uses json.dumps without the sort_keys=True parameter.

In my testing, this can cause JWT header, for example, to be encoded differently randomly.

{ "alg": "HS256", "typ": "JWT" }

vs

{ "typ": "JWT" "alg": "HS256", }

Here is my JWT verification code:

def from_jwt(jwt, algo, key):
    (header, claim, sig) = jwt.split('.')
    header = jws.utils.decode(header)
    assert header['alg'] == algo, header
    claim = jws.utils.decode(claim)
    r = jws.verify(header, claim, sig, key)
    assert r
    return claim

jws.verify signature verification fails when header is ordered differently.

Does it make sense to set sort_keys=True?

parser failed wth "ParameterNotUnderstood: Could not find an action for Header Parameter 'ppt''"

payload ={"alg":"ES256","typ":"passport","ppt":"shaken","x5u":"https://wiresharkserver.mtimslab.atttest.com/vesper/dig-sig.crt"}
payload ={}
header = {"alg":"ES256","typ":"passport","ppt":"shaken","x5u":"https://wiresharkserver.mtimslab.atttest.com/vesper/dig-sig.crt"}
payload = {"attest":"A","dest":{"tn":["+12249587065"]},"iat":1504163217,"orig":{"tn":"+12249587035"},"origid":"6cf14ce7-5c58-403c-8982-07f11b8680d5"}
signature = jws.sign(header, payload, 'secret')
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python2.7/site-packages/jws/init.py", line 23, in sign
header.process(data, 'sign')
File "/usr/lib/python2.7/site-packages/jws/header.py", line 67, in process
instance = cls(param, data['header'][param], data)
File "/usr/lib/python2.7/site-packages/jws/header.py", line 10, in init
self.value = self.clean(value)
File "/usr/lib/python2.7/site-packages/jws/header.py", line 30, in clean
raise ParameterNotUnderstood("Could not find an action for Header Parameter '%s'" % self.name)
jws.exceptions.ParameterNotUnderstood: Could not find an action for Header Parameter 'ppt'

JWT authorization module for Requests

Hiya,

Kenneth Reitz's requests library has a system for pluggable authentication & authorization modules. I've made a stab at a JWT module: jwt_auth.py in https://github.com/tgs/python-badgekit-api-client/tree/master/badgekit

I'm thinking about how make it available to the public - some requests auth modules have their own projects, like https://github.com/requests/requests-ntlm . In this case, it seems a little silly, because the JWT auth is just one file, some unit tests, and a dependency on python-jws. Would you like to include the auth module in your project? I'm happy to clean it up if you want to review the code. On the other hand, if you're mostly busy with other stuff, I can release it as its own project.

Thanks!
-Thomas

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.