async def submit_conclude_secret(app, requester_address, share_secret_state, zeroth_priv, private_key): """ Args: share_secret_address: desrialize share_secret transaction data on share_secret address created from the random index for the user """ acc_signer = create_signer(zeroth_priv) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(private_key, nonce) user_signed_nonce = ecdsa_signature(zeroth_priv, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() ##ON the processor side, signed_nonce will be checked against admin account ##public key ##this is required as this will add to the confidence that this tramsaction ##was signed by the database owners or The ADMIN transaction_data = { "user_address": requester_address, "share_secret_address": share_secret_state["address"], "active": False, "timestamp": indian_time_stamp(), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, "user_signed_nonce": user_signed_nonce, } ##transaction["address"] is actually an address of the shared_secret_transaction inputs = [requester_address, share_secret_state["address"]] outputs = [share_secret_state["address"]] payload = payload_pb2.CreateConcludeSecret(**transaction_data) instance = await SendConcludeSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.create_conclude_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, }) logger.info(transaction_data) return transaction_data
async def submit_admin_account(app, user): acc_signer= encryption_utils.create_signer(app.config.ADMIN_ZERO_PRIV) transaction_data= {"config": app.config, "txn_key": acc_signer, "batch_key": app.config.SIGNER, "org_name": user["org_name"], #float_account address "user_id": user["user_id"], "pancard": hashlib.\ sha512(app.config.ADMIN_PANCARD.encode())\ .hexdigest(), "gst_number": hashlib.\ sha512(app.config.ADMIN_GST_NUMBER.encode())\ .hexdigest(), "tan_number": hashlib.\ sha512(app.config.ADMIN_TAN_NUMBER.encode())\ .hexdigest(), "phone_number": hashlib.\ sha512(user["phone_number"].encode())\ .hexdigest(), "email": user["email"], "time": int(time.time()), "indian_time": route_utils.indian_time_stamp(), "role": user["role"], "create_asset_idxs": [], "deactivate": False, "deactivate_on": None, } transaction_ids, batch_id = await __send_organization_account(**transaction_data) logging.info(batch_id) if batch_id: user.update({ "transaction_id": transaction_ids[0], "batch_id": batch_id, "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], }) result = await accounts_query.insert_account(app, user) logging.info(result) return True return
async def submit_receive_secret(app, requester_user_id, requester_state, requester_address, requester_mnemonic): """ Args: requester_state(str): The user state present on the blockchain who wants to create a new receive secret address requester_mnemonic: decrypted mnemonic of the user """ index = await generate_key_index(requester_state.get("receive_secret_idxs") ) logging.info(index) nth_keys = await remote_calls.key_index_keys(app, requester_mnemonic, [index, 0]) nth_priv, nth_pub = nth_keys[str(index)]["private_key"], \ nth_keys[str(index)]["public_key"] zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] ##to prove that this receive_secret has been created by the user himself, ##nonce must be signed by the zeroth private of the account nonce = random.randint(2**20, 2**30) ## nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(zeroth_priv, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() acc_signer = create_signer(nth_priv) transaction_data = { "role": requester_state["role"], "active": True, "created_on": indian_time_stamp(), "nonce": nonce, "signed_nonce": signed_nonce, "nonce_hash": nonce_hash, "requester_address": requester_address, "idx": index, } receive_secret_address = addresser.receive_secret_address( acc_signer.get_public_key().as_hex(), index) ##both the inputs and outputs addresses will be the same ##requester addresss will be fetched from blockchain and checked if its exists, ##The receive_secret idx will be appended to the array fo account addresses = [requester_address, receive_secret_address] logging.info(f"addresses are {addresses}") payload = payload_pb2.CreateReceiveSecret(**transaction_data) instance = await SendReceiveSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.push_receive_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=addresses, outputs=addresses, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "signed_nonce": signed_nonce.decode() }) db_instance = await DBReceiveSecret(app, app.config.DATABASE["receive_secret"], "receive_secret_idxs") await db_instance.store_receive_secrets(requester_user_id, transaction_data) await db_instance.update_user_receive_secret(requester_user_id, index) return transaction_data
async def submit_execute_share_secret(app, requester, receive_secret_address, shared_secret_state, private, public): """ app(dict): configuration of the whole application requester(dict): database entry of the user who requested this api, i.e who tries to execute a share_Secret transactions shared with him on his receive_secret transaction share_secret_state(dict): Blcokchain state of the share_secret tansaction which will be executed by this user private(hex encoded string): Private key of the requester with whom the receive secret transaction was created, this private was generaed from the idx mentioned in the receive_secret transaction from the requester mnemonic public(hex encoded string): corresponding public of the private Process: share_secret transaction has three keys , key: hex encoded AES key encrypted with the public key of the requester secret: hex encoded shamir secret share encrypted with the AES key mentioned above reset_key: The new hex encoded key generated from the users new_password this is also encrypted with requester public key. Step1: decrypt hex encoded KEY (AES) with private key Step2: decrypt unhexlified secret with AES key from step1. Step3: decrypt unhexlified reset_key with private_key Step4: Encrypt Secret with reset_key """ secret = shared_secret_state[ "secret"] ##encrypted secret with AES key i.e key reset_key = shared_secret_state["reset_key"] ##new aes key which will be #used to encrypt the secret after decryption key = shared_secret_state[ "key"] #THE aes key which was oriniginally used to encrypt secret ##the key is hex encoed but this function will first dehexlify it and then ## decrypt with private key de_org_key = decrypt_w_privkey(key, private) #this orginal AES key de_org_key will be in bytes unhexlified_secret = binascii.unhexlify(secret) ##This is the bare secret which was originally shared with this user de_org_secret = aes_decrypt(de_org_key, unhexlified_secret) ##Now we have to decrypt the new aes key which user has updated as reset_key ##in this contract ##It was also encrypted with the public key of the account address de_reset_key = priv_decrypt(binascii.unhexlify(reset_key), private) ##now encypting orginila share with new reset key ciphertext, tag, nonce = aes_encrypt(de_reset_key, de_org_secret) secret = b"".join([tag, ciphertext, nonce]) ##encrypting the shared mnemonic with users account public key ##the return will also be in bytes i.e encrypted_secret_share #encrypted_secret_share = pub_encrypt(secret_share, account["public"]) #logging.info(encrypted_secret_share) #secret_share = binascii.hexlify(encrypted_secret_share) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(private, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() acc_signer = create_signer(private) transaction_data = { "share_secret_address": shared_secret_state["address"], "reset_secret": binascii.hexlify(secret), "timestamp": indian_time_stamp(), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, } addresses = [shared_secret_state["address"], receive_secret_address] logging.info(f"addresses are {addresses}") payload = payload_pb2.CreateExecuteShareSecret(**transaction_data) instance = await SendExecuteSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, batch_id = await instance.push_receive_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=addresses, outputs=addresses, payload=payload) logging.info(transaction_data) #transaction_ids, batch_id = await __send_execute_share_mnemonic(**transaction_data) """ if transaction_ids: logging.info("Execute share secret Transaction has been created successfully") ##which imlies the transaction has been submitted successfully, ##now all the changes that are required to be done on the databse can ##be done ##Update users create_asset_idxs key on users entry will be updated by ## whomever will call this, because update can happend on pending_users share_asset_address = addresser.share_asset_address( share_asset_pub, key_index) account_signature = account_hex_signature.decode() asset_signature=asset_hex_signature.decode() transaction_data.update({"transaction_id": transaction_ids[0], "batch_id": batch_id, "account_signature": account_signature, "asset_signature": asset_signature, "address": share_asset_address }) [transaction_data.pop(field) for field in ["config", "txn_key", "batch_key"]] await share_assets_query.store_share_asset(app, transaction_data) ##now asset must be update with share_with key await assets_query.update_issuer_asset_shared( app, asset_address, key_index) ##TOFO update receiver_address asset and issuer_asset_Address in DB await accounts_query.update_share_asset_idxs( app, org_state["user_id"], key_index) if child_user_id: await accounts_query.update_share_asset_idxs( app, child_user_id, key_index) return share_asset_address else: return False """ return
async def submit_activate_secret(app, transaction, password): """ Args: transaction: desrialize share_secret transaction data on share_secret address created from the random index for the user """ key, salt = generate_scrypt_key(password, 1, None) ##the encrypted scrypt key will also be in bytes. this is the scrypt key ##which will be encrypted with other users public key, ##The other user will decrypt with their account private key ##and also the secret stored on shasred address, ##now he will encrypt the unencrypted original secret with this new scrypt ##key encrypted_key = pub_encrypt(key, transaction["owner_public"]) acc_signer = create_signer(app.config.ADMIN_ZERO_PRIV) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(app.config.ADMIN_ZERO_PRIV, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() ##ON the processor side, signed_nonce will be checked against admin account ##public key ##this is required as this will add to the confidence that this tramsaction ##was signed by the database owners or The ADMIN admin_address = addresser.organization_address(app.config.ADMIN_ZERO_PUB, 0) transaction_data = { "share_secret_address": transaction["address"], "reset_key": binascii.hexlify(encrypted_key), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, "admin_address": admin_address, "timestamp": indian_time_stamp() } ##transaction["address"] is actually an address of the shared_secret_transaction inputs = [transaction["address"], admin_address] outputs = [transaction["address"], admin_address] payload = payload_pb2.CreateActivateSecret(**transaction_data) instance = await SendActivateSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.create_activate_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "key": binascii.hexlify(key).decode(), "salt": binascii.hexlify(salt).decode(), }) return transaction_data
async def submit_user_account(app, pancard=None, phone_number=None, email=None, role=None, \ password=None, first_name=None, last_name=None): """ org_name is by default None for the user """ if role != "USER": raise errors.CustomError("Roel required is USER") user = await route_utils.new_user_account(app, pancard=pancard, phone_number=phone_number, email=email, role=role, first_name=first_name, last_name=last_name) ##no9w the create account address and signer will be the user himself user_mnemonic, user_account = await route_utils.set_password( app, account=user, password=password) master_pub, master_priv, zero_pub, zero_priv = await \ remote_calls.from_mnemonic(app.config.GOAPI_URL, user_mnemonic) acc_signer = create_signer(zero_priv) ##hashing gst number and tan number if present ##import from ledger.account import float_account, other then create_asset_idxs ## wil be emprty for the float_account, if we push empty list on blockchain ##it wil hsow an error, its better to not to send them at the first place find_hash = lambda x: hashlib.sha512(x.encode()).hexdigest() if x else None transaction_data = { "config": app.config, "txn_key": acc_signer, "batch_key": app.config.SIGNER, "first_name": first_name, "last_name": last_name, "user_id": user_account["user_id"], "pancard": find_hash(pancard), "phone_number": find_hash(phone_number), "email": find_hash(email), "time": int(time.time()), "indian_time": route_utils.indian_time_stamp(), "role": "USER", "deactivate": False, "deactivate_on": None, } transaction_ids, batch_id = await __send_user_account(**transaction_data) logging.info(batch_id) if batch_id: ##if successful, insert this user in pending_users table user_account.update({ "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "transaction_id": transaction_ids[0], "batch_id": batch_id, "role": "USER", "pancard": transaction_data["pancard"], }) logging.debug(user_account) await accounts_query.insert_account(app, user_account) ##update user pending_user with claim, claim_by , claimed_on keys return user_account
async def submit_share_secret(app, requester, requester_address, receive_secret, index, private_key): """ Args: requester(dict): The db entry of the user who wants to share the mnemonic receive_secret(dict): The blockchain state of the receive_secret addr to whom this user wants to share the mnemonic {'role': 'USER', 'active': True, 'created_on': '2018-12-28 19:59:14 IST+0530', 'nonce': 802584806, 'signed_nonce': '304402204b79ebf02b7.........', 'nonce_hash': '87b4e684b071956e5598b.........', 'idx': 1044988318, 'public': '026f914d49e6321f668139e75.........', 'address': 'a9d5c23e49419e21d9f5a2ef.........', "salt": "secret": the part of the mnemonic share shared with this receive_secret} address is added by deserialize_receive_secret function secret_share (str): One share of the encrypted mnemonic of the user out of many others which will be shared with the user represented by account. index(int): ranom index generated from the user mnemonic at which a new shared_mnemonic address will be generated at which this share of the mnemonic will be stored after encrypting it with a random AES key and encrypting AES key with the public key of the user represented but the account. private_key(str): private key of the requested generated from its mnemonic present at the index. """ acc_signer = create_signer(private_key) ##encrypting the shared mnemonic with users account public key ##the return will also be in bytes i.e encrypted_secret_share #encrypted_secret_share = pub_encrypt(secret_share, account["public"]) #logging.info(encrypted_secret_share) #secret_share = binascii.hexlify(encrypted_secret_share) key = generate_aes_key(16) ##this is in bytes ciphertext, tag, nonce = aes_encrypt(key, receive_secret["secret"]) ciphertext = b"".join([tag, ciphertext, nonce]) ##The AES_GCM encrypted file content encryptes_secret_share = binascii.hexlify(ciphertext).decode() ##Encrypting AES key with the public key present at the receive_secret transaction, ##output will ne hex encoded encryted AES key encrypted_key = encrypt_w_pubkey(key, receive_secret["public"]) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(requester["zeroth_private"], nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() transaction_data = { "ownership": receive_secret["address"], "active": False, "secret": encryptes_secret_share, "key": encrypted_key, "secret_hash": hashlib.sha512(receive_secret["secret"]).hexdigest(), "role": "USER", "idx": index, "created_on": route_utils.indian_time_stamp(), "nonce": nonce, "signed_nonce": signed_nonce, "nonce_hash": nonce_hash, "user_address": requester_address #because at the processing side ##user state needs to be appended with ##shared_asecret_address on their share_secret_addresses } share_secret_address = addresser.shared_secret_address( acc_signer.get_public_key().as_hex(), index) ##both the inputs and outputs addresses will be the same ##requester addresss will be fetched from blockchain and checked if its exists ##and the shared_secret_addresses will be appended to its inputs = [ requester_address, share_secret_address, receive_secret["address"] ] outputs = [requester_address, share_secret_address] payload = payload_pb2.CreateShareSecret(**transaction_data) instance = await SendTransactions(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.share_mnemonic_transaction( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "share_secret_address": share_secret_address, "signed_nonce": signed_nonce.decode(), "public": acc_signer.get_public_key().as_hex() }) return transaction_data
async def submit_organization_account(app, user): """ """ ##no9w the create account address and signer will be the user himself master_pub, master_priv, zero_pub, zero_priv = await \ remote_calls.from_mnemonic(app.config.GOAPI_URL, user["mnemonic"]) if user["acc_zero_pub"] != zero_pub: raise Exception("wrong mnemonic for user, Key mismatch error") acc_signer=encryption_utils.create_signer(zero_priv) ##hashing gst number and tan number if present ##fecth float account details from the blokchchain, because it might be a possibility ##that there are several create_asset transaction in pipeline, and the user ## now start the procedute to claim the acccount, Now if we fetch pending user ## rom db rather then blokchcain then flt_acc_idxs will differ flt_acc_address = addresser.float_account_address( user["parent_pub"], user["parent_idx"]) flt_account = await deserialize_state.deserialize_float_account( app.config.REST_API_URL, flt_acc_address) ##import from ledger.account import float_account, other then create_asset_idxs ## wil be emprty for the float_account, if we push empty list on blockchain ##it wil hsow an error, its better to not to send them at the first place transaction_data= {"config": app.config, "txn_key": acc_signer, "batch_key": app.config.SIGNER, "org_name": user["org_name"], "parent_pub": user["parent_pub"], #required to find #float_account address "user_id": user["user_id"], "pancard": hashlib.\ sha512(user["pancard"].encode())\ .hexdigest(), "gst_number": hashlib.\ sha512(user["gst_number"].encode())\ .hexdigest(), "tan_number": hashlib.\ sha512(user["tan_number"].encode())\ .hexdigest(), "phone_number": hashlib.\ sha512(user["phone_number"].encode())\ .hexdigest(), "email": user["email"], "time": int(time.time()), "indian_time": upload_utils.indian_time_stamp(), "parent_zero_pub": user["parent_zero_pub"], "parent_role": user["parent_role"], "role": user["role"], "create_asset_idxs": flt_account.get("create_asset_idxs"), "deactivate": False, "deactivate_on": None, "parent_idx": user["parent_idx"], "float_account_address": flt_acc_address, } transaction_ids, batch_id = await __send_organization_account(**transaction_data) logging.info(batch_id) if batch_id: logging.debug(user) ##if successful, insert this user in pending_users table user.update({ "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "transaction_id": transaction_ids[0], "batch_id": batch_id, "create_asset_idxs": flt_account.get("create_asset_idxs"), "type": "ORGANIZATION"}) user.pop("mnemonic") logging.debug(user) await accounts_query.insert_account(app, user) ##update user pending_user with claim, claim_by , claimed_on keys await accounts_query.claim_account(app, user["user_id"], user["email"], user["phone_number"], user["indian_time"]) ##return new user data whose float_account has just been created return user