def decode(self, s, key, claims_cls=None, claims_options=None, claims_params=None): """Decode the JWS with the given key. This is similar with :meth:`verify`, except that it will raise BadSignatureError when signature doesn't match. :param s: text of JWT :param key: key used to verify the signature :param claims_cls: class to be used for JWT claims :param claims_options: `options` parameters for claims_cls :param claims_params: `params` parameters for claims_cls :return: claims_cls instance :raise: BadSignatureError """ if claims_cls is None: claims_cls = JWTClaims s = to_bytes(s) dot_count = s.count(b'.') if dot_count == 2: data = self._jws.deserialize_compact(s, key, decode_payload) elif dot_count == 4: data = self._jwe.deserialize_compact(s, key, decode_payload) else: raise DecodeError('Invalid input segments length') return claims_cls( data['payload'], data['header'], options=claims_options, params=claims_params, )
def _extract(s): try: s = to_bytes(s) signing_input, signature_segment = s.rsplit(b'.', 1) header_segment, payload_segment = signing_input.split(b'.', 1) except ValueError: raise DecodeError('Not enough segments') try: header_data = urlsafe_b64decode(header_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid header padding') try: header = json.loads(header_data.decode('utf-8')) except ValueError as e: raise DecodeError('Invalid header string: {}'.format(e)) if not isinstance(header, Mapping): raise DecodeError('Header must be a json object') if 'alg' not in header: raise DecodeError('Missing "alg" in header') try: payload = urlsafe_b64decode(payload_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid payload padding') try: signature = urlsafe_b64decode(signature_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid crypto padding') return header, payload, signing_input, signature
def create_half_hash(s, alg): hash_type = 'sha{}'.format(alg[2:]) hash_alg = getattr(hashlib, hash_type, None) if not hash_alg: return None data_digest = hash_alg(to_bytes(s)).digest() slice_index = int(len(data_digest) / 2) return urlsafe_b64encode(data_digest[:slice_index])
def rsa_sha1_signature(base_string, rsa_private_key): """Generate signature via RSA-SHA1 method, per `Section 3.4.3`_. The "RSA-SHA1" signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in `RFC3447, Section 8.2`_ (also known as PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5. To use this method, the client MUST have established client credentials with the server that included its RSA public key (in a manner that is beyond the scope of this specification). .. _`Section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 .. _`RFC3447, Section 8.2`: http://tools.ietf.org/html/rfc3447#section-8.2 """ from .rsa import sign_sha1 base_string = to_bytes(base_string) s = sign_sha1(to_bytes(base_string), rsa_private_key) sig = binascii.b2a_base64(s)[:-1] return to_unicode(sig)
def loads(self, obj): for k in ['crv', 'x']: if k not in obj: raise ValueError('Not a elliptic curve key') crv = obj['crv'] if crv not in CURVES_KEYS: raise ValueError('Unsupported crv for OKP') keys = CURVES_KEYS[crv] # The parameter "d" MUST be present for private keys if 'd' in obj: crv_key = keys[1] d_bytes = urlsafe_b64decode(to_bytes(obj['d'])) return crv_key.from_private_bytes(d_bytes) crv_key = keys[0] x_bytes = urlsafe_b64decode(to_bytes(obj['x'])) return crv_key.from_public_bytes(x_bytes)
def create_basic_header(username, password): """ Create an authorization header from the username and password according to RFC 2617 (https://tools.ietf.org/html/rfc2617). Use this to send client credentials in the authorization header. """ text = "{}:{}".format(username, password) auth = to_unicode(base64.b64encode(to_bytes(text))) return {"Authorization": "Basic " + auth}
def thumbprint(self): """Implementation of RFC7638 JSON Web Key (JWK) Thumbprint.""" fields = list(self.REQUIRED_JSON_FIELDS) fields.append('kty') fields.sort() data = OrderedDict() for k in fields: data[k] = self.tokens[k] json_data = json_dumps(data) digest_data = hashlib.sha256(to_bytes(json_data)).digest() return to_unicode(urlsafe_b64encode(digest_data))