示例#1
0
def test_imported_privkey(setup_wallets):
    for n in ["mainnet", "testnet"]:
        privkey = "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401"
        jm_single().config.set("BLOCKCHAIN", "network", n)
        password = "******"
        password_key = bitcoin.bin_dbl_sha256(password)
        wifprivkey = bitcoin.wif_compressed_privkey(privkey, get_p2pk_vbyte())
        #mainnet is "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi"
        #to verify use from_wif_privkey and privkey_to_address
        if n == "mainnet":
            iaddr = "1LDsjB43N2NAQ1Vbc2xyHca4iBBciN8iwC"
        else:
            iaddr = "mzjq2E92B3oRB7yDKbwM7XnPaAnKfRERw2"
        privkey_bin = bitcoin.from_wif_privkey(
            wifprivkey, vbyte=get_p2pk_vbyte()).decode('hex')[:-1]
        encrypted_privkey = encryptData(password_key, privkey_bin)
        encrypted_privkey_bad = encryptData(password_key, privkey_bin[:6])
        walletdir = "wallets"
        testwalletname = "test" + n
        pathtowallet = os.path.join(walletdir, testwalletname)
        seed = bitcoin.sha256("\xaa" * 64)[:32]
        encrypted_seed = encryptData(password_key, seed.decode('hex'))
        timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
        for ep in [encrypted_privkey, encrypted_privkey_bad]:
            walletfilejson = {
                'creator':
                'joinmarket project',
                'creation_time':
                timestamp,
                'encrypted_seed':
                encrypted_seed.encode('hex'),
                'network':
                n,
                'index_cache': [[0, 0]] * 5,
                'imported_keys': [{
                    'encrypted_privkey': ep.encode('hex'),
                    'mixdepth': 0
                }]
            }
            walletfile = json.dumps(walletfilejson)
            if not os.path.exists(walletdir):
                os.makedirs(walletdir)
            with open(pathtowallet, "wb") as f:
                f.write(walletfile)
            if ep == encrypted_privkey_bad:
                with pytest.raises(Exception) as e_info:
                    Wallet(testwalletname, password, 5, 6, False, False)
                continue
            newwallet = Wallet(testwalletname, password, 5, 6, False, False)
            assert newwallet.seed == seed
            #test accessing the key from the addr
            assert newwallet.get_key_from_addr(
                iaddr) == bitcoin.from_wif_privkey(wifprivkey,
                                                   vbyte=get_p2pk_vbyte())
            if n == "testnet":
                jm_single().bc_interface.sync_wallet(newwallet)
    load_program_config()
def wallet_generate_recover_bip39(
    method,
    walletspath,
    default_wallet_name,
    callbacks=(cli_display_user_words, cli_user_mnemonic_entry,
               cli_get_wallet_passphrase_check, cli_get_wallet_file_name,
               cli_get_mnemonic_extension)):
    """Optionally provide callbacks:
    0 - display seed
    1 - enter seed (for recovery)
    2 - enter wallet password
    3 - enter wallet file name
    4 - enter mnemonic extension
    The defaults are for terminal entry.
    """
    #using 128 bit entropy, 12 words, mnemonic module
    m = Mnemonic("english")
    if method == "generate":
        mnemonic_extension = callbacks[4]()
        words = m.generate()
        callbacks[0](words, mnemonic_extension)
    elif method == 'recover':
        words, mnemonic_extension = callbacks[1]()
        if not words:
            return False
    entropy = str(m.to_entropy(words))
    password = callbacks[2]()
    if not password:
        return False
    password_key = btc.bin_dbl_sha256(password)
    encrypted_entropy = encryptData(password_key, entropy)
    encrypted_mnemonic_extension = None
    if mnemonic_extension:
        mnemonic_extension = mnemonic_extension.strip()
        #check all ascii printable
        if not all([a > '\x19' and a < '\x7f' for a in mnemonic_extension]):
            return False
        #padding to stop an adversary easily telling how long the mn extension is
        #padding at the start because of how aes blocks are combined
        #checksum in order to tell whether the decryption was successful
        cleartext_length = 79
        padding_length = cleartext_length - 10 - len(mnemonic_extension)
        if padding_length > 0:
            padding = os.urandom(padding_length).replace('\xff', '\xfe')
        else:
            padding = ''
        cleartext = (padding + '\xff' + mnemonic_extension + '\xff' +
                     btc.dbl_sha256(mnemonic_extension)[:8])
        encrypted_mnemonic_extension = encryptData(password_key, cleartext)
    return persist_walletfile(walletspath,
                              default_wallet_name,
                              encrypted_entropy,
                              encrypted_mnemonic_extension,
                              callbacks=(callbacks[3], ))
示例#3
0
def wallet_importprivkey(wallet, mixdepth):
    print('WARNING: This imported key will not be recoverable with your 12 ' +
          'word mnemonic phrase. Make sure you have backups.')
    print('WARNING: Handling of raw ECDSA bitcoin private keys can lead to '
          'non-intuitive behaviour and loss of funds.\n  Recommended instead '
          'is to use the \'sweep\' feature of sendpayment.py ')
    privkeys = raw_input('Enter private key(s) to import: ')
    privkeys = privkeys.split(',') if ',' in privkeys else privkeys.split()
    # TODO read also one key for each line
    for privkey in privkeys:
        # TODO is there any point in only accepting wif format? check what
        # other wallets do
        privkey_bin = btc.from_wif_privkey(privkey,
                                        vbyte=get_p2pk_vbyte()).decode('hex')[:-1]
        encrypted_privkey = encryptData(wallet.password_key, privkey_bin)
        if 'imported_keys' not in wallet.walletdata:
            wallet.walletdata['imported_keys'] = []
        wallet.walletdata['imported_keys'].append(
            {'encrypted_privkey': encrypted_privkey.encode('hex'),
             'mixdepth': mixdepth})
    if wallet.walletdata['imported_keys']:
        fd = open(wallet.path, 'w')
        fd.write(json.dumps(wallet.walletdata))
        fd.close()
        print('Private key(s) successfully imported')
示例#4
0
def wallet_generate_recover(method, walletspath,
                            default_wallet_name='wallet.json'):
    if jm_single().config.get("POLICY", "segwit") == "true":
        #Here using default callbacks for scripts (not used in Qt)
        return wallet_generate_recover_bip39(method, walletspath,
                                             default_wallet_name)
    if method == 'generate':
        seed = btc.sha256(os.urandom(64))[:32]
        words = mn_encode(seed)
        print('Write down this wallet recovery seed\n\n' + ' '.join(words) +
              '\n')
    elif method == 'recover':
        words = raw_input('Input 12 word recovery seed: ')
        words = words.split()  # default for split is 1 or more whitespace chars
        if len(words) != 12:
            print('ERROR: Recovery seed phrase must be exactly 12 words.')
            return False
        seed = mn_decode(words)
        print(seed)
    password = cli_get_wallet_passphrase_check()
    if not password:
        return False
    password_key = btc.bin_dbl_sha256(password)
    encrypted_seed = encryptData(password_key, seed.decode('hex'))
    return persist_walletfile(walletspath, default_wallet_name, encrypted_seed)
def wallet_generate_recover_bip39(
    method,
    walletspath,
    default_wallet_name,
    callbacks=(cli_user_words, cli_user_words_entry, cli_password_check,
               cli_get_walletname)):
    """Optionally provide callbacks:
    0 - display seed
    1 - enter seed (for recovery)
    2 - enter password
    3 - enter wallet name
    The defaults are for terminal entry.
    """
    #using 128 bit entropy, 12 words, mnemonic module
    m = Mnemonic("english")
    if method == "generate":
        words = m.generate()
        callbacks[0](words)
    elif method == 'recover':
        words = callbacks[1]()
    entropy = str(m.to_entropy(words))
    password, password_key = callbacks[2]()
    if not password:
        return False
    encrypted_entropy = encryptData(password_key, entropy)
    return persist_walletfile(walletspath,
                              default_wallet_name,
                              encrypted_entropy,
                              callbacks=(callbacks[3], ))
示例#6
0
def create_wallet_for_sync(wallet_file, password, wallet_structure, a):
    #Prepare a testnet wallet file for this wallet
    password_key = bitcoin.bin_dbl_sha256(password)
    #We need a distinct seed for each run so as not to step over each other;
    #make it through a deterministic hash
    seedh = bitcoin.sha256("".join([str(x) for x in a]))[:32]
    encrypted_seed = encryptData(password_key, seedh.decode('hex'))
    timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
    walletfilejson = {
        'creator': 'joinmarket project',
        'creation_time': timestamp,
        'encrypted_seed': encrypted_seed.encode('hex'),
        'network': get_network()
    }
    walletfile = json.dumps(walletfilejson)
    if not os.path.exists('wallets'):
        os.makedirs('wallets')
    with open(os.path.join('wallets', wallet_file), "wb") as f:
        f.write(walletfile)
    #The call to Wallet() in make_wallets should now find the file
    #and read from it:
    return make_wallets(1, [wallet_structure],
                        fixed_seeds=[wallet_file],
                        test_wallet=True,
                        passwords=[password])[0]['wallet']
def test_wallet_create(setup_wallets, includecache, wrongnet, storepwd,
                       extendmd, pwdnumtries):
    walletdir, pathtowallet, testwalletname, wallet = create_default_testnet_wallet(
    )
    assert wallet.get_key(
        4, 1,
        17) == "1289ca322f96673acef83f396a9735840e3ab69f0459cf9bfa8d9985a876534401"
    assert wallet.get_addr(2, 0, 5) == "myWPu9QJWHGE79XAmuKkwKgNk8vsr5evpk"
    jm_single().bc_interface.wallet_synced = True
    assert wallet.get_new_addr(1, 0) == "mi88ZgDGPmarzcsU6S437h9CY9BLmgH5M6"
    assert wallet.get_external_addr(3) == "mvChQuChnXVhqvH67wfMxrodPQ7xccdVJU"
    addr3internal = wallet.get_internal_addr(3)
    assert addr3internal == "mv26o79Bauf2miJMoxoSu1vXmfXnk85YPQ"
    assert wallet.get_key_from_addr(
        addr3internal) == "2a283c9a2168a25509e2fb944939637228c50c8b4fecd9024650316c4584246501"
    dummyaddr = "mvw1NazKDRbeNufFANqpYNAANafsMC2zVU"
    assert not wallet.get_key_from_addr(dummyaddr)
    #Make a new Wallet(), and prepare a testnet wallet file for this wallet

    password = "******"
    password_key = bitcoin.bin_dbl_sha256(password)
    seed = bitcoin.sha256("\xaa" * 64)[:32]
    encrypted_seed = encryptData(password_key, seed.decode('hex'))
    timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
    net = get_network() if not wrongnet else 'mainnnet'
    walletfilejson = {'creator': 'joinmarket project',
                      'creation_time': timestamp,
                      'encrypted_seed': encrypted_seed.encode('hex'),
                      'network': net}
    if includecache:
        mmd = wallet.max_mix_depth if not extendmd else wallet.max_mix_depth + 5
        print("using mmd: " + str(mmd))
        walletfilejson.update({'index_cache': [[0, 0]] * mmd})
    walletfile = json.dumps(walletfilejson)
    if not os.path.exists(walletdir):
        os.makedirs(walletdir)
    with open(pathtowallet, "wb") as f:
        f.write(walletfile)
    if wrongnet:
        with pytest.raises(ValueError) as e_info:
            Wallet(testwalletname,
                   password,
                   5,
                   6,
                   extend_mixdepth=extendmd,
                   storepassword=storepwd)
        return
    from string import ascii_letters
    for i in range(
            pwdnumtries):  #multiple tries to ensure pkcs7 error is triggered
        with pytest.raises(WalletError) as e_info:
            wrongpwd = "".join([random.choice(ascii_letters) for _ in range(20)
                               ])
            Wallet(testwalletname,
                   wrongpwd,
                   5,
                   6,
                   extend_mixdepth=extendmd,
                   storepassword=storepwd)

    with pytest.raises(WalletError) as e_info:
        Wallet(testwalletname,
               None,
               5,
               6,
               extend_mixdepth=extendmd,
               storepassword=storepwd)
    newwallet = Wallet(testwalletname,
                       password,
                       5,
                       6,
                       extend_mixdepth=extendmd,
                       storepassword=storepwd)
    assert newwallet.seed == seed
    #now we have a functional wallet + file, update the cache; first try
    #with failed paths
    oldpath = newwallet.path
    newwallet.path = None
    newwallet.update_cache_index()
    newwallet.path = "fake-path-definitely-doesnt-exist"
    newwallet.update_cache_index()
    #with real path
    newwallet.path = oldpath
    newwallet.index = [[1, 1]] * 5
    newwallet.update_cache_index()

    #ensure we cannot find a mainnet wallet from seed
    seed = "goodbye"
    jm_single().config.set("BLOCKCHAIN", "network", "mainnet")
    with pytest.raises(IOError) as e_info:
        Wallet(seed, 5, 6, False, False)
    load_program_config()
def test_wallet_create(setup_wallets, includecache, wrongnet, storepwd,
                       extendmd, pwdnumtries):
    walletdir, pathtowallet, testwalletname, wallet = create_default_testnet_wallet(
    )
    assert wallet.get_key(
        4, 1,
        17) == "96095d7542e4e832c476b9df7e49ca9e5be61ad3bb8c8a3bdd8e141e2f4caf9101"
    assert wallet.get_addr(2, 0, 5) == "2NBUxbEQrGPKrYCV6d4o7Y4AtJ34Uy6gZZg"
    jm_single().bc_interface.wallet_synced = True
    assert wallet.get_new_addr(1, 0) == "2Mz817RE6zqywgkG2h9cATUoiXwnFSxufk2"
    assert wallet.get_external_addr(3) == "2N3gn65WXEzbLnjk5FLDZPc1pL6ebvZAmoA"
    addr3internal = wallet.get_internal_addr(3)
    assert addr3internal == "2N5NMTYogAyrGhDtWBnVQUp1kgwwFzcf7UM"
    assert wallet.get_key_from_addr(
        addr3internal) == "089a7173314d29f99e02a37e36da517ce41537a317c83284db1f33dda0af0cc201"
    dummyaddr = "mvw1NazKDRbeNufFANqpYNAANafsMC2zVU"
    assert not wallet.get_key_from_addr(dummyaddr)
    #Make a new Wallet(), and prepare a testnet wallet file for this wallet

    password = "******"
    password_key = bitcoin.bin_dbl_sha256(password)
    seed = bitcoin.sha256("\xaa" * 64)[:32]
    encrypted_seed = encryptData(password_key, seed.decode('hex'))
    timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
    net = get_network() if not wrongnet else 'mainnnet'
    walletfilejson = {'creator': 'joinmarket project',
                      'creation_time': timestamp,
                      'encrypted_seed': encrypted_seed.encode('hex'),
                      'network': net}
    if includecache:
        mmd = wallet.max_mix_depth if not extendmd else wallet.max_mix_depth + 5
        print("using mmd: " + str(mmd))
        walletfilejson.update({'index_cache': [[0, 0]] * mmd})
    walletfile = json.dumps(walletfilejson)
    if not os.path.exists(walletdir):
        os.makedirs(walletdir)
    with open(pathtowallet, "wb") as f:
        f.write(walletfile)
    if wrongnet:
        with pytest.raises(ValueError) as e_info:
            SegwitWallet(testwalletname,
                   password,
                   5,
                   6,
                   extend_mixdepth=extendmd,
                   storepassword=storepwd)
        return
    from string import ascii_letters
    for i in range(
            pwdnumtries):  #multiple tries to ensure pkcs7 error is triggered
        with pytest.raises(WalletError) as e_info:
            wrongpwd = "".join([random.choice(ascii_letters) for _ in range(20)
                               ])
            SegwitWallet(testwalletname,
                   wrongpwd,
                   5,
                   6,
                   extend_mixdepth=extendmd,
                   storepassword=storepwd)

    with pytest.raises(WalletError) as e_info:
        SegwitWallet(testwalletname,
               None,
               5,
               6,
               extend_mixdepth=extendmd,
               storepassword=storepwd)
    newwallet = SegwitWallet(testwalletname,
                       password,
                       5,
                       6,
                       extend_mixdepth=extendmd,
                       storepassword=storepwd)
    assert newwallet.seed == wallet.wallet_data_to_seed(seed)
    #now we have a functional wallet + file, update the cache; first try
    #with failed paths
    oldpath = newwallet.path
    newwallet.path = None
    newwallet.update_cache_index()
    newwallet.path = "fake-path-definitely-doesnt-exist"
    newwallet.update_cache_index()
    #with real path
    newwallet.path = oldpath
    newwallet.index = [[1, 1]] * 5
    newwallet.update_cache_index()

    #ensure we cannot find a mainnet wallet from seed
    seed = "goodbye"
    jm_single().config.set("BLOCKCHAIN", "network", "mainnet")
    with pytest.raises(IOError) as e_info:
        Wallet(seed, 5, 6, False, False)
    load_program_config()
示例#9
0
           '\n')
 elif method == 'recover':
     words = raw_input('Input 12 word recovery seed: ')
     words = words.split()  # default for split is 1 or more whitespace chars
     if len(words) != 12:
         print('ERROR: Recovery seed phrase must be exactly 12 words.')
         sys.exit(0)
     seed = mn_decode(words)
     print(seed)
 password = getpass.getpass('Enter wallet encryption passphrase: ')
 password2 = getpass.getpass('Reenter wallet encryption passphrase: ')
 if password != password2:
     print('ERROR. Passwords did not match')
     sys.exit(0)
 password_key = btc.bin_dbl_sha256(password)
 encrypted_seed = encryptData(password_key, seed.decode('hex'))
 timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
 walletfile = json.dumps({'creator': 'joinmarket project',
                          'creation_time': timestamp,
                          'encrypted_seed': encrypted_seed.encode('hex'),
                          'network': get_network()})
 walletname = raw_input('Input wallet file name (default: wallet.json): ')
 if len(walletname) == 0:
     walletname = 'wallet.json'
 walletpath = os.path.join('wallets', walletname)
 # Does a wallet with the same name exist?
 if os.path.isfile(walletpath):
     print('ERROR: ' + walletpath + ' already exists. Aborting.')
     sys.exit(0)
 else:
     fd = open(walletpath, 'w')