コード例 #1
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_4_8_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     S = jws.JWS(payload=plaintext)
     # 4_8_2
     protected = \
         base64url_decode(JWS_Protected_Header_4_8_2).decode('utf-8')
     header = json_encode(JWS_Unprotected_Header_4_8_2)
     pri_key = jwk.JWK(**RSA_Private_Key_3_4)
     S.add_signature(pri_key, None, protected, header)
     # 4_8_3
     header = json_encode(JWS_Unprotected_Header_4_8_3)
     pri_key = jwk.JWK(**EC_Private_Key_3_2)
     S.add_signature(pri_key, None, None, header)
     # 4_8_4
     protected = \
         base64url_decode(JWS_Protected_Header_4_8_4).decode('utf-8')
     sym_key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S.add_signature(sym_key, None, protected)
     sig = S.serialize()
     # Can't compare signature with reference because ECDSA uses
     # random nonces every time a signature is generated.
     rsa_key = jwk.JWK(**RSA_Public_Key_3_3)
     ec_key = jwk.JWK(**EC_Public_Key_3_1)
     S.deserialize(sig, rsa_key)
     S.deserialize(sig, ec_key)
     S.deserialize(sig, sym_key)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_8_5), rsa_key)
     S.deserialize(json_encode(JWS_general_4_8_5), ec_key)
     S.deserialize(json_encode(JWS_general_4_8_5), sym_key)
コード例 #2
0
def derive_key(privkey, point_x, point_y, alg, bitsize, headers):
    # OtherInfo is defined in NIST SP 56A 5.8.1.2.1

    # AlgorithmID
    otherinfo = struct.pack('>I', len(alg))
    otherinfo += bytes(alg.encode('utf8'))

    # PartyUInfo
    apu = base64url_decode(headers['apu']) if 'apu' in headers else b''
    otherinfo += struct.pack('>I', len(apu))
    otherinfo += apu

    # PartyVInfo
    apv = base64url_decode(headers['apv']) if 'apv' in headers else b''
    otherinfo += struct.pack('>I', len(apv))
    otherinfo += apv

    # SuppPubInfo
    otherinfo += struct.pack('>I', bitsize)

    # no SuppPrivInfo

    # Shared Key generation

    x, y = point_x, point_y
    P = vulnecc.AffinePoint(vulnecc.curveP256_vuln, x, y)
    s = privkey
    shared = s * P
    shared_key = int.to_bytes(shared.x, 32, "big")

    ckdf = ConcatKDFHash(algorithm=hashes.SHA256(),
                         length=bitsize // 8,
                         otherinfo=otherinfo,
                         backend=default_backend())
    return ckdf.derive(shared_key)
コード例 #3
0
 def test_4_8_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     S = jws.JWS(payload=plaintext)
     # 4_8_2
     protected = \
         base64url_decode(JWS_Protected_Header_4_8_2).decode('utf-8')
     header = json_encode(JWS_Unprotected_Header_4_8_2)
     pri_key = jwk.JWK(**RSA_Private_Key_3_4)
     S.add_signature(pri_key, None, protected, header)
     # 4_8_3
     header = json_encode(JWS_Unprotected_Header_4_8_3)
     pri_key = jwk.JWK(**EC_Private_Key_3_2)
     S.add_signature(pri_key, None, None, header)
     # 4_8_4
     protected = \
         base64url_decode(JWS_Protected_Header_4_8_4).decode('utf-8')
     sym_key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S.add_signature(sym_key, None, protected)
     sig = S.serialize()
     # Can't compare signature with reference because ECDSA uses
     # random nonces every time a signature is generated.
     rsa_key = jwk.JWK(**RSA_Public_Key_3_3)
     ec_key = jwk.JWK(**EC_Public_Key_3_1)
     S.deserialize(sig, rsa_key)
     S.deserialize(sig, ec_key)
     S.deserialize(sig, sym_key)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_8_5), rsa_key)
     S.deserialize(json_encode(JWS_general_4_8_5), ec_key)
     S.deserialize(json_encode(JWS_general_4_8_5), sym_key)
コード例 #4
0
    def _derive(self, privkey, pubkey, alg, bitsize, headers):
        # OtherInfo is defined in NIST SP 56A 5.8.1.2.1

        # AlgorithmID
        otherinfo = struct.pack('>I', len(alg))
        otherinfo += bytes(alg.encode('utf8'))

        # PartyUInfo
        apu = base64url_decode(headers['apu']) if 'apu' in headers else b''
        otherinfo += struct.pack('>I', len(apu))
        otherinfo += apu

        # PartyVInfo
        apv = base64url_decode(headers['apv']) if 'apv' in headers else b''
        otherinfo += struct.pack('>I', len(apv))
        otherinfo += apv

        # SuppPubInfo
        otherinfo += struct.pack('>I', bitsize)

        # no SuppPrivInfo

        # Shared Key generation
        if isinstance(privkey, ec.EllipticCurvePrivateKey):
            shared_key = privkey.exchange(ec.ECDH(), pubkey)
        else:
            # X25519/X448
            shared_key = privkey.exchange(pubkey)

        ckdf = ConcatKDFHash(algorithm=hashes.SHA256(),
                             length=_inbytes(bitsize),
                             otherinfo=otherinfo,
                             backend=self.backend)
        return ckdf.derive(shared_key)
コード例 #5
0
ファイル: cyprov_crypto.py プロジェクト: utzig/cysecuretools
    def readable_jwt(txt):
        """
        Convert a JWT token in base64url into a readable dictionary object
        with decoded payload and header for printing and logging
        """
        lst = txt.split('.')
        readable = {
            'protected': json_decode(base64url_decode(lst[0])),
            'payload': json_decode(base64url_decode(lst[1])),
            'signature': lst[2]
        }

        # create readable timestamps for exp/iat claims
        payload = readable["payload"]
        if "iat" in payload:
            t = payload["iat"]
            if isinstance(t, int):
                t = datetime.fromtimestamp(t).isoformat(' ')
                payload["iat"] = t
        if "exp" in payload:
            t = payload["exp"]
            if isinstance(t, int):
                t = datetime.fromtimestamp(t).isoformat(' ')
                payload["exp"] = t

        print(json.dumps(readable, indent=4, sort_keys=False))
        return readable
コード例 #6
0
ファイル: jwe.py プロジェクト: tiran/jwcrypto
    def _derive(self, privkey, pubkey, alg, keydatalen, headers):
        # OtherInfo is defined in NIST SP 56A 5.8.1.2.1

        # AlgorithmID
        otherinfo = struct.pack('>I', len(alg))
        otherinfo += bytes(alg.encode('utf8'))

        # PartyUInfo
        apu = base64url_decode(headers['apu']) if 'apu' in headers else b''
        otherinfo += struct.pack('>I', len(apu))
        otherinfo += apu

        # PartyVInfo
        apv = base64url_decode(headers['apv']) if 'apv' in headers else b''
        otherinfo += struct.pack('>I', len(apv))
        otherinfo += apv

        # SuppPubInfo
        otherinfo += struct.pack('>I', keydatalen)

        # no SuppPrivInfo

        shared_key = privkey.exchange(ec.ECDH(), pubkey)
        ckdf = ConcatKDFHash(algorithm=hashes.SHA256(),
                             length=keydatalen // 8,
                             otherinfo=otherinfo,
                             backend=self.backend)
        return ckdf.derive(shared_key)
コード例 #7
0
    def verify_jws(self, raw_jws: str, did_document: DidDocument or None):
        c = raw_jws.split('.')
        data = {
            'protected':
            json.loads(base64url_decode(str(c[0])).decode('utf-8')),
            'payload': json.loads(base64url_decode(str(c[1])).decode('utf-8')),
            'signature': base64url_decode(str(c[2]))
        }
        key_id = data['protected']['kid']
        issuer = data['payload']['iss']

        if did_document is None:
            _cache_pub_key_of_issuer = self.document.get_public_key(
                key_id=key_id)
            if not _cache_pub_key_of_issuer:
                self.document = self.__get_document(issuer)

        pub_key_of_issuer = self.document.get_public_key(key_id=key_id)
        if not pub_key_of_issuer:
            raise DidNotFoundException(
                error_message=f"Not Found KeyID in did document {issuer}")

        user_pub_key_hex = pub_key_of_issuer.get('publicKeyHex')
        if not user_pub_key_hex:
            return None

        user_pub_key = jwk.JWK.from_pem(
            VerifyingKey.from_string(bytes.fromhex(user_pub_key_hex),
                                     curve=SECP256k1).to_pem())
        return VerifiableSignedJWT.verify(token=raw_jws, key=user_pub_key)
コード例 #8
0
 def _deserialize_signature(self, s):
     o = dict()
     o['signature'] = base64url_decode(str(s['signature']))
     if 'protected' in s:
         p = base64url_decode(str(s['protected']))
         o['protected'] = p.decode('utf-8')
     if 'header' in s:
         o['header'] = s['header']
     return o
コード例 #9
0
    def deserialize(self, raw_jws, key=None, alg=None):
        """Deserialize a JWS token.

        NOTE: Destroys any current status and tries to import the raw
        JWS provided.

        :param raw_jws: a 'raw' JWS token (JSON Encoded or Compact
         notation) string.
        :param key: A (:class:`jwcrypto.jwk.JWK`) verification key (optional).
         If a key is provided a verification step will be attempted after
         the object is successfully deserialized.
        :param alg: The signing algorithm (optional). usually the algorithm
         is known as it is provided with the JOSE Headers of the token.

        :raises InvalidJWSObject: if the raw object is an invaid JWS token.
        :raises InvalidJWSSignature: if the verification fails.
        """
        self.objects = dict()
        o = dict()
        try:
            try:
                djws = json_decode(raw_jws)
                if 'signatures' in djws:
                    o['signatures'] = list()
                    for s in djws['signatures']:
                        os = self._deserialize_signature(s)
                        o['signatures'].append(os)
                        self._deserialize_b64(o, os.get('protected'))
                else:
                    o = self._deserialize_signature(djws)
                    self._deserialize_b64(o, o.get('protected'))

                if 'payload' in djws:
                    if o.get('b64', True):
                        o['payload'] = base64url_decode(str(djws['payload']))
                    else:
                        o['payload'] = djws['payload']

            except ValueError:
                c = raw_jws.split('.')
                if len(c) != 3:
                    raise InvalidJWSObject('Unrecognized representation')
                p = base64url_decode(str(c[0]))
                if len(p) > 0:
                    o['protected'] = p.decode('utf-8')
                    self._deserialize_b64(o, o['protected'])
                o['payload'] = base64url_decode(str(c[1]))
                o['signature'] = base64url_decode(str(c[2]))

            self.objects = o

        except Exception as e:  # pylint: disable=broad-except
            raise InvalidJWSObject('Invalid format', repr(e))

        if key:
            self.verify(key, alg)
コード例 #10
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_4_1_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_1_2).decode('utf-8')
     pub_key = jwk.JWK(**RSA_Public_Key_3_3)
     pri_key = jwk.JWK(**RSA_Private_Key_3_4)
     S = jws.JWS(payload=plaintext)
     S.add_signature(pri_key, None, protected)
     self.assertEqual(JWS_compact_4_1_3, S.serialize(compact=True))
     S.deserialize(json_encode(JWS_general_4_1_3), pub_key)
     S.deserialize(json_encode(JWS_flattened_4_1_3), pub_key)
コード例 #11
0
 def test_4_1_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_1_2).decode('utf-8')
     pub_key = jwk.JWK(**RSA_Public_Key_3_3)
     pri_key = jwk.JWK(**RSA_Private_Key_3_4)
     S = jws.JWS(payload=plaintext)
     S.add_signature(pri_key, None, protected)
     self.assertEqual(JWS_compact_4_1_3, S.serialize(compact=True))
     S.deserialize(json_encode(JWS_general_4_1_3), pub_key)
     S.deserialize(json_encode(JWS_flattened_4_1_3), pub_key)
コード例 #12
0
 def test_4_6_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_6_2).decode('utf-8')
     header = json_encode(JWS_Unprotected_Header_4_6_2)
     key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S = jws.JWS(payload=plaintext)
     S.add_signature(key, None, protected, header)
     sig = S.serialize()
     S.deserialize(sig, key)
     self.assertEqual(json_decode(sig), JWS_flattened_4_6_3)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_6_3), key)
     S.deserialize(json_encode(JWS_flattened_4_6_3), key)
コード例 #13
0
 def test_5_10_encryption(self):
     plaintext = Payload_plaintext_5
     protected = base64url_decode(JWE_Protected_Header_5_10_4)
     aad = base64url_decode(AAD_5_10_1)
     aes_key = jwk.JWK(**AES_key_5_8_1)
     E = jwe.JWE(plaintext, protected, aad=aad)
     E.add_recipient(aes_key)
     e = E.serialize()
     E.deserialize(e, aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_general_5_10_5), aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_flattened_5_10_5), aes_key)
     self.assertEqual(E.payload, plaintext)
コード例 #14
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_5_10_encryption(self):
     plaintext = Payload_plaintext_5
     protected = base64url_decode(JWE_Protected_Header_5_10_4)
     aad = base64url_decode(AAD_5_10_1)
     aes_key = jwk.JWK(**AES_key_5_8_1)
     E = jwe.JWE(plaintext, protected, aad=aad)
     E.add_recipient(aes_key)
     e = E.serialize()
     E.deserialize(e, aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_general_5_10_5), aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_flattened_5_10_5), aes_key)
     self.assertEqual(E.payload, plaintext)
コード例 #15
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_4_6_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_6_2).decode('utf-8')
     header = json_encode(JWS_Unprotected_Header_4_6_2)
     key = jwk.JWK(**Symmetric_Key_MAC_3_5)
     S = jws.JWS(payload=plaintext)
     S.add_signature(key, None, protected, header)
     sig = S.serialize()
     S.deserialize(sig, key)
     self.assertEqual(json_decode(sig), JWS_flattened_4_6_3)
     # Just deserialize each example form
     S.deserialize(json_encode(JWS_general_4_6_3), key)
     S.deserialize(json_encode(JWS_flattened_4_6_3), key)
コード例 #16
0
ファイル: jws.py プロジェクト: Allu2/jwcrypto
    def deserialize(self, raw_jws, key=None, alg=None):
        """Deserialize a JWS token.

        NOTE: Destroys any current status and tries to import the raw
        JWS provided.

        :param raw_jws: a 'raw' JWS token (JSON Encoded or Compact
         notation) string.
        :param key: A (:class:`jwcrypto.jwk.JWK`) verification key (optional).
         If a key is provided a verification step will be attempted after
         the object is successfully deserialized.
        :param alg: The signing algorithm (optional). usually the algorithm
         is known as it is provided with the JOSE Headers of the token.

        :raises InvalidJWSObject: if the raw object is an invaid JWS token.
        :raises InvalidJWSSignature: if the verification fails.
        """
        self.objects = dict()
        o = dict()
        try:
            try:
                djws = json_decode(raw_jws)
                o['payload'] = base64url_decode(str(djws['payload']))
                if 'signatures' in djws:
                    o['signatures'] = list()
                    for s in djws['signatures']:
                        os = dict()
                        os['signature'] = base64url_decode(str(s['signature']))
                        if 'protected' in s:
                            p = base64url_decode(str(s['protected']))
                            os['protected'] = p.decode('utf-8')
                        if 'header' in s:
                            os['header'] = s['header']
                        o['signatures'].append(os)
                else:
                    o['signature'] = base64url_decode(str(djws['signature']))
                    if 'protected' in djws:
                        p = base64url_decode(str(djws['protected']))
                        o['protected'] = p.decode('utf-8')
                    if 'header' in djws:
                        o['header'] = djws['header']

            except ValueError:
                c = raw_jws.split('.')
                if len(c) != 3:
                    raise InvalidJWSObject('Unrecognized representation')
                p = base64url_decode(str(c[0]))
                if len(p) > 0:
                    o['protected'] = p.decode('utf-8')
                o['payload'] = base64url_decode(str(c[1]))
                o['signature'] = base64url_decode(str(c[2]))

            self.objects = o

        except Exception as e:  # pylint: disable=broad-except
            raise InvalidJWSObject('Invalid format', repr(e))

        if key:
            self.verify(key, alg)
コード例 #17
0
ファイル: jwk.py プロジェクト: redrocket-ctf/csr-2020-tasks
 def _get_public_key(self, arg=None):
     if self._params['kty'] == 'oct':
         return self._key['k']
     elif self._params['kty'] == 'RSA':
         return self._rsa_pub(self._key).public_key(default_backend())
     elif self._params['kty'] == 'EC':
         try:
             return self._ec_pub(self._key, arg).public_key(default_backend())
         except ValueError:
             # invalid point
             from jwcrypto.jwa import _decode_int
             return _decode_int(base64url_decode(self._key['x'])), _decode_int(base64url_decode(self._key['y']))
     elif self._params['kty'] == 'OKP':
         return self._okp_pub(self._key)
     else:
         raise NotImplementedError
コード例 #18
0
ファイル: jwe.py プロジェクト: ColtonProvias/jwcrypto
 def get_key(self, key, op):
     if key.key_type != 'oct':
         raise InvalidJWEKeyType('oct', key.key_type)
     rk = base64url_decode(key.get_op_key(op))
     if len(rk) != self.keysize:
         raise InvalidJWEKeyLength(self.keysize * 8, len(rk) * 8)
     return rk
コード例 #19
0
    def _okp_pri(self, k):
        try:
            privkey = _OKP_CURVES_TABLE[k['crv']].privkey
        except KeyError:
            raise InvalidJWKValue('Unknown curve "%s"' % k['crv'])

        return privkey.from_private_bytes(base64url_decode(k['d']))
コード例 #20
0
ファイル: jws.py プロジェクト: ColtonProvias/jwcrypto
 def verify(self, key, payload, signature):
     vkey = base64url_decode(key.get_op_key('verify'))
     h = self._hmac_setup(vkey, payload)
     try:
         h.verify(signature)
     except InvalidSignature as e:
         raise InvalidJWSSignature(exception=e)
コード例 #21
0
    def _load(self):
        logger.debug('finding eq_session_id in database',
                     eq_session_id=self.eq_session_id)

        self._eq_session = data_access.get_by_key(EQSession,
                                                  self.eq_session_id)

        if self._eq_session:
            self.user_id = self._eq_session.user_id

            if self._eq_session.session_data:
                encrypted_session_data = self._eq_session.session_data
                session_data = StorageEncryption(self.user_id, self.user_ik, self.pepper)\
                    .decrypt_data(encrypted_session_data)

                # for backwards compatibility
                # session data used to be base64 encoded before encryption
                try:
                    session_data = base64url_decode(
                        session_data.decode()).decode()
                except ValueError:
                    pass

                self.session_data = json.loads(
                    session_data, object_hook=lambda d: SessionData(**d))

            logger.debug(
                'found matching eq_session for eq_session_id in database',
                session_id=self._eq_session.eq_session_id,
                user_id=self._eq_session.user_id)
        else:
            logger.debug('eq_session_id not found in database',
                         eq_session_id=self.eq_session_id)

        return self._eq_session
コード例 #22
0
ファイル: __init__.py プロジェクト: davedoesdev/python-jwt
def process_jwt(jwt):
    """
    Process a JSON Web Token without verifying it.

    Call this before :func:`verify_jwt` if you need access to the header or claims in the token before verifying it. For example, the claims might identify the issuer such that you can retrieve the appropriate public key.

    :param jwt: The JSON Web Token to verify.
    :type jwt: str or unicode

    :rtype: tuple
    :returns: ``(header, claims)``
    """
    header, claims, _ = jwt.split('.')
    parsed_header = json_decode(base64url_decode(header))
    parsed_claims = json_decode(base64url_decode(claims))
    return parsed_header, parsed_claims
コード例 #23
0
    def _load(self) -> None:
        logger.debug("finding eq_session_id in database",
                     eq_session_id=self.eq_session_id)
        self._eq_session: Optional[EQSession] = current_app.eq["storage"].get(
            EQSession, self.eq_session_id)  # type: ignore

        if self._eq_session and self._eq_session.session_data:
            self.user_id = self._eq_session.user_id

            encrypted_session_data = self._eq_session.session_data
            session_data_as_bytes = StorageEncryption(
                self.user_id, self.user_ik,
                self.pepper).decrypt_data(encrypted_session_data)

            session_data_as_str = session_data_as_bytes.decode()
            # for backwards compatibility
            # session data used to be base64 encoded before encryption
            try:
                session_data_as_str = base64url_decode(
                    session_data_as_str).decode()
            except ValueError:
                pass

            self.session_data = json_loads(
                session_data_as_str, object_hook=lambda d: SessionData(**d))

            logger.debug(
                "found matching eq_session for eq_session_id in database",
                session_id=self._eq_session.eq_session_id,
                user_id=self._eq_session.user_id,
            )
        else:
            logger.debug("eq_session_id not found in database",
                         eq_session_id=self.eq_session_id)
コード例 #24
0
ファイル: jws.py プロジェクト: Allu2/jwcrypto
 def verify(self, key, payload, signature):
     vkey = base64url_decode(key.get_op_key('verify'))
     h = self._hmac_setup(vkey, payload)
     try:
         h.verify(signature)
     except InvalidSignature as e:
         raise InvalidJWSSignature(exception=e)
コード例 #25
0
 def jti_size_should_be_as_expected(self, claims):
     """ Check jti size """
     if jti_size and not callable(
             privk
     ):  # don't assume format of externally-generated JTIs
         expect(len(base64url_decode(
             claims['jti']))).to_equal(jti_size)
コード例 #26
0
def process_jwt(jwt):
    """
    Process a JSON Web Token without verifying it.

    Call this before :func:`verify_jwt` if you need access to the header or claims in the token before verifying it. For example, the claims might identify the issuer such that you can retrieve the appropriate public key.

    :param jwt: The JSON Web Token to verify.
    :type jwt: str or unicode

    :rtype: tuple
    :returns: ``(header, claims)``
    """
    header, claims, _ = jwt.split('.')
    parsed_header = json_decode(base64url_decode(header))
    parsed_claims = json_decode(base64url_decode(claims))
    return parsed_header, parsed_claims
コード例 #27
0
    def _get_key(self, alg, key, p2s, p2c):
        if not isinstance(key, JWK):
            # backwards compatiblity for old interface
            if isinstance(key, bytes):
                plain = key
            else:
                plain = key.encode('utf8')
        else:
            plain = base64url_decode(key.get_op_key())

        salt = bytes(self.name.encode('utf8')) + b'\x00' + p2s

        if self.hashsize == 256:
            hashalg = hashes.SHA256()
        elif self.hashsize == 384:
            hashalg = hashes.SHA384()
        elif self.hashsize == 512:
            hashalg = hashes.SHA512()
        else:
            raise ValueError('Unknown Hash Size')

        kdf = PBKDF2HMAC(algorithm=hashalg, length=_inbytes(self.keysize),
                         salt=salt, iterations=p2c, backend=self.backend)
        rk = kdf.derive(plain)
        if _bitsize(rk) != self.keysize:
            raise InvalidJWEKeyLength(self.keysize, len(rk))
        return JWK(kty="oct", use="enc", k=base64url_encode(rk))
コード例 #28
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_4_3_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_3_2).decode('utf-8')
     pub_key = jwk.JWK(**EC_Public_Key_3_1)
     pri_key = jwk.JWK(**EC_Private_Key_3_2)
     S = jws.JWS(payload=plaintext)
     S.add_signature(pri_key, None, protected)
     # Can't compare signature with reference because ECDSA uses
     # random nonces every time a signature is generated.
     sig = S.serialize()
     S.deserialize(sig, pub_key)
     # Just deserialize each example form
     S.deserialize(JWS_compact_4_3_3, pub_key)
     S.deserialize(json_encode(JWS_general_4_3_3), pub_key)
     S.deserialize(json_encode(JWS_flattened_4_3_3), pub_key)
コード例 #29
0
 def topic(self):
     """ Generate token """
     token = jwt.generate_jwt(payload, None, 'none', timedelta(seconds=60))
     header, claims, _ = token.split('.')
     parsed_header = json_decode(base64url_decode(header))
     del parsed_header['alg']
     return u"%s.%s." % (base64url_encode(json_encode(parsed_header)), claims)
コード例 #30
0
 def test_4_3_signing(self):
     plaintext = base64url_decode(Payload_plaintext_b64_4)
     protected = \
         base64url_decode(JWS_Protected_Header_4_3_2).decode('utf-8')
     pub_key = jwk.JWK(**EC_Public_Key_3_1)
     pri_key = jwk.JWK(**EC_Private_Key_3_2)
     S = jws.JWS(payload=plaintext)
     S.add_signature(pri_key, None, protected)
     # Can't compare signature with reference because ECDSA uses
     # random nonces every time a signature is generated.
     sig = S.serialize()
     S.deserialize(sig, pub_key)
     # Just deserialize each example form
     S.deserialize(JWS_compact_4_3_3, pub_key)
     S.deserialize(json_encode(JWS_general_4_3_3), pub_key)
     S.deserialize(json_encode(JWS_flattened_4_3_3), pub_key)
コード例 #31
0
ファイル: jsf.py プロジェクト: yurikhan/jsf
    def _verify(self, prop: str, key: JWK, alg: Optional[AlgorithmName],
                header: JsonObject, signer: Optional[JsonObject],
                patch_header: _PatchHeader) -> None:
        a = self._get_alg(alg, signer or header, InvalidJWSSignature)

        # Prepare payload for verification algorithm
        payload = copy(self._payload)
        h = copy(header)
        s = copy(signer)
        signature = base64url_decode((s or h).pop(_VALUE))
        exclude = h.pop(_EXCLUDES, [])
        for x in exclude:
            payload.pop(x, None)

        h.update(patch_header(s))

        payload[prop] = h
        canonical = _dumpb(payload)

        # Verify signature
        if key is None:
            key = JWK(**((s or h).get(_PUBLICKEY, None)))
        c = JWSCore(a, key, header=None, payload='',
                    algs=self._allowed_algs)
        c.engine.verify(key, canonical, signature)
コード例 #32
0
ファイル: jwe.py プロジェクト: tiran/jwcrypto
 def unwrap(self, key, keylen, ek, headers):
     self._check_key(key)
     if ek != b'':
         raise InvalidJWEData('Invalid Encryption Key.')
     cek = base64url_decode(key.get_op_key('decrypt'))
     if len(cek) != keylen:
         raise InvalidJWEKeyLength(keylen, len(cek))
     return cek
コード例 #33
0
    def unwrap(self, key, bitsize, ek, headers):
        rk = self._get_key(key, 'decrypt')

        if 'iv' not in headers:
            raise ValueError('Invalid Header, missing "iv" parameter')
        iv = base64url_decode(headers['iv'])
        if 'tag' not in headers:
            raise ValueError('Invalid Header, missing "tag" parameter')
        tag = base64url_decode(headers['tag'])

        cipher = Cipher(algorithms.AES(rk), modes.GCM(iv, tag),
                        backend=self.backend)
        decryptor = cipher.decryptor()
        cek = decryptor.update(ek) + decryptor.finalize()
        if _bitsize(cek) != bitsize:
            raise InvalidJWEKeyLength(bitsize, _bitsize(cek))
        return cek
コード例 #34
0
 def wrap(self, key, bitsize, cek, headers):
     self._check_key(key)
     if cek:
         return (cek, None)
     k = base64url_decode(key.get_op_key('encrypt'))
     if _bitsize(k) != bitsize:
         raise InvalidCEKeyLength(bitsize, _bitsize(k))
     return {'cek': k}
 def _get_base64_encoded_data(self, data):
     """
     Legacy data was stored in a dict, base64-encoded, and not compressed:
     { 'data': '<base 64 encoded and encrypted data' }
     """
     data = json.loads(data).get('data')
     decrypted_data = self.encrypter.decrypt_data(data)
     return base64url_decode(decrypted_data.decode()).decode()
コード例 #36
0
ファイル: jwe.py プロジェクト: tiran/jwcrypto
    def unwrap(self, key, keylen, ek, headers):
        rk = self._get_key(key, 'decrypt')

        if 'iv' not in headers:
            raise InvalidJWEData('Invalid Header, missing "iv" parameter')
        iv = base64url_decode(headers['iv'])
        if 'tag' not in headers:
            raise InvalidJWEData('Invalid Header, missing "tag" parameter')
        tag = base64url_decode(headers['tag'])

        cipher = Cipher(algorithms.AES(rk), modes.GCM(iv, tag),
                        backend=self.backend)
        decryptor = cipher.decryptor()
        cek = decryptor.update(ek) + decryptor.finalize()
        if len(cek) != keylen:
            raise InvalidJWEKeyLength(keylen, len(cek))
        return cek
コード例 #37
0
ファイル: jwe.py プロジェクト: ColtonProvias/jwcrypto
 def wrap(self, key, keylen, cek):
     self.check_key(key)
     if cek:
         return (cek, None)
     k = base64url_decode(key.get_op_key('encrypt'))
     if len(k) != keylen:
         raise InvalidCEKeyLength(keylen, len(k))
     return (k, '')
コード例 #38
0
 def unwrap(self, key, bitsize, ek, headers):
     self._check_key(key)
     if ek != b'':
         raise ValueError('Invalid Encryption Key.')
     cek = base64url_decode(key.get_op_key('decrypt'))
     if _bitsize(cek) != bitsize:
         raise InvalidJWEKeyLength(bitsize, _bitsize(cek))
     return cek
コード例 #39
0
 def topic(self):
     """ Generate token """
     token = jwt.generate_jwt(payload, None, 'none', timedelta(seconds=60))
     header, claims, _ = token.split('.')
     parsed_header = json_decode(base64url_decode(header))
     del parsed_header['alg']
     return u"%s.%s." % (base64url_encode(
         json_encode(parsed_header)), claims)
コード例 #40
0
    def _okp_pub(self):
        crv = self._params.get('crv', None)
        try:
            pubkey = _OKP_CURVES_TABLE[crv].pubkey
        except KeyError:
            raise InvalidJWKValue('Unknown curve "%s"' % crv)

        x = base64url_decode(self._params['x'])
        return pubkey.from_public_bytes(x)
コード例 #41
0
    def _okp_pri(self):
        crv = self._params.get('crv', None)
        try:
            privkey = _OKP_CURVES_TABLE[crv].privkey
        except KeyError:
            raise InvalidJWKValue('Unknown curve "%s"' % crv)

        d = base64url_decode(self._params['d'])
        return privkey.from_private_bytes(d)
コード例 #42
0
ファイル: jwe.py プロジェクト: tiran/jwcrypto
 def _get_key(self, key, op):
     if not isinstance(key, JWK):
         raise ValueError('key is not a JWK object')
     if key.key_type != 'oct':
         raise InvalidJWEKeyType('oct', key.key_type)
     rk = base64url_decode(key.get_op_key(op))
     if len(rk) != self.keysize:
         raise InvalidJWEKeyLength(self.keysize * 8, len(rk) * 8)
     return rk
コード例 #43
0
 def _get_key(self, key, op):
     if not isinstance(key, JWK):
         raise ValueError('key is not a JWK object')
     if key.key_type != 'oct':
         raise InvalidJWEKeyType('oct', key.key_type)
     rk = base64url_decode(key.get_op_key(op))
     if _bitsize(rk) != self.keysize:
         raise InvalidJWEKeyLength(self.keysize, _bitsize(rk))
     return rk
コード例 #44
0
ファイル: __init__.py プロジェクト: davedoesdev/node-jsjws
def verify(sjws, pub_pem):
    sjws = json_decode(sjws)
    pub_pem = json_decode(pub_pem.replace('\n', '\\n'))
    if pub_pem.startswith("-----BEGIN"):
        pub_key = JWK.from_pem(to_bytes_2and3(pub_pem))
    else:
        pub_key = JWK(kty='oct', k=base64url_encode(pub_pem))
    sig = JWS()
    sig.deserialize(sjws, pub_key)
    sys.stdout.write(base64url_decode(json_decode(sig.serialize())['payload']))
コード例 #45
0
ファイル: jwe.py プロジェクト: tiran/jwcrypto
    def unwrap(self, key, keylen, ek, headers):
        if 'p2s' not in headers:
            raise InvalidJWEData('Invalid Header, missing "p2s" parameter')
        if 'p2c' not in headers:
            raise InvalidJWEData('Invalid Header, missing "p2c" parameter')
        p2s = base64url_decode(headers['p2s'])
        p2c = headers['p2c']
        kek = self._get_key(headers['alg'], key, p2s, p2c)

        aeskw = _AesKw(self.keysize * 8)
        return aeskw.unwrap(kek, keylen, ek, headers)
コード例 #46
0
 def f(sjwt, iat_skew=timedelta()):
     """ verify token using node-jsjws """
     r = spawn(
         "fixtures.verify({now}, {sjwt}, {iat_skew}, {key}, {alg})".format(
             now=timegm(datetime.utcnow().utctimetuple()),
             sjwt=json_encode(sjwt),
             iat_skew=iat_skew.total_seconds(),
             key=json_encode(base64url_decode(json_decode(key.export())['k']) if key.is_symmetric else key.export_to_pem()),
             alg=json_encode(alg)),
         True)
     return tuple(r)
コード例 #47
0
 def f(claims, alg, lifetime=None, expires=None, not_before=None):
     """ generate token using node-jsjws """
     now = datetime.utcnow()
     return spawn(
         "fixtures.generate({now}, {header}, {claims}, {expires}, {not_before}, {key})".format(
             now=timegm(now.utctimetuple()),
             header=json_encode({'alg': alg}),
             claims=json_encode(claims),
             expires=timegm(((now + lifetime) if lifetime else expires).utctimetuple()),
             not_before=timegm((not_before or now).utctimetuple()),
             key=json_encode(base64url_decode(json_decode(key.export())['k']) if key.is_symmetric else key.export_to_pem(True, None))),
         False)
コード例 #48
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_5_6_encryption(self):
     plaintext = Payload_plaintext_5
     protected = base64url_decode(JWE_Protected_Header_5_6_3)
     aes_key = jwk.JWK(**AES_key_5_6_1)
     E = jwe.JWE(plaintext, protected)
     E.add_recipient(aes_key)
     _ = E.serialize(compact=True)
     e = E.serialize()
     E.deserialize(e, aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(JWE_compact_5_6_4, aes_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_general_5_6_4), aes_key)
     self.assertEqual(E.payload, plaintext)
コード例 #49
0
ファイル: tests-cookbook.py プロジェクト: Allu2/jwcrypto
 def test_5_2_encryption(self):
     plaintext = Payload_plaintext_5
     protected = base64url_decode(JWE_Protected_Header_5_2_4)
     rsa_key = jwk.JWK(**RSA_key_5_2_1)
     E = jwe.JWE(plaintext, protected)
     E.add_recipient(rsa_key)
     e = E.serialize()
     E.deserialize(e, rsa_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(JWE_compact_5_2_5, rsa_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_general_5_2_5), rsa_key)
     self.assertEqual(E.payload, plaintext)
     E.deserialize(json_encode(JWE_flattened_5_2_5), rsa_key)
     self.assertEqual(E.payload, plaintext)
コード例 #50
0
ファイル: tests.py プロジェクト: pombredanne/jwcrypto
 def check_sign(self, test):
     s = jws.JWSCore(test['alg'],
                     jwk.JWK(**test['key']),
                     test['protected'],
                     test['payload'],
                     test.get('allowed_algs', None))
     sig = s.sign()
     decsig = base64url_decode(sig['signature'])
     s.verify(decsig)
     # ECDSA signatures are always different every time
     # they are generated unlike RSA or symmetric ones
     if test['key']['kty'] != 'EC':
         self.assertEqual(decsig, test['signature'])
     else:
         # Check we can verify the test signature independently
         # this is so taht we can test the ECDSA agaist a known
         # good signature
         s.verify(test['signature'])
コード例 #51
0
ファイル: jwe.py プロジェクト: Allu2/jwcrypto
    def deserialize(self, raw_jwe, key=None):
        """Deserialize a JWE token.

        NOTE: Destroys any current status and tries to import the raw
        JWE provided.

        :param raw_jwe: a 'raw' JWE token (JSON Encoded or Compact
         notation) string.
        :param key: A (:class:`jwcrypto.jwk.JWK`) decryption key (optional).
         If a key is provided a idecryption step will be attempted after
         the object is successfully deserialized.

        :raises InvalidJWEData: if the raw object is an invaid JWE token.
        :raises InvalidJWEOperation: if the decryption fails.
        """

        self.objects = dict()
        self.plaintext = None
        self.cek = None

        o = dict()
        try:
            try:
                djwe = json_decode(raw_jwe)
                o['iv'] = base64url_decode(str(djwe['iv']))
                o['ciphertext'] = base64url_decode(str(djwe['ciphertext']))
                o['tag'] = base64url_decode(str(djwe['tag']))
                if 'protected' in djwe:
                    p = base64url_decode(str(djwe['protected']))
                    o['protected'] = p.decode('utf-8')
                if 'unprotected' in djwe:
                    o['unprotected'] = json_encode(djwe['unprotected'])
                if 'aad' in djwe:
                    o['aad'] = base64url_decode(str(djwe['aad']))
                if 'recipients' in djwe:
                    o['recipients'] = list()
                    for rec in djwe['recipients']:
                        e = dict()
                        if 'encrypted_key' in rec:
                            e['encrypted_key'] = \
                                base64url_decode(str(rec['encrypted_key']))
                        if 'header' in rec:
                            e['header'] = json_encode(rec['header'])
                        o['recipients'].append(e)
                else:
                    if 'encrypted_key' in djwe:
                        o['encrypted_key'] = \
                            base64url_decode(str(djwe['encrypted_key']))
                    if 'header' in djwe:
                        o['header'] = json_encode(djwe['header'])

            except ValueError:
                c = raw_jwe.split('.')
                if len(c) != 5:
                    raise InvalidJWEData()
                p = base64url_decode(str(c[0]))
                o['protected'] = p.decode('utf-8')
                ekey = base64url_decode(str(c[1]))
                if ekey != '':
                    o['encrypted_key'] = base64url_decode(str(c[1]))
                o['iv'] = base64url_decode(str(c[2]))
                o['ciphertext'] = base64url_decode(str(c[3]))
                o['tag'] = base64url_decode(str(c[4]))

            self.objects = o

        except Exception as e:  # pylint: disable=broad-except
            raise InvalidJWEData('Invalid format', repr(e))

        if key:
            self.decrypt(key)
コード例 #52
0
ファイル: jwe.py プロジェクト: Allu2/jwcrypto
 def unwrap(self, key, ek):
     self.check_key(key)
     if ek != b'':
         raise InvalidJWEData('Invalid Encryption Key.')
     return base64url_decode(key.get_op_key('decrypt'))
コード例 #53
0
ファイル: jwt_spec.py プロジェクト: davedoesdev/python-jwt
 def jti_size_should_be_as_expected(self, claims):
     """ Check jti size """
     if jti_size and not callable(privk): # don't assume format of externally-generated JTIs
         expect(len(base64url_decode(claims['jti']))).to_equal(jti_size)
コード例 #54
0
ファイル: __init__.py プロジェクト: davedoesdev/python-jwt
def verify_jwt(jwt,
               pub_key=None,
               allowed_algs=None,
               iat_skew=timedelta(),
               checks_optional=False,
               ignore_not_implemented=False):
    """
    Verify a JSON Web Token.

    :param jwt: The JSON Web Token to verify.
    :type jwt: str or unicode

    :param pub_key: The public key to be used to verify the token. Note: if you pass ``None`` and **allowed_algs** contains ``none`` then the token's signature will not be verified.
    :type pub_key: `jwcrypto.jwk.JWK <https://jwcrypto.readthedocs.io/en/latest/jwk.html>`_

    :param allowed_algs: Algorithms expected to be used to sign the token. The ``in`` operator is used to test membership.
    :type allowed_algs: list or NoneType (meaning an empty list)

    :param iat_skew: The amount of leeway to allow between the issuer's clock and the verifier's clock when verifiying that the token was generated in the past. Defaults to no leeway.
    :type iat_skew: datetime.timedelta

    :param checks_optional: If ``False``, then the token must contain the **typ** header property and the **iat**, **nbf** and **exp** claim properties.
    :type checks_optional: bool

    :param ignore_not_implemented: If ``False``, then the token must *not* contain the **jku**, **jwk**, **x5u**, **x5c** or **x5t** header properties.
    :type ignore_not_implemented: bool

    :rtype: tuple
    :returns: ``(header, claims)`` if the token was verified successfully. The token must pass the following tests:

    - Its header must contain a property **alg** with a value in **allowed_algs**.
    - Its signature must verify using **pub_key** (unless its algorithm is ``none`` and ``none`` is in **allowed_algs**).
    - If the corresponding property is present or **checks_optional** is ``False``:

      - Its header must contain a property **typ** with the value ``JWT``.
      - Its claims must contain a property **iat** which represents a date in the past (taking into account :obj:`iat_skew`).
      - Its claims must contain a property **nbf** which represents a date in the past.
      - Its claims must contain a property **exp** which represents a date in the future.

    :raises: If the token failed to verify.
    """
    if allowed_algs is None:
        allowed_algs = []

    if not isinstance(allowed_algs, list):
        # jwcrypto only supports list of allowed algorithms
        raise _JWTError('allowed_algs must be a list')

    header, claims, _ = jwt.split('.')

    parsed_header = json_decode(base64url_decode(header))

    alg = parsed_header.get('alg')
    if alg is None:
        raise _JWTError('alg header not present')
    if alg not in allowed_algs:
        raise _JWTError('algorithm not allowed: ' + alg)

    if not ignore_not_implemented:
        for k in parsed_header:
            if k not in JWSHeaderRegistry:
                raise _JWTError('unknown header: ' + k)
            if not JWSHeaderRegistry[k].supported:
                raise _JWTError('header not implemented: ' + k)

    if pub_key:
        token = JWS()
        token.allowed_algs = allowed_algs
        token.deserialize(jwt, pub_key)
    elif 'none' not in allowed_algs:
        raise _JWTError('no key but none alg not allowed')

    parsed_claims = json_decode(base64url_decode(claims))

    utcnow = datetime.utcnow()
    now = timegm(utcnow.utctimetuple())

    typ = parsed_header.get('typ')
    if typ is None:
        if not checks_optional:
            raise _JWTError('typ header not present')
    elif typ != 'JWT':
        raise _JWTError('typ header is not JWT')

    iat = parsed_claims.get('iat')
    if iat is None:
        if not checks_optional:
            raise _JWTError('iat claim not present')
    elif iat > timegm((utcnow + iat_skew).utctimetuple()):
        raise _JWTError('issued in the future')

    nbf = parsed_claims.get('nbf')
    if nbf is None:
        if not checks_optional:
            raise _JWTError('nbf claim not present')
    elif nbf > now:
        raise _JWTError('not yet valid')

    exp = parsed_claims.get('exp')
    if exp is None:
        if not checks_optional:
            raise _JWTError('exp claim not present')
    elif exp <= now:
        raise _JWTError('expired')

    return parsed_header, parsed_claims
コード例 #55
0
ファイル: jwk.py プロジェクト: pombredanne/jwcrypto
 def _decode_int(self, n):
     return int(hexlify(base64url_decode(n)), 16)
コード例 #56
0
ファイル: jws.py プロジェクト: Allu2/jwcrypto
 def sign(self, key, payload):
     skey = base64url_decode(key.get_op_key('sign'))
     h = self._hmac_setup(skey, payload)
     return h.finalize()
コード例 #57
0
ファイル: jws.py プロジェクト: Allu2/jwcrypto
    def add_signature(self, key, alg=None, protected=None, header=None):
        """Adds a new signature to the object.

        :param key: A (:class:`jwcrypto.jwk.JWK`) key of appropriate for
         the "alg" provided.
        :param alg: An optional algorithm name. If already provided as an
         element of the protected or unprotected header it can be safely
         omitted.
        :param potected: The Protected Header (optional)
        :param header: The Unprotected Header (optional)

        :raises InvalidJWSObject: if no payload has been set on the object.
        :raises ValueError: if the key is not a :class:`JWK` object.
        :raises ValueError: if the algorithm is missing or is not provided
         by one of the headers.
        :raises InvalidJWAAlgorithm: if the algorithm is not valid, is
         unknown or otherwise not yet implemented.
        """

        if not self.objects.get('payload', None):
            raise InvalidJWSObject('Missing Payload')

        p = dict()
        if protected:
            p = json_decode(protected)
            # TODO: allow caller to specify list of headers it understands
            if 'crit' in p:
                self._check_crit(p['crit'])

        if header:
            h = json_decode(header)
            p = self._merge_headers(p, h)

        if 'alg' in p:
            if alg is None:
                alg = p['alg']
            elif alg != p['alg']:
                raise ValueError('"alg" value mismatch, specified "alg" '
                                 'does not match JOSE header value')

        if alg is None:
            raise ValueError('"alg" not specified')

        S = JWSCore(alg, key, protected, self.objects['payload'])
        sig = S.sign()

        o = dict()
        o['signature'] = base64url_decode(sig['signature'])
        if protected:
            o['protected'] = protected
        if header:
            o['header'] = h
        o['valid'] = True

        if 'signatures' in self.objects:
            self.objects['signatures'].append(o)
        elif 'signature' in self.objects:
            self.objects['signatures'] = list()
            n = dict()
            n['signature'] = self.objects['signature']
            del self.objects['signature']
            if 'protected' in self.objects:
                n['protected'] = self.objects['protected']
                del self.objects['protected']
            if 'header' in self.objects:
                n['header'] = self.objects['header']
                del self.objects['header']
            if 'valid' in self.objects:
                n['valid'] = self.objects['valid']
                del self.objects['valid']
            self.objects['signatures'].append(n)
            self.objects['signatures'].append(o)
        else:
            self.objects.update(o)
コード例 #58
0
ファイル: tests.py プロジェクト: pombredanne/jwcrypto
A4_example = {'key': A4_key,
              'alg': 'ES512',
              'protected': bytes(bytearray(A4_protected)).decode('utf-8'),
              'payload': bytes(bytearray(A4_payload)),
              'signature': bytes(bytearray(A4_signature))}


# RFC 7515 - A.4
A5_protected = 'eyJhbGciOiJub25lIn0'
A5_payload = A2_payload
A5_key = \
    {"kty": "oct", "k": ""}
A5_signature = b''
A5_example = {'key': A5_key,
              'alg': 'none',
              'protected': base64url_decode(A5_protected).decode('utf-8'),
              'payload': bytes(bytearray(A5_payload)),
              'signature': A5_signature}

A6_serialized = \
    '{' + \
    '"payload":' + \
    '"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF' + \
    'tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",' + \
    '"signatures":[' + \
    '{"protected":"eyJhbGciOiJSUzI1NiJ9",' + \
    '"header":' + \
    '{"kid":"2010-12-29"},' + \
    '"signature":' + \
    '"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ' + \
    'mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb' + \