def create_claim(address_from,workspace_contract_from, address_to, workspace_contract_to,private_key_from, topicname, data, privacy, mode) : """ main reate claim function @data = str @topicname is credential id @privacy is public/private/secret scheme 2 """ # calculate claim_id derived from credential "id" (topicname) topicvalue = topicname2topicvalue(topicname) claim_id = mode.w3.solidityKeccak(['address', 'uint256'], [address_from, topicvalue]).hex() # encrypt data data_encrypted = encrypt_data(workspace_contract_to, {topicname : data}, privacy, mode, address_caller=address_from) if not data_encrypted : logging.warning('data encryption failed') return None # store on IPFS ipfs_hash = Talao_ipfs.ipfs_add(data_encrypted, mode) if not ipfs_hash : logging.error('ipfs failed') return None # fire transaction nonce = mode.w3.eth.getTransactionCount(address_from) contract = mode.w3.eth.contract(workspace_contract_to,abi=constante.workspace_ABI) txn = contract.functions.addClaim(topicvalue, 2, address_from, b'signature', privacy.encode(), ipfs_hash ).buildTransaction({'chainId': mode.CHAIN_ID,'gas': 4000000,'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 not mode.w3.eth.waitForTransactionReceipt(transaction_hash, timeout=2000, poll_latency=1)['status'] logging.error('transaction failed') return None return claim_id
def _get_claim(workspace_contract_from, identity_workspace_contract, claim_id, mode) : """ Internal function to access claim data """ w3 = mode.w3 contract = w3.eth.contract(identity_workspace_contract, abi=constante.workspace_ABI) claim = contract.functions.getClaim(claim_id).call() privacy = claim[4].decode() ipfs_hash = claim[5] issuer = claim[2] scheme = claim[1] topic_value = claim[0] data_encrypted = Talao_ipfs.ipfs_get(ipfs_hash) address_from = contracts_to_owners(workspace_contract_from, mode) msg = decrypt_data(identity_workspace_contract, data_encrypted, privacy, mode, address_caller=address_from) if msg : data = list(msg.values())[0] else : logging.error('decrypt claim failed') return None return issuer, identity_workspace_contract, data, ipfs_hash, scheme, claim_id, privacy, topic_value
def _get_claim(workspace_contract_from, private_key_from, identity_workspace_contract, claim_id, mode): """ Internal function to access claim data """ w3 = mode.w3 contract = w3.eth.contract(identity_workspace_contract, abi=constante.workspace_ABI) claim = contract.functions.getClaim(claim_id).call() data = claim[4].decode('utf-8') # privacy ipfs_hash = claim[5] issuer = claim[2] scheme = claim[1] topic_value = claim[0] #topicname = topicvalue2topicname(topic_value) if data != 'private' and data != 'secret' and data != 'public': # compatiblité avec version precedente. data public non cryptee to_be_decrypted = False privacy = 'public' else: # toutes les datas sont encryptees to_be_decrypted = True privacy = data if to_be_decrypted: # upload data encrypted from ipfs data_encrypted = Talao_ipfs.ipfs_get(ipfs_hash) address_from = contracts_to_owners(workspace_contract_from, mode) msg = privatekey.decrypt_data(identity_workspace_contract, data_encrypted, privacy, mode, address_caller=address_from) if msg: #data= msg[topicname] data = list(msg.values())[0] else: logging.error('decrypt claim failed') data = None gas_used = 1000 created = "" gas_price = 1 transaction_hash = "0" return issuer, identity_workspace_contract, data, ipfs_hash, gas_price * gas_used, transaction_hash, scheme, claim_id, privacy, topic_value, created
def add_file(address_from, workspace_contract_from, address_to, workspace_contract_to, private_key_from, doctype, file_name, mydays, privacy, mode, synchronous): w3 = mode.w3 file_path = mode.uploads_path + file_name try: this_file = open(file_path, mode='rb') # b is important -> binary except IOError: logging.error('Error : IOEroor open file in File.py') return None, None, None this_data = this_file.read() data = { 'filename': file_name, 'content': b64encode(this_data).decode('utf_8') } # cryptage des données par le user if privacy != 'public': """ contract = w3.eth.contract(workspace_contract_to,abi = constante.workspace_ABI) mydata = contract.functions.identityInformation().call() """ if privacy == 'private': my_aes = privatekey.get_key(address_to, 'aes_key', mode) if privacy == 'secret': my_aes = privatekey(address_to, 'secret_key', mode) if my_aes is None: return None, None, None # coder les datas bytesdatajson = bytes(json.dumps(data), 'utf-8') # dict -> json(str) -> bytes header = b'header' cipher = AES.new( my_aes, AES.MODE_EAX ) #https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html cipher.update(header) ciphertext, tag = cipher.encrypt_and_digest(bytesdatajson) json_k = ['nonce', 'header', 'ciphertext', 'tag'] json_v = [ b64encode(x).decode('utf-8') for x in [cipher.nonce, header, ciphertext, tag] ] data = dict(zip(json_k, json_v)) data['filename'] = file_name # calcul de la date if mydays == 0: expires = 0 else: myexpires = datetime.utcnow() + datetime.timedelta(days=mydays, seconds=0) expires = int(myexpires.timestamp()) #envoyer la transaction sur le contrat contract = w3.eth.contract(workspace_contract_to, abi=constante.workspace_ABI) nonce = w3.eth.getTransactionCount(address_from) # stocke sur ipfs les data attention on archive des bytes ipfs_hash = Talao_ipfs.ipfs_add(data, mode) # calcul du checksum en bytes des data, conversion du dictionnaire data en chaine str #_data = json.dumps(data) #checksum = hashlib.md5(bytes(_data, 'utf-8')).hexdigest() # la conversion inverse de bytes(data, 'utf-8') est XXX.decode('utf-8') checksum = b'' encrypted = False if privacy == 'public' else True # Transaction txn = contract.functions.createDocument(doctype, 2, expires, checksum, 1, bytes(ipfs_hash, 'utf-8'), encrypted).buildTransaction({ 'chainId': mode.CHAIN_ID, 'gas': 500000, 'gasPrice': w3.toWei( mode.GASPRICE, 'gwei'), 'nonce': nonce, }) signed_txn = w3.eth.account.signTransaction(txn, private_key_from) w3.eth.sendRawTransaction(signed_txn.rawTransaction) transaction_hash = w3.toHex(w3.keccak(signed_txn.rawTransaction)) if synchronous == True: receipt = w3.eth.waitForTransactionReceipt(transaction_hash, timeout=2000, poll_latency=1) if receipt['status'] == 0: return None, None, None # recuperer l iD du document sur le dernier event DocumentAdded contract = w3.eth.contract(workspace_contract_to, abi=constante.workspace_ABI) myfilter = contract.events.DocumentAdded.createFilter( fromBlock=mode.fromBlock, toBlock='latest') eventlist = myfilter.get_all_entries() document_id = eventlist[-1]['args']['id'] return document_id, ipfs_hash, transaction_hash
def get_file(workspace_contract_from, private_key_from, workspace_contract_user, documentId, new_filename, mode): w3 = mode.w3 contract = w3.eth.contract(workspace_contract_user, abi=constante.workspace_ABI) (doctype, doctypeversion, expires, issuer, checksum, engine, ipfshash, encrypted, related) = contract.functions.getDocument(documentId).call() if doctype == 30000: privacy = 'public' elif doctype == 30001: privacy = 'private' elif doctype == 30002: privacy = 'secret' else: logging.error('Error : wrong doctype in get file') return None # get transaction info contract = w3.eth.contract(workspace_contract_user, abi=constante.workspace_ABI) claim_filter = contract.events.DocumentAdded.createFilter( fromBlock=mode.fromBlock, toBlock='latest') event_list = claim_filter.get_all_entries() found = False for doc in event_list: if doc['args']['id'] == documentId: found = True transactionhash = doc['transactionHash'] transaction_hash = transactionhash.hex() transaction = w3.eth.getTransaction(transaction_hash) gas_price = transaction['gasPrice'] identity_workspace_contract = transaction['to'] block_number = transaction['blockNumber'] block = mode.w3.eth.getBlock(block_number) date = datetime.fromtimestamp(block['timestamp']) #gas_used = w3.eth.getTransactionReceipt(transaction_hash).gasUsed gas_used = 1000 created = str(date) break if not found: logging.error('Error : event list in get_file') return None # recuperation du msg data = Talao_ipfs.ipfs_get(ipfshash.decode('utf-8')) filename = data['filename'] # calcul de la date expires = 'Unlimited' if expires == 0 else str( datetime.fromtimestamp(expires)) if privacy == 'public': to_be_decrypted = False to_be_stored = True elif workspace_contract_from != workspace_contract_user and privacy == 'private' and private_key_from is not None: #recuperer les cle AES cryptée du user sur son partnership de l identité contract = w3.eth.contract(workspace_contract_from, abi=constante.workspace_ABI) acct = Account.from_key(private_key_from) mode.w3.eth.defaultAccount = acct.address partnership_data = contract.functions.getPartnership( workspace_contract_user).call() # one tests if the user in in partnershipg with identity (pending or authorized) if partnership_data[1] in [1, 2] and partnership_data[4] != b'': his_aes_encrypted = partnership_data[4] to_be_decrypted = True to_be_stored = True else: to_be_decrypted = False to_be_stored = False data = {'filename': filename, 'content': "Encrypted"} elif workspace_contract_from == workspace_contract_user: #recuperer les cle AES cryptée dans l identité contract = w3.eth.contract(workspace_contract_user, abi=constante.workspace_ABI) mydata = contract.functions.identityInformation().call() if privacy == 'private': his_aes_encrypted = mydata[5] if privacy == 'secret': his_aes_encrypted = mydata[6] to_be_decrypted = True to_be_stored = True else: # workspace_contract_from != wokspace_contract_user and privacy == secret or private_key_from is None: to_be_decrypted = False to_be_stored = False logging.error( 'Warning : workspace_contract_from != wokspace_contract_user and privacy == secret or private_key_from is None (file.py)' ) data = {'filename': filename, 'content': "Encrypted"} if to_be_decrypted: # read la cle RSA privee sur le fichier de l identité contract = mode.w3.eth.contract(mode.foundation_contract, abi=constante.foundation_ABI) address_from = contract.functions.contractsToOwners( workspace_contract_from).call() rsa_key = privatekey.get_key(address_from, 'rsa_key', mode) if rsa_key is None: logging.error('Warning : RSA key not found in file.py') return None # decoder la cle AES cryptée avec la cle RSA privée key = RSA.importKey(rsa_key) cipher = PKCS1_OAEP.new(key) his_aes = cipher.decrypt(his_aes_encrypted) # decoder les datas try: del data['filename'] b64 = data #json.loads(json_input) json_k = ['nonce', 'header', 'ciphertext', 'tag'] jv = {k: b64decode(b64[k]) for k in json_k} cipher = AES.new(his_aes, AES.MODE_EAX, nonce=jv['nonce']) cipher.update(jv['header']) plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag']) msg = json.loads(plaintext.decode('utf-8')) data = msg except ValueError: logging.error("Error : data Decryption error") return None new_filename = filename if new_filename == "" else new_filename if to_be_stored: new_file = open(mode.uploads_path + new_filename, "wb") new_file.write(b64decode(data['content'])) new_file.close() return issuer, identity_workspace_contract, data, ipfshash.decode( 'utf-8' ), gas_price * gas_used, transaction_hash, doctype, doctypeversion, created, expires, issuer, privacy, related
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 _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 __init__(self, workspace_contract, mode, authenticated=False, workspace_contract_from=None, private_key_from=None): self.workspace_contract = workspace_contract category = get_category(self.workspace_contract, mode) if category == 2001: # company self.type = "company" if category == 1001: # person self.type = "person" self.authenticated = authenticated self.did = 'did:talao:' + mode.BLOCKCHAIN + ':' + self.workspace_contract[ 2:] self.address = contractsToOwners(self.workspace_contract, mode) self.get_all_documents(mode) self.get_issuer_keys(mode) self.get_identity_skills(mode) self.get_identity_certificate(mode) self.get_identity_private_certificate(mode) self.get_identity_secret_certificate(mode) self.has_vault_access = has_vault_access(self.address, mode) if self.authenticated: self.has_relay_private_key(mode) if self.private_key: self.get_partners(mode) else: self.partners = [] self.has_relay_rsa_key(mode) if self.rsa_key: self.get_secret(mode) # get aes and secret keys else: self.secret = 'Encrypted' self.aes = 'Encrypted' self.eth = mode.w3.eth.getBalance( self.address) / 1000000000000000000 self.token = token_balance(self.address, mode) self.is_relay_activated(mode) self.get_identity_personal(self.workspace_contract, self.private_key_value, mode) self.get_identity_file(self.workspace_contract, self.private_key_value, mode) else: self.partners = [] self.private_key = False self.rsa_key = False self.relay_activated = False address_from = contractsToOwners(workspace_contract_from, mode) private_key_from = privatekey.get_key(address_from, 'private_key', mode) self.get_identity_file(workspace_contract_from, private_key_from, mode) self.get_identity_personal(workspace_contract_from, private_key_from, mode) if self.type == "company": self.name = self.personal['name']['claim_value'] else: # self.type == "person" : self.profil_title = self.personal['profil_title']['claim_value'] self.name = self.personal['firstname'][ 'claim_value'] + ' ' + self.personal['lastname']['claim_value'] personal = json.loads( ns.get_personal(self.workspace_contract, mode)) self.experience = personal.get('experience_claims', []) self.education = personal.get('education_claims', []) #get image/logo and signature ipfs and download files to upload folder #self.picture = get_image(self.workspace_contract, 'picture', mode) self.picture = self.personal['picture'] if not self.picture: self.picture = 'QmRzXTCn5LyVpdUK9Mc5kTa3VH7qH4mqgFGaSZ3fncEFaq' if self.type == "person" else 'QmXKeAgNZhLibNjYJFHCiXFvGhqsqNV2sJCggzGxnxyhJ5' if not os.path.exists(mode.uploads_path + self.picture): Talao_ipfs.get_picture(self.picture, mode.uploads_path + self.picture) #self.signature = get_image(self.workspace_contract, 'signature', mode) self.signature = self.personal['signature'] if not self.signature: self.signature = 'QmS9TTtjw1Fr5oHkbW8gcU7TnnmDvnFVUxYP9BF36kgV7u' if not os.path.exists(mode.uploads_path + self.signature): Talao_ipfs.get_picture(self.signature, mode.uploads_path + self.signature)