Exemple #1
0
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
Exemple #2
0
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_receive_asset(app, requester, _id_, name, description,
                               at_which_asset_expires):
    """
    """
    f = await userapis.SolveAccount(requester, app)
    decrypted_mnemonic = f.decrypted_mnemonic
    logging.info(f"THis is the decrypted mnemonic {decrypted_mnemonic}")
    org_db_entry = f.org_db
    receive_asset_idxs = f.org_state.get("receive_asset_idxs")
    child_user_id = f.child_user_id
    child_zero_pub = f.child_zero_pub
    account_zero_pub = f.zero_pub

    key_index = await ledger_utils.generate_key_index(array=receive_asset_idxs)

    nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic,
                                                 [key_index, 0])

    nth_priv, nth_pub = nth_keys[str(key_index)]["private_key"], \
                        nth_keys[str(key_index)]["public_key"]

    org_priv, org_pub = nth_keys[str(0)]["private_key"], \
                        nth_keys[str(0)]["public_key"]

    org_account_address = addresser.create_organization_account_address(
        account_id=account_zero_pub, index=0)

    instance = await userapis.SolveAddress(org_account_address,
                                           app.config.REST_API_URL)
    org_state = instance.data

    ##the transaction will be signed by users nth private key
    create_asset_signer = ledger_utils.create_signer(nth_priv)

    ##we havent included the child_nth_pub in this transaction because it
    ## can be calculated from txn_key on the processor side

    ##for added security we will send a nonce signed by issuer account
    ##private key
    nonce = random.randint(2**20, 2**30)
    nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest()
    ##nonce signed by zerothprivate key and in hex format
    hex_signatures = signatures.ecdsa_signature(org_priv, nonce)

    receive_asset_address = addresser.receive_asset_address(asset_id=nth_pub,
                                                            index=key_index)

    unique_code = int("".join(map(str, random.choices(list(range(1, 10)),
                                                      k=5))))
    unique_code_hash = hashlib.sha224(str(unique_code).encode()).hexdigest()
    encrypted_unique_code = encryption_utils.encrypt_w_pubkey(
        str(unique_code).encode(), nth_pub)
    encrypted_admin_unique_code = encryption_utils.encrypt_w_pubkey(
        str(unique_code).encode(), app.config.ADMIN_ZERO_PUB)

    transaction_data = {
        "config": app.config,
        "txn_key": create_asset_signer,
        "batch_key": app.config.SIGNER,
        "_id_": _id_,
        "time": int(time.time()),
        "indiantime": upload_utils.indian_time_stamp(),
        "idx": key_index,
        "at_which_asset_expires": at_which_asset_expires,
        "org_name": org_state["org_name"],
        "org_address": org_account_address,
        "org_zero_pub": org_pub,
        "org_role": org_state["role"],
        "receive_asset_details": {
            "name": name,
            "description": description
        },
        "child_zero_pub": child_zero_pub,
        "signed_nonce": hex_signatures,
        "nonce": nonce,
        "nonce_hash": nonce_hash,
        "unique_code_hash": unique_code_hash,
        "encrypted_unique_code": encrypted_unique_code,
        "encrypted_admin_unique_code": encrypted_admin_unique_code
    }

    logging.info(f"THis is the transaction data in receive_asset")
    logging.info(pprint(transaction_data))

    transaction_ids, batch_id = await send_receive_asset(**transaction_data)

    if batch_id:
        [
            transaction_data.pop(field)
            for field in ["config", "txn_key", "batch_key"]
        ]
        signed_nonce = transaction_data["signed_nonce"].decode()

        transaction_data.update({
            "user_id": requester["user_id"],
            "public": nth_pub,
            "transaction_id": transaction_ids[0],
            "batch_id": batch_id,
            "signed_nonce": signed_nonce,
            "unique_code": unique_code
        })

        await receive_assets_query.store_receive_assets(app, transaction_data)
        await accounts_query.update_receive_assets_idxs(
            app, org_db_entry["user_id"], key_index)
        ##if this receive_asset is created by child of the organization
        ##then update the child account receive_asset_idxs array also
        if child_user_id:
            await accounts_query.update_receive_assets_idxs(
                app, child_user_id, key_index)

            #await accounts_query.update_create_asst_idxs_pending(app,
            #requester["user_id"], key_index)

        return nth_pub, key_index, receive_asset_address
    else:
        logging.error("Create asset Faied, GO to hell Dude!!!!,\
         Kabhi kabhi lagta hai ki bhagwan hone ka bhi kya fayda")
    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
Exemple #6
0
async def submit_share_asset(app, requester, asset_address,
                             receive_asset_address, unique_code, revoked_on,
                             comments):
    """

        1.check whether asset_address is valid asset address or not
        2. check whether the asset is empty or not
        3.check whether the asset has been transsefred the ownership to someother  empty asset
        4.check whether the requester is the owner of this asset or not
        5.check whether the receiver_asset_address is a valid receive_asset_address or not
        6.check whether at_which_asset_expires is stil valid or hasnt expired
        7.cheque whether the sha_2224 hash of unique code matches with receiver_asset

    """

    f = await userapis.SolveAccount(requester, app)
    decrypted_mnemonic = f.decrypted_mnemonic
    org_state = f.org_state
    logging.info(f"THis is the decrypted mnemonic {decrypted_mnemonic}")
    share_asset_idxs = f.org_state.get("share_asset_idxs")
    child_user_id = f.child_user_id
    child_zero_pub = f.child_zero_pub
    account_zero_pub = f.zero_pub

    unique_code_hash = hashlib.sha224(str(unique_code).encode()).hexdigest()
    if await share_assets_query.find_share_asset(app, asset_address,
                                                 receive_asset_address):
        raise ApiInternalError("This shared asset has already been done")
    ##checking point 5
    receive_asset_instance = await userapis.SolveAddress(
        receive_asset_address, app.config.REST_API_URL)

    if receive_asset_instance.type != "RECEIVE_ASSET":
        raise AssetError("receive_asset_address is notreceive asset address")

    if not receive_asset_instance.data[
            "at_which_asset_expires"] > upload_utils.now_time_stamp():
        raise errors.InvalidValidityPeriod("The time to share asset with this \
                    address has been expired")

    if receive_asset_instance.data["unique_code_hash"] !=\
            unique_code_hash:
        raise AssetError(
            "Unique code provided is either wrong or meant for different receiver_address"
        )

    asset_instance = await userapis.SolveAddress(asset_address,
                                                 app.config.REST_API_URL)
    if asset_instance.type != "CREATE_ASSET":
        raise AssetError("asset_address is not asset address")

    ##check point 2
    if not asset_instance.data["file_name"] or not asset_instance.data[
            "file_hash"]:
        raise AssetError("Empty assets cannot be shared")

    ##decrypting issuer mnemonic

    requester_account_address = addresser.create_organization_account_address(
        account_id=org_state["public"], index=0)

    ##Check if the asset had been transffered to the issuer i.e issets which were
    ###not created by the issuer cant be transffered to other users
    if asset_instance.data.get("ownership_transfer"):
        message = f"This asset which already have been transffered to \
                {issuer_asset.get('ownership_transfer')} can be shared"

        logging.error(message)
        raise AssetError(message)

    key_index = await ledger_utils.generate_key_index(share_asset_idxs)
    logging.info(f"THis is the key index for issuer {key_index}")

    ##at which the asset was created
    asset_index = asset_instance.data["idx"]

    nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic,
                                                 [0, key_index, asset_index])

    ##account kets for the issuer
    requester_zeroth_priv, requester_zeroth_pub = \
                    nth_keys[str(0)]["private_key"], \
                        nth_keys[str(0)]["public_key"]

    ##keys at which teh asset which needs to be shared was floated
    create_asset_priv, create_asset_pub = nth_keys[str(asset_index)]["private_key"], \
                            nth_keys[str(asset_index)]["public_key"]

    ##keys at which the shared asset index will be floated
    share_asset_priv, share_asset_pub = nth_keys[str(key_index)]["private_key"], \
                            nth_keys[str(key_index)]["public_key"]

    ##check if issuer n th public key is exactly the public key mentioned in the
    ##asset transaction present on the blockchain, this also checks whether
    ##the requester is actually the owner of the asset
    if create_asset_pub != asset_instance.data.get("public"):
        logging.error("This asset address is not owned by the issuer")
        raise AssetError("This asset address is not owned by the issuer")

    ##decrypting file data stored ob the issuer asset address, this can be
    ##done by issuer private key present on the nth index
    data = await asset_utils.decrypt_file_data(
        asset_instance.data["key"], asset_instance.data["url"],
        asset_instance.data["file_hash"], create_asset_priv)

    ##TODO: check file_hash
    file_data = {
        "data": data,
        "file_name": asset_instance.data["file_name"],
        "file_hash": asset_instance.data["file_hash"]
    }

    ##encrypting again with the public key present at the receiver_asset_address
    key, encrypted_key, s3_url, encrypted_s3_url = \
        await asset_utils.encrypt_file_data(None, receive_asset_instance.data["public"], app.config,
            file_data)

    logging.info(f"This is the key {key} , encrypted_key{encrypted_key} \
                and the s3_url {s3_url}")
    master_key, master_url = await asset_utils.master_url_n_key(
        app.config.ADMIN_ZERO_PUB, key, s3_url)

    ##Now this transaction should be signed by user

    create_asset_signer = ledger_utils.create_signer(share_asset_priv)

    ##for added security we will send a nonce signed by issuer account
    ##private key
    nonce = random.randint(2**20, 2**30)
    nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest()
    account_hex_signature = signatures.ecdsa_signature(requester_zeroth_priv,
                                                       nonce)

    ##nonce must also be signed with the private key at random index at which
    ##create asset is present
    asset_hex_signature = signatures.ecdsa_signature(create_asset_priv, nonce)

    transaction_data = {
        "config": app.config,
        "txn_key": create_asset_signer,
        "batch_key": app.config.SIGNER,
        "key": encrypted_key,
        "url": encrypted_s3_url,
        "master_key": master_key,
        "master_url": master_url,
        "time": int(time.time()),
        "indiantime": upload_utils.indian_time_stamp(),
        "file_name": asset_instance.data["file_name"],
        "file_hash": asset_instance.data["file_hash"],
        "original_asset_address": asset_address,
        "revoked_on": revoked_on,
        "comments": comments,
        "idx": key_index,
        "account_signature": account_hex_signature,
        "asset_signature": asset_hex_signature,
        "nonce": nonce,
        "nonce_hash": nonce_hash,
        "to_org_name": receive_asset_instance.data["org_name"],
        "to_org_address": receive_asset_instance.data["org_address"],
        "issuer_account_address": requester_account_address,
        "receive_asset_address": receive_asset_address,
        "child_zero_pub": child_zero_pub,
        "unique_code_hash": unique_code_hash,
    }

    transaction_ids, batch_id = await send_share_asset(**transaction_data)

    if transaction_ids:
        logging.info("Share 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_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
Exemple #8
0
async def submit_transfer_asset(app, requester, issuer_address,
                                receiver_address, expired_on):

    ##decrypting issuer mnemonic
    logging.info("Enter into Transfer asset")
    f = await userapis.SolveAccount(requester, app)
    decrypted_mnemonic = f.decrypted_mnemonic

    logging.info(f"Requester Mnemonic is {decrypted_mnemonic}")
    instance = await userapis.SolveAddress(issuer_address,
                                           app.config.REST_API_URL)

    ##getting issuer public key and the index at which this asset was created
    if instance.type != "CREATE_ASSET":
        raise AssetError("Not a valid issuer address")

    issuer_asset = instance.data
    issuer_asset_public_key, issuer_asset_idx = \
                issuer_asset["public"], issuer_asset["idx"]

    instance = await userapis.SolveAddress(receiver_address,
                                           app.config.REST_API_URL)

    if instance.type != "CREATE_ASSET":
        raise AssetError("Not a valid receiver address")
    receiver_asset = instance.data

    logging.info(f"Deserialized receiver asset <<{issuer_asset}>>")

    ##checking is issuer asset is empty or not, empty assets cant be transffered
    if not issuer_asset["file_name"] or not issuer_asset["file_hash"]:
        logging.error("Empty assets cannot be transffered")
        raise AssetError("Empty assets cannot be transffered")

    ##Check if the asset had been transffered to the issuer i.e issets which were
    ###not created by the issuer cant be transffered to other users
    if issuer_asset.get("ownership_received"):
        message = f"This asset is not owned by the user but \
                        received from {issuer_asset['parent_address']}"

        logging.error(message)
        raise AssetError(message)

    ##checking if receiver_asset is empty or not, non empty assets couldnt receive
    ##assets
    if receiver_asset.get("file_name") or receiver_asset.get("file_hash"):
        logging.error("Non empty assets cannot be a receiver")
        raise AssetError("Non empty assets cannot be a receiver")

    ##get issuer keys from the GOAPI_URL, private key corresponding to the
    ##random index public key at which the asset was floated
    issuer_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic,
                                                    [issuer_asset_idx, 0])


    issuer_zeroth_priv, issuer_zeroth_pub = \
                    issuer_keys[str(0)]["private_key"], \
                        issuer_keys[str(0)]["public_key"]


    issuer_nth_priv, issuer_nth_pub = issuer_keys[str(issuer_asset_idx)]["private_key"], \
                            issuer_keys[str(issuer_asset_idx)]["public_key"]

    ##check if issuer n th public key is exactly the public key mentioned in the
    ##asset transaction present on the blockchain, this also checks whether
    ##the requester is actually the owner of the asset
    if issuer_nth_pub != issuer_asset_public_key:
        logging.error("This asset address is not owned by the issuer")
        raise AssetError("This asset address is not owned by the issuer")

    ##decrypting file data stored ob the issuer asset address, this can be
    ##done by issuer private key present on the nth index
    data = await asset_utils.decrypt_file_data(issuer_asset["key"],
                                               issuer_asset["url"],
                                               issuer_asset["file_hash"],
                                               issuer_nth_priv)

    ##TODO: check file_hash
    file_data = {
        "data": data,
        "file_name": issuer_asset["file_name"],
        "file_hash": issuer_asset["file_hash"]
    }

    ##encrypting again with the public key present at the receiver_asset_address
    key, encrypted_key, s3_url, encrypted_s3_url = \
        await asset_utils.encrypt_file_data(None, receiver_asset["public"], app.config,
            file_data)

    logging.info(f"This is the key {key} , encrypted_key{encrypted_key} \
                and the s3_url {s3_url}")
    master_key, master_url = await asset_utils.master_url_n_key(
        app.config.ADMIN_ZERO_PUB, key, s3_url)

    ##Now this transaction should be signed by user

    create_asset_signer = ledger_utils.create_signer(issuer_nth_priv)

    ##for added security we will send a nonce signed by issuer account
    ##private key
    nonce = random.randint(2**20, 2**30)
    ##nonce signed by zerothprivate key and in hex format
    hex_signatures = signatures.ecdsa_signature(issuer_zeroth_priv, nonce)

    transaction_data = {
        "config": app.config,
        "txn_key": create_asset_signer,
        "batch_key": app.config.SIGNER,
        "key": encrypted_key,
        "url": encrypted_s3_url,
        "time": int(time.time()),
        "indiantime": upload_utils.indian_time_stamp(),
        "file_name": issuer_asset["file_name"],
        "file_hash": issuer_asset["file_hash"],
        "expired_on": expired_on,
        "master_key": master_key,
        "master_url": master_url,
        "scope": issuer_asset["scope"],
        "receiver_address": receiver_address,
        "issuer_address": issuer_address,
        "issuer_pub": issuer_nth_pub,
        "issuer_zero_pub": issuer_zeroth_pub,
        "signed_nonce": hex_signatures,
        "nonce": nonce,
        "issuer_child_zero_pub": issuer_asset.get("child_zero_pub"),
    }

    logging.info(transaction_data)
    transaction_ids, batch_id = await send_transfer_asset(**transaction_data)

    if transaction_ids:
        ##just because signatures are in bytes
        signed_nonce = transaction_data["signed_nonce"].decode()
        logging.info("Create 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
        transaction_data.update({
            "transaction_id": transaction_ids[0],
            "batch_id": batch_id,
            "signed_nonce": signed_nonce
        })

        [
            transaction_data.pop(field)
            for field in ["config", "txn_key", "batch_key"]
        ]
        await transfer_assets_query.store_transfer_assets(
            app, transaction_data)
        await assets_query.update_issuer_asset(app, issuer_address,
                                               transaction_data)
        await assets_query.update_receiver_asset(app, receiver_address,
                                                 transaction_data)
        ##TOFO update receiver_address asset and issuer_asset_Address in DB
        return True

    else:
        return False
    return
async def submit_child_account(app, parent_org, child):
    """
    Decrypt parent_org menmonic with the ADMIN private key
    Get orgnization account for parent_org
    Generate a random index at the child_account_idxs array of the
    Get Public/Private key pair at random_indexfrom parent_org mnemonic
    Generate child_address from this pair and index

    Signed nonce with zeroth public key of the parent_org
    """

    decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic(
        app, parent_org["encrypted_admin_mnemonic"], parent_org["role"])

    logging.info(decrypted_mnemonic)

    org_address = addresser.create_organization_account_address(
        parent_org["acc_zero_pub"], 0)

    org_account = await deserialize_state.deserialize_org_account(
        app.config.REST_API_URL, org_address)

    logging.info(org_account)
    ##lets chaeck if the parent user_i

    child_account_idxs = org_account.get("child_account_idxs")

    ##This will generate a new key which doesnt exists in the flt_acc_idxs array
    key_index = await ledger_utils.generate_key_index(child_account_idxs)
    logging.info(f"THis is the key index for parent {key_index}")

    nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic,
                                                 [key_index, 0])


    org_nth_priv, org_nth_pub = nth_keys[str(key_index)]["private_key"], \
                            nth_keys[str(key_index)]["public_key"]

    ##getting zeroth private key to be used later

    org_zeroth_priv, org_zeroth_pub = nth_keys[str(0)]["private_key"], \
                            nth_keys[str(0)]["public_key"]

    ##signer created from the parent key
    signer = upload_utils.create_signer(org_nth_priv)

    ##sending signatures, A nonce signed by zeroth_private_key
    nonce = random.randint(2**20, 2**31)
    nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest()
    hex_signatures = signatures.ecdsa_signature(org_zeroth_priv, nonce)

    ##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": signer,
        "batch_key": app.config.SIGNER,
        "parent_idx": key_index,
        "parent_zero_pub": org_zeroth_pub,
        "parent_role": parent_org["role"],
        "first_name": child["first_name"],
        "last_name": child["last_name"],
        "org_name": child["org_name"],
        "user_id": child["user_id"],
        "pancard": child["pancard"],
        "gst_number": child["gst_number"],
        "tan_number": child["tan_number"],
        "phone_number": child["phone_number"],
        "email": child["email"],
        "time": int(time.time()),
        "indian_time": upload_utils.indian_time_stamp(),
        "role": "CHILD",
        "deactivate": False,
        "deactivate_on": None,
        "nonce": nonce,
        "nonce_hash": nonce_hash,
        "signed_nonce": hex_signatures
    }

    transaction_ids, batch_id = await send_child_account(**transaction_data)

    logging.info(batch_id)
    if batch_id:
        ##if successful, insert this user in pending_users table
        child.update({
            "parent_idx": key_index,
            "public": org_nth_pub,
            "transaction_id": transaction_ids[0],
            "batch_id": batch_id,
            "parent_zero_pub": org_zeroth_pub,
            "parent_role": parent_org["role"],
            "nonce": nonce,
            "nonce_hash": nonce_hash,
            "signed_nonce": hex_signatures.decode(),
            "time": transaction_data["time"],
            "indian_time": transaction_data["indian_time"],
            "role": "CHILD",
            "deactivate": False,
            "deactivate_on": None,
        })

        logging.debug(child)
        await accounts_query.insert_account(app, child)

        ##update child_account_idxs array of the parent_org
        await accounts_query.update_child_account_idxs(app,
                                                       parent_org["user_id"],
                                                       key_index)

    return child
Exemple #10
0
async def submit_float_account(app, requester, user):

    ##retrive float_account from parent

    ## handle if the parent is actually a child account, then the flt_acc_idxs
    ## of the parent must be used

    ##elseif organization is directly creating another org account then its
    ## own flt_account_idxs must be used

    ##a junk entry needs to be sent which is A once signed by the parent orgnisation of the
    ## child or the organization itself zeroth_private_key, which that the float_account is
    ## actually being sent by the concerned authority, otherwise anyone can generate any
    ## random keys and then make a float_transaction because we are not checking any other details
    ## for cros checking


    if requester["role"] == "CHILD":
        ##now find the parent pub of this child to track the parent
        ##organization account
        ##child will get the flt_acc_idxs of the parent organization
        org_address = addresser.create_organization_account_address(
                    requester["parent_zero_pub"], 0)

        org_account = await deserialize_state.deserialize_org_account(
                    app.config.REST_API_URL, org_address)

        logging.info(org_account)
        ##lets chaeck if the parent user_id hash matched with the child parent_id
        if requester["parent_idx"] not in org_account["child_account_idxs"]:
            raise Exception("Child parent_idx not in parent org child_account_idxs")


        if requester["org_name"] != org_account["org_name"]:
            raise Exception("Child org_name is different from  parent")


        ##since child was created from the PUblic key present at parent_idx at the
        ##parent org mnemonic, We need to get that so that we can generated child
        ##adddress, Remember, child_account_addresses generates from parent_org
        ##not with the zeroth key of the child mnemonic

        ##TODO: you can also check whether the child address generated from
        #parent org public key pair at requester parent_idx is same as requester
        ## address
        ##float_account_idxs array of the child's parent organisation

        flt_acc_idxs = org_account.get("float_account_idxs")

        ##now we need to decrypt the parent mnemonic so that we can get the Public/private key
        ##pair corresponding to the the random index
        parent_id = org_account["user_id"]
        logging.info(f"Parent id for the child is {parent_id} and\
            float_account_idxs are {flt_acc_idxs}")

        org_db = await accounts_query.find_on_key(app, "user_id", parent_id)

        logging.info(org_db)
        if org_db["role"] != "ADMIN":
            decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic(
                                app,
                                org_db["encrypted_admin_mnemonic"],
                                org_db["role"])
        else:
            decrypted_mnemonic = app.config.ADMIN_MNEMONIC
        logging.info(decrypted_mnemonic)


        nth_keys = await remote_calls.key_index_keys(app,
                                decrypted_mnemonic, [requester["parent_idx"]])


        nth_priv, nth_pub = nth_keys[str(requester["parent_idx"])]["private_key"], \
                            nth_keys[str(requester["parent_idx"])]["public_key"]


        zero_pub = org_db["acc_zero_pub"]
        parent_role = org_db["role"]
        child_zero_pub = nth_pub

    else: #orgnisation itself is creating this float_account
        logging.info(requester)

        ##float_account_idxs array of the orgnization itself
        flt_acc_idxs = await accounts_query.get_field(app, requester["user_id"],
                "float_account_idxs")
        flt_acc_idxs = flt_acc_idxs.get("float_account_idxs")

        logging.info(f"Float account indxs for the orgnization {flt_acc_idxs}")
        decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic(app,
                                requester["encrypted_admin_mnemonic"],
                                requester["role"])

        logging.info(decrypted_mnemonic)

        zero_pub = requester["acc_zero_pub"]
        parent_role = requester["role"]
        child_zero_pub = None


    logging.info(f"This is the decrypted mnemonic for parent {decrypted_mnemonic}")

    ##This will generate a new key which doesnt exists in the flt_acc_idxs array
    key_index = await ledger_utils.generate_key_index(flt_acc_idxs)
    logging.info(f"THis is the key index for parent {key_index}")

    nth_keys = await remote_calls.key_index_keys(app,
                                        decrypted_mnemonic, [key_index, 0])


    nth_priv, nth_pub = nth_keys[str(key_index)]["private_key"], \
                            nth_keys[str(key_index)]["public_key"]


    ##getting zeroth private key to be used later

    zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], \
                            nth_keys[str(0)]["public_key"]

    flt_acc_address = addresser.float_account_address(nth_pub,
                key_index)

    logging.info(f"This is the flt acc addressfor user {flt_acc_address}")
    logging.info(f"Checking if valid account address has been generated\
                                    {addresser.address_is(flt_acc_address)}")


    ##signer created from the parent key
    flt_acc_signer=upload_utils.create_signer(nth_priv)

    ##sending signatures, A nonce signed by zeroth_private_key
    nonce = random.randint(2**20, 2**31)
    nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest()
    hex_signatures = signatures.ecdsa_signature(zeroth_priv, nonce)


    ##hashing gst number and tan number if present
    if user.get("gst_number"):
        gst_number = hashlib.sha224(user["gst_number"].encode()).hexdigest()
    else:
        gst_number = None

    if user.get("tan_number"):
        tan_number = hashlib.sha224(user["tan_number"]\
                            .encode()).hexdigest()
    else:
        tan_number = None

    ##import from ledger.account import float_account
    transaction_data= {"config": app.config,
                        "txn_key": flt_acc_signer,
                        "batch_key": app.config.SIGNER,
                        "org_name": user["org_name"],
                        "pancard": hashlib.sha224(user["pancard"]\
                                            .encode()).hexdigest(),
                        "gst_number": gst_number,
                        "tan_number": tan_number,
                        "phone_number": user["phone_number"],
                        "email": user["email"],
                        "claimed": False,
                        "claimed_by": None,
                        "create_asset_idxs": [],
                        "parent_pub": nth_pub,
                        "parent_idx": key_index,
                        "time": int(time.time()),
                        "indian_time": upload_utils.indian_time_stamp(),
                        "parent_zero_pub": zero_pub,
                        "parent_role": parent_role,
                        "role": user["role"],
                        "claimed_on": None,
                        "nonce": nonce,
                        "nonce_hash": nonce_hash,
                        "signed_nonce": hex_signatures,
                        "child_zero_pub": child_zero_pub
                        }

    transaction_ids, batch_id = await send_float_account(**transaction_data)

    if batch_id:
        logging.debug(user)
        ##if successful, insert this user in pending_users table
        user.update({"parent_pub": nth_pub,
                    "parent_idx": key_index,
                    "time": transaction_data["time"],
                    "indian_time": transaction_data["indian_time"],
                    "parent_zero_pub": transaction_data["parent_zero_pub"],
                    "parent_role": transaction_data["parent_role"],
                    "transaction_id": transaction_ids[0],
                    "batch_id": batch_id,
                    "child_zero_pub": child_zero_pub,
                    })
        logging.debug(f"User after submitting float_Account trasaction {user}")
        await accounts_query.insert_pending_account(app, user)

    if requester["role"] == "CHILD":
        ##update parent create_flt_idcs array
        await accounts_query.update_flt_acc_idxs(app, org_db["user_id"], key_index)
        ##update float_account_idxs of the child also, so that we would
        ##know which child created which float_account_idxs
        await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index)

    else:
        await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index)

    ##return new user data whose float_account has just been created
    return user