def forgot_password(mode) : """ @app.route('/forgot_password/', methods = ['GET', 'POST']) This function is called from the login view. build JWE to store timestamp, username and email, we use Talao RSA key """ if request.method == 'GET' : return render_template('./login/forgot_password_init.html') if request.method == 'POST' : username = request.form.get('username') if not ns.username_exist(username, mode) : flash("Username not found", "warning") return render_template('./login/login_password.html') email= ns.get_data_from_username(username, mode)['email'] private_rsa_key = privatekey.get_key(mode.owner_talao, 'rsa_key', mode) RSA_KEY = RSA.import_key(private_rsa_key) public_rsa_key = RSA_KEY.publickey().export_key('PEM').decode('utf-8') expired = datetime.timestamp(datetime.now()) + 180 # 3 minutes live # build JWE jwe = JsonWebEncryption() header = {'alg': 'RSA1_5', 'enc': 'A256GCM'} json_string = json.dumps({'username' : username, 'email' : email, 'expired' : expired}) payload = bytes(json_string, 'utf-8') token = jwe.serialize_compact(header, payload, public_rsa_key) link = mode.server + 'forgot_password_token/?'+ urlencode({'token' : token.decode('utf-8')}, doseq=True) subject = "Renew your password" if Talao_message.messageHTML(subject, email, 'forgot_password', {'link': link}, mode): flash("You are going to receive an email to renew your password.", "success") return render_template('./login/login_password.html')
def forgot_password_token(mode) : """ @app.route('/forgot_password_token/', methods = ['GET', 'POST']) This function is called from email to decode token and reset password. """ if request.method == 'GET' : token = request.args.get('token') key = privatekey.get_key(mode.owner_talao, 'rsa_key', mode) jwe = JsonWebEncryption() try : data = jwe.deserialize_compact(token, key) except : flash ('Incorrect data', 'danger') logging.warning('JWE did not decrypt') return render_template('./login/login_password.html') payload = json.loads(data['payload'].decode('utf-8')) if payload['expired'] < datetime.timestamp(datetime.now()) : flash ('Delay expired (3 minutes maximum)', 'danger') return render_template('./login/login_password.html') session['email_password'] = payload['email'] session['username_password'] = payload['username'] return render_template('./login/update_password_external.html') if request.method == 'POST' : if session['email_password'] != request.form['email'] : flash('Incorrect email', 'danger') return render_template('./login/update_password_external.html') ns.update_password(session['username_password'], request.form['password'], mode) flash('Password updated', "success") del session['email_password'] del session['username_password'] return render_template('./login/login_password.html')
def decode_row_batch(crypt: CryptoOptions, data) -> vpb.RowBatchData: jwe = JsonWebEncryption() rb = vpb.RowBatchData() data = jwe.deserialize_compact(data, crypt.jwk_private_key) rb.ParseFromString(data['payload']) return rb
def decrypt(self, token, key, type='AES'): if type == 'AES': data = SJCL.decrypt(self, token, key) return data.decode() else: jwe = JsonWebEncryption() data = jwe.deserialize_compact(token, key) return data['payload'].decode()
def test_compact_rsa(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) s = jwe.serialize_compact({ 'alg': 'RSA-OAEP', 'enc': 'A256GCM' }, 'hello', read_file_path('rsa_public.pem')) data = jwe.deserialize_compact(s, read_file_path('rsa_private.pem')) header, payload = data['header'], data['payload'] self.assertEqual(payload, b'hello') self.assertEqual(header['alg'], 'RSA-OAEP')
def test_ecdh_es_with_okp(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) key = OKPKey.generate_key('X25519', is_private=True) for alg in [ "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW" ]: protected = {'alg': alg, 'enc': 'A128GCM'} data = jwe.serialize_compact(protected, b'hello', key) rv = jwe.deserialize_compact(data, key) self.assertEqual(rv['payload'], b'hello')
def test_with_zip_header(self): jwe = JsonWebEncryption() s = jwe.serialize_compact( { 'alg': 'RSA-OAEP', 'enc': 'A128CBC-HS256', 'zip': 'DEF' }, 'hello', read_file_path('rsa_public.pem')) data = jwe.deserialize_compact(s, read_file_path('rsa_private.pem')) header, payload = data['header'], data['payload'] self.assertEqual(payload, b'hello') self.assertEqual(header['alg'], 'RSA-OAEP')
def test_dir_alg_c20p(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) key = OctKey.generate_key(256, is_private=True) protected = {'alg': 'dir', 'enc': 'C20P'} data = jwe.serialize_compact(protected, b'hello', key) rv = jwe.deserialize_compact(data, key) self.assertEqual(rv['payload'], b'hello') key2 = OctKey.generate_key(128, is_private=True) self.assertRaises(ValueError, jwe.deserialize_compact, data, key2) self.assertRaises(ValueError, jwe.serialize_compact, protected, b'hello', key2)
def test_ecdh_es_raise(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) protected = {'alg': 'ECDH-ES', 'enc': 'A128GCM'} key = { "kty": "EC", "crv": "P-256", "x": "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y": "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", } data = jwe.serialize_compact(protected, b'hello', key) self.assertRaises(ValueError, jwe.deserialize_compact, data, key) key = OKPKey.generate_key('Ed25519', is_private=True) self.assertRaises(ValueError, jwe.serialize_compact, protected, b'hello', key)
def test_aes_gcm_jwe(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) sizes = [128, 192, 256] _enc_choices = [ 'A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512', 'A128GCM', 'A192GCM', 'A256GCM' ] for s in sizes: alg = 'A{}GCMKW'.format(s) key = os.urandom(s // 8) for enc in _enc_choices: protected = {'alg': alg, 'enc': enc} data = jwe.serialize_compact(protected, b'hello', key) rv = jwe.deserialize_compact(data, key) self.assertEqual(rv['payload'], b'hello')
def test_ecdh_es_jwe(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) key = { "kty": "EC", "crv": "P-256", "x": "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y": "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", "d": "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" } for alg in [ "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW" ]: protected = {'alg': alg, 'enc': 'A128GCM'} data = jwe.serialize_compact(protected, b'hello', key) rv = jwe.deserialize_compact(data, key) self.assertEqual(rv['payload'], b'hello')
def test_ecdh_key_agreement_computation(self): # https://tools.ietf.org/html/rfc7518#appendix-C jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) alice_key = { "kty": "EC", "crv": "P-256", "x": "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y": "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", "d": "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" } bob_key = { "kty": "EC", "crv": "P-256", "x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", "d": "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw" } headers = { "alg": "ECDH-ES", "enc": "A128GCM", "apu": "QWxpY2U", "apv": "Qm9i", } alg = jwe._alg_algorithms['ECDH-ES'] key = alg.prepare_key(alice_key) bob_key = alg.prepare_key(bob_key) public_key = bob_key.get_op_key('wrapKey') dk = alg.deliver(key, public_key, headers, 128) self.assertEqual(urlsafe_b64encode(dk), b'VqqN6vgjbSBcIijNcacQGg')
def encrypted_script_response( self, opts: vpb.ExecuteScriptRequest.EncryptionOptions ) -> vpb.ExecuteScriptResponse: ''' Returns a script repsonse with encrypted row batch fields, if they exist, and if the options are set. ''' es_resp = self.execute_script_response if not es_resp.HasField("data"): return es_resp if opts is None: return es_resp # Now we encrypt the batch. rb = es_resp.data.batch.SerializeToString() key = JsonWebKey.import_key(json.loads(opts.jwk_key)) encrypted_batch = JsonWebEncryption().serialize_compact( { 'alg': opts.key_alg, 'enc': opts.content_alg, 'zip': opts.compression_alg, }, rb, key) # Make sure we only send the encrypted_batch through. es_resp.data.ClearField('batch') es_resp.data.encrypted_batch = encrypted_batch return es_resp
def encrypt(self, data, type='AES', Key=None, dump=True): """ Encrypt data using RSA , AES param: type= type of key used in encryption: 'AES' or 'RSA' param: key= use your own key for RSA encryption param: dump= dumps the data if neccessary """ if dump == True: payload = str(json.dumps(data)).encode() else: payload = str(data).encode() if type == 'RSA': key = RSA.generate(2048) key = key.exportKey('PEM') key = jwk.dumps(key, kty='RSA') if Key: key = Key protected = {'alg': 'RSA-OAEP', 'enc': 'A256GCM'} jwe = JsonWebEncryption() token = jwe.serialize_compact(protected, payload, key) token = token.decode() else: key = secrets.token_urlsafe(32) token = SJCL().encrypt(payload, key, "ccm", 1000, 32) token['salt'] = str(token['salt']).replace("b'", "").replace("'", "") token['ct'] = str(token['ct']).replace("b'", "").replace("'", "") token['iv'] = str(token['iv']).replace("b'", "").replace("'", "") dic = {} dic['iv'] = token['iv'] dic['v'] = token['v'] dic['iter'] = token['iter'] dic['ks'] = token['ks'] dic['ts'] = token['ts'] dic['mode'] = token['mode'] dic['adata'] = token['adata'] dic['cipher'] = token['cipher'] dic['salt'] = token['salt'] dic['ct'] = token['ct'] token = dic return {'token': token, 'key': key}
def test_not_supported_alg(self): public_key = read_file_path('rsa_public.pem') private_key = read_file_path('rsa_private.pem') jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) s = jwe.serialize_compact({ 'alg': 'RSA-OAEP', 'enc': 'A256GCM' }, 'hello', public_key) jwe = JsonWebEncryption(algorithms=['RSA1_5', 'A256GCM']) self.assertRaises(errors.UnsupportedAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA-OAEP', 'enc': 'A256GCM' }, 'hello', public_key) self.assertRaises(errors.UnsupportedCompressionAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA1_5', 'enc': 'A256GCM', 'zip': 'DEF' }, 'hello', public_key) self.assertRaises( errors.UnsupportedAlgorithmError, jwe.deserialize_compact, s, private_key, ) jwe = JsonWebEncryption(algorithms=['RSA-OAEP', 'A192GCM']) self.assertRaises(errors.UnsupportedEncryptionAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA-OAEP', 'enc': 'A256GCM' }, 'hello', public_key) self.assertRaises(errors.UnsupportedCompressionAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA-OAEP', 'enc': 'A192GCM', 'zip': 'DEF' }, 'hello', public_key) self.assertRaises( errors.UnsupportedEncryptionAlgorithmError, jwe.deserialize_compact, s, private_key, )
def test_invalid_header(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) public_key = read_file_path('rsa_public.pem') self.assertRaises(errors.MissingAlgorithmError, jwe.serialize_compact, {}, 'a', public_key) self.assertRaises(errors.UnsupportedAlgorithmError, jwe.serialize_compact, {'alg': 'invalid'}, 'a', public_key) self.assertRaises(errors.MissingEncryptionAlgorithmError, jwe.serialize_compact, {'alg': 'RSA-OAEP'}, 'a', public_key) self.assertRaises(errors.UnsupportedEncryptionAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA-OAEP', 'enc': 'invalid' }, 'a', public_key) self.assertRaises(errors.UnsupportedCompressionAlgorithmError, jwe.serialize_compact, { 'alg': 'RSA-OAEP', 'enc': 'A256GCM', 'zip': 'invalid' }, 'a', public_key)
def _create(address_from, workspace_contract_from, address_to, workspace_contract_to, private_key_from, doctype, data, mydays, privacy, mode, synchronous, version, id, sequence): # align doctype with privacy if privacy == 'private' and doctype == 20000: doctype = 20001 if privacy == 'secret' and doctype == 20000: doctype = 20002 # @data = dict if isinstance(data, str): data = json.loads(data) logging.error('data must be a dict') #encrypt data with AES key (public, private or secret) Deprecated if version == 3: data = privatekey.encrypt_data(workspace_contract_to, data, privacy, mode) if not data: logging.error('encryption problem') return None, None, None #encrypt server side data as JWE with identity RSA key elif version == 4: jwe = JsonWebEncryption() protected = {'alg': 'RSA-OAEP', 'enc': 'A256GCM'} payload = json.dumps(data).encode() private_rsa_key = privatekey.get_key(address_to, 'rsa_key', mode) RSA_KEY = RSA.import_key(private_rsa_key) public_rsa_key = RSA_KEY.publickey().export_key('PEM').decode('utf-8') if not id: id = str(uuid.uuid1()) if not sequence: sequence = 0 data = { "id": id, "sequence": sequence, "jwe": jwe.serialize_compact(protected, payload, public_rsa_key).decode() } # encrypt data with AES key of identity" elif version == 5: jwe = JsonWebEncryption() protected = {'alg': 'A128KW', 'enc': 'A128CBC-HS256'} payload = json.dumps(data).encode() if privacy == 'public': secret = mode.aes_public_key.encode() else: secret = privatekey.get_key(address_to, privacy, mode) if not id: id = str(uuid.uuid1()) if not sequence: sequence = 0 data = { "id": id, "sequence": sequence, "jwe": jwe.serialize_compact(protected, payload, secret).decode() } # No data encryption. data have been probably encrypted as JWE client side elif version == 6: data = { "id": str(uuid.uuid1()), "sequence": 0, 'jwe': json.dumps(data) } else: logging.error('pb version') return None, None, None # Build transaction contract = mode.w3.eth.contract(workspace_contract_to, abi=constante.workspace_ABI) nonce = mode.w3.eth.getTransactionCount(address_from) # upkoad on ipfs ipfs_hash = Talao_ipfs.ipfs_add(data, mode) if not ipfs_hash: logging.error('IPFS connexion problem') return None, None, None # checksum (bytes) checksum = hashlib.md5(bytes(json.dumps(data), 'utf-8')).hexdigest() # Transaction expires = 0 txn = contract.functions.createDocument(doctype, version, expires, checksum, 1, bytes(ipfs_hash, 'utf-8'), True).buildTransaction({ 'chainId': mode.CHAIN_ID, 'gas': 1000000, 'gasPrice': mode.w3.toWei( mode.GASPRICE, 'gwei'), 'nonce': nonce, }) signed_txn = mode.w3.eth.account.signTransaction(txn, private_key_from) mode.w3.eth.sendRawTransaction(signed_txn.rawTransaction) transaction_hash = mode.w3.toHex(mode.w3.keccak(signed_txn.rawTransaction)) if synchronous: if not mode.w3.eth.waitForTransactionReceipt( transaction_hash, timeout=2000, poll_latency=1)['status']: logging.error('transaction to create document failed') return None, None, None # Get document id on last event contract = mode.w3.eth.contract(workspace_contract_to, abi=constante.workspace_ABI) from_block = mode.w3.eth.blockNumber - 10 myfilter = contract.events.DocumentAdded.createFilter( fromBlock=from_block, toBlock='latest') eventlist = myfilter.get_all_entries() document_id = eventlist[-1]['args']['id'] return document_id, ipfs_hash, transaction_hash else: return None, None, None
def test_register_invalid_algorithms(self): self.assertRaises(ValueError, JsonWebEncryption, ['INVALID']) jwe = JsonWebEncryption(algorithms=[]) self.assertRaises(ValueError, jwe.register_algorithm, JWS_ALGORITHMS[0])
def test_ase_gcm_jwe_invalid_key(self): jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) protected = {'alg': 'A128GCMKW', 'enc': 'A128GCM'} self.assertRaises(ValueError, jwe.serialize_compact, protected, b'hello', b'invalid-key')
def jweRsaEncryptToBase64UrlToken(rsaPublicKey, jweKeyAlgorithm, jweEncryptionAlgorithm, jwePayloadObject): jwe = JsonWebEncryption() jweHeaderObject = buildHeaderObject(jweKeyAlgorithm, jweEncryptionAlgorithm) return jwe.serialize_compact(jweHeaderObject, json.dumps(jwePayloadObject), rsaPublicKey)
def _get(workspace_contract_from, private_key_from, workspace_contract_user, documentId, mode): # @documentID is int if not isinstance(documentId, int): documentId = int(documentId) logging.error('doc_id must be int') w3 = mode.w3 contract = w3.eth.contract(workspace_contract_user, abi=constante.workspace_ABI) #try : (doctype, doctypeversion, unused, issuer, unused, unused, ipfshash, unused, unused) = contract.functions.getDocument(documentId).call() #except : # logging.error('connexion blockchain talaonet impossble, document.py') # return None, None, None, None, None, None, None if doctype in [50000, 40000, 10000, 15000, 20000, 11000]: privacy = 'public' if doctype in [50001, 40001, 15001, 20001]: privacy = 'private' if doctype in [50002, 40002, 20002]: privacy = 'secret' workspace_contract_identity = workspace_contract_user # download from IPFS ipfs_data = Talao_ipfs.ipfs_get(ipfshash.decode('utf-8')) # previous version (deprecated) if privacy == 'public' and doctypeversion == 2: return issuer, workspace_contract_identity, ipfs_data, ipfshash.decode( ), privacy, "", 0 # data encrypted server side with AES algo and server keys (public, private, secret) elif doctypeversion == 3: msg = privatekey.decrypt_data(workspace_contract_user, ipfs_data, privacy, mode) if msg: # decrypt avec algo AES-EAX ou AES-CBC return issuer, workspace_contract_user, msg, ipfshash.decode( 'utf-8'), privacy, "", 0 else: # la clé RSA n'est pas disponible sur le serveur logging.warning('Cannot decrypt data') return issuer, workspace_contract_user, { "data": 'Encrypted' }, ipfshash.decode('utf-8'), privacy, "", 0 # data encrypted server side as JWE with RSA identity key elif doctypeversion == 4: jwe = JsonWebEncryption() address_user = contracts_to_owners(workspace_contract_user, mode) key = privatekey.get_key(address_user, 'rsa_key', mode) data = jwe.deserialize_compact(ipfs_data['jwe'], key) payload = data['payload'] return issuer, workspace_contract_user, payload.decode( ), ipfshash.decode(), privacy, "", 0 # data encrypted server side as JWE with AES key elif doctypeversion == 5: jwe = JsonWebEncryption() address_user = contracts_to_owners(workspace_contract_user, mode) if privacy == 'public': secret = mode.aes_public_key.encode() else: secret = privatekey.get_key(address_user, privacy, mode) data = jwe.deserialize_compact(ipfs_data['jwe'], secret) payload = data['payload'] return issuer, workspace_contract_user, payload.decode( ), ipfshash.decode(), privacy, ipfs_data['id'], ipfs_data['sequence'] # data encrypted client side as JWE. There is no server decryption. elif doctypeversion == 6: return issuer, workspace_contract_user, ipfs_data[ 'jwe'], ipfshash.decode(), privacy, "", 0 else: logging.error('pb doctypeversion') return None, None, None, None, None, None, None
def jweRsaDecryptFromBase64UrlToken(rsaPrivateKey, jweTokenBase64Url): jwe = JsonWebEncryption() return jwe.deserialize_compact(jweTokenBase64Url, rsaPrivateKey)
def test_not_enough_segments(self): s = 'a.b.c' jwe = JsonWebEncryption(algorithms=JWE_ALGORITHMS) self.assertRaises(errors.DecodeError, jwe.deserialize_compact, s, None)