def compute_tx_key(spend_key_private, tx_prefix_hash, salt=None, rand_mult=None): """ :param spend_key_private: :param tx_prefix_hash: :param salt: :param rand_mult: :return: """ if not salt: salt = crypto.random_bytes(32) if not rand_mult: rand_mult_num = crypto.random_scalar() rand_mult = crypto.encodeint(rand_mult_num) else: rand_mult_num = crypto.decodeint(rand_mult) rand_inp = crypto.sc_add(spend_key_private, rand_mult_num) passwd = crypto.keccak_2hash(crypto.encodeint(rand_inp) + tx_prefix_hash) tx_key = crypto.compute_hmac(salt, passwd) # tx_key = crypto.pbkdf2(passwd, salt, count=100) return tx_key, salt, rand_mult
async def save_account(self, file): """ Stores account data :param file: :return: """ if self.wallet_salt is None: self.wallet_salt = crypto.random_bytes(32) # Wallet view key encryption wallet_enc_key = misc.wallet_enc_key(self.wallet_salt, self.wallet_password) ciphertext = chacha_poly.encrypt_pack(wallet_enc_key, crypto.encodeint(self.priv_view)) with open(file, "w") as fh: data = { "view_key_enc": binascii.hexlify(ciphertext).decode("ascii"), "address": self.address.decode("ascii"), "network_type": self.network_type, "wallet_salt": binascii.hexlify(self.wallet_salt).decode("ascii"), "rpc_addr": self.rpc_addr, "wallet_file": self.wallet_file, "monero_bin": self.monero_bin, } json.dump(data, fh, indent=2)
async def init(self, ctx, msg): from apps.monero.controller import wrapper self.ctx = ctx self.creds = await wrapper.monero_get_creds(self.ctx, msg.address_n or (), msg.network_type) self._state_init() self.a = self.creds.view_key_private self.A = self.creds.view_key_public self.b = self.creds.spend_key_private self.B = self.creds.spend_key_public self.key_enc = crypto.random_bytes( 32) # WARNING: potentially dangerous for whole session.
def new_random_wallet(cls, user_entropy=None, network=BitcoinMainNet): """ Generate a new wallet using a randomly generated 512 bit seed. Args: user_entropy: Optional user-supplied entropy which is combined combined with the random seed, to help counteract compromised PRNGs. You are encouraged to add an optional `user_entropy` string to protect against a compromised CSPRNG. This will be combined with the output from the CSPRNG. Note that if you do supply this value it only adds additional entropy and will not be sufficient to recover the random wallet. If you're even saving `user_entropy` at all, you're doing it wrong. """ seed = crypto.random_bytes(64) if user_entropy: user_entropy = str(user_entropy) # allow for int/long seed += user_entropy return cls.from_master_secret(seed, network=network)
async def init(self, ctx, msg: MoneroKeyImageExportInitRequest): self.ctx = ctx await self.derive_creds(msg) confirmation = await self.iface.confirm_ki_sync(msg, ctx=ctx) if not confirmation: return Failure(code=FailureType.ActionCancelled, message="rejected") self.num = msg.num self.hash = msg.hash self.enc_key = crypto.random_bytes(32) # Sub address precomputation if msg.subs and len(msg.subs) > 0: for sub in msg.subs: monero.compute_subaddresses( self.creds, sub.account, sub.minor_indices, self.subaddresses ) return MoneroKeyImageExportInitAck()
async def open_account_file(self, file): """ Opens account file :param file: :return: """ with open(file) as fh: js = json.load(fh) # Wallet key encryption self.wallet_password = await self.prompt_password() self.wallet_salt = common.defvalkey(js, "wallet_salt") if self.wallet_salt is None: self.wallet_salt = crypto.random_bytes(32) else: self.wallet_salt = binascii.unhexlify(self.wallet_salt) # Wallet view key dec. if "view_key" in js: self.priv_view = crypto.b16_to_scalar( js["view_key"].encode("utf8")) elif "view_key_enc" in js: wallet_enc_key = misc.wallet_enc_key(self.wallet_salt, self.wallet_password) plain = chacha_poly.decrypt_pack( wallet_enc_key, binascii.unhexlify(js["view_key_enc"])) self.priv_view = crypto.decodeint(plain) self.address = js["address"].encode("utf8") self.wallet_file = js["wallet_file"] self.monero_bin = js["monero_bin"] self.set_network_type(js["network_type"]) self.rpc_addr = js["rpc_addr"] await self.open_with_keys(self.priv_view, self.address)
async def store_cdata(self, cdata, signed_tx, tx, transfers): """ Stores transaction data for later usage. - cdata.enc_salt1, cdata.enc_salt2, cdata.enc_keys - tx_keys are AEAD protected, key derived from spend key - only token can open. - construction data for further proofs. :param cdata: :param signed_tx: :param tx: :param transfers: :return: """ hash = cdata.tx_prefix_hash prefix = binascii.hexlify(hash[:12]) tx_key_salt = crypto.random_bytes(32) tx_key_inp = hash + crypto.encodeint(self.priv_view) tx_view_key = crypto.pbkdf2(tx_key_inp, tx_key_salt, 2048) unsigned_data = xmrtypes.UnsignedTxSet() unsigned_data.txes = [tx] unsigned_data.transfers = transfers if transfers is not None else [] writer = xmrserialize.MemoryReaderWriter() ar = xmrboost.Archive(writer, True) await ar.root() await ar.message(unsigned_data) unsigned_key = crypto.keccak_2hash(b'unsigned;' + tx_view_key) ciphertext = chacha_poly.encrypt_pack(unsigned_key, bytes(writer.get_buffer())) # Serialize signed transaction writer = xmrserialize.MemoryReaderWriter() ar = xmrserialize.Archive(writer, True) await ar.root() await ar.message(signed_tx) signed_tx_bytes = writer.get_buffer() signed_tx_hmac_key = crypto.keccak_2hash(b'hmac;' + tx_view_key) signed_tx_hmac = crypto.compute_hmac(signed_tx_hmac_key, signed_tx_bytes) try: js = { "time": int(time.time()), "hash": binascii.hexlify(hash).decode("ascii"), "enc_salt1": binascii.hexlify(cdata.enc_salt1).decode("ascii"), "enc_salt2": binascii.hexlify(cdata.enc_salt2).decode("ascii"), "tx_keys": binascii.hexlify(cdata.enc_keys).decode("ascii"), "unsigned_data": binascii.hexlify(ciphertext).decode("ascii"), "tx_salt": binascii.hexlify(tx_key_salt).decode("ascii"), "tx_signed": binascii.hexlify(signed_tx_bytes).decode("ascii"), "tx_signed_hmac": binascii.hexlify(signed_tx_hmac).decode("ascii"), } with open("transaction_%s.json" % prefix.decode("ascii"), "w") as fh: json.dump(js, fh, indent=2) fh.write("\n") except Exception as e: self.trace_logger.log(e) print("Unable to save transaction data for transaction %s" % binascii.hexlify(hash).decode("ascii"))
def create_wallet(self, line): """ Creates a new account :return: """ if self.args.account_file: if os.path.exists(self.args.account_file): logger.error("Wallet file exists, could not overwrite") return print("Generating new wallet...") seed = crypto.random_bytes(32) wl = bip32.Wallet.from_master_secret(seed) seed_bip32_words, seed_bip32_words_indices = wl.to_seed_words() seed_bip32_b58 = wl.serialize_b58() # Generate private keys based on the gen mechanism. Bip44 path + Monero backward compatible data = wl.get_child_for_path("m/44'/128'/0'/0/0") to_hash = data.chain_code + binascii.unhexlify( data.private_key.get_key()) # to_hash is initial seed in the Monero sense, recoverable from this seed hashed = crypto.cn_fast_hash(to_hash) electrum_words = " ".join(mnemonic.mn_encode(hashed)) keys = monero.generate_monero_keys(hashed) spend_sec, spend_pub, view_sec, view_pub = keys print("Seed: 0x%s" % binascii.hexlify(seed).decode("ascii")) print("Seed bip39 words: %s" % " ".join(seed_bip32_words)) print("Seed bip32 b58: %s" % seed_bip32_b58) print("Seed Monero: 0x%s" % binascii.hexlify(hashed).decode("ascii")) print("Seed Monero wrds: %s" % electrum_words) print("") print("Spend key priv: 0x%s" % binascii.hexlify(crypto.encodeint(spend_sec)).decode("ascii")) print("View key priv: 0x%s" % binascii.hexlify(crypto.encodeint(view_sec)).decode("ascii")) print("") print("Spend key pub: 0x%s" % binascii.hexlify(crypto.encodepoint(spend_pub)).decode("ascii")) print("View key pub: 0x%s" % binascii.hexlify(crypto.encodepoint(view_pub)).decode("ascii")) self.init_with_keys(spend_sec, view_sec) print("") print("Address: %s" % self.creds.address.decode("ascii")) self.account_data = collections.OrderedDict() self.account_data["seed"] = binascii.hexlify(seed).decode("ascii") self.account_data["spend_key"] = binascii.hexlify( crypto.encodeint(spend_sec)).decode("ascii") self.account_data["view_key"] = binascii.hexlify( crypto.encodeint(view_sec)).decode("ascii") self.account_data["meta"] = collections.OrderedDict([ ("addr", self.creds.address.decode("ascii")), ("bip44_seed", binascii.hexlify(seed).decode("ascii")), ("bip32_39_words", " ".join(seed_bip32_words)), ("bip32_b58", seed_bip32_b58), ("monero_seed", binascii.hexlify(hashed).decode("ascii")), ("monero_words", electrum_words), ]) if self.args.account_file: with open(self.args.account_file, "w+") as fh: json.dump(self.account_data, fh, indent=2) print("Wallet generated") self.update_prompt()