def extractSignedDataFromVersionsDotTxt(wholeFile, doVerify=True): """ This method returns a pair: a dictionary to lookup link by OS, and a formatted string that is sorted by OS, and re-formatted list that will hash the same regardless of original format or ordering """ msgBegin = wholeFile.find('# -----BEGIN-SIGNED-DATA-') msgBegin = wholeFile.find('\n', msgBegin + 1) + 1 msgEnd = wholeFile.find('# -----SIGNATURE---------') sigBegin = wholeFile.find('\n', msgEnd + 1) + 3 sigEnd = wholeFile.find('# -----END-SIGNED-DATA---') MSGRAW = wholeFile[msgBegin:msgEnd] SIGHEX = wholeFile[sigBegin:sigEnd].strip() if -1 in [msgBegin, msgEnd, sigBegin, sigEnd]: LOGERROR('No signed data block found') return '' if doVerify: Pub = SecureBinaryData(hex_to_binary(ARMORY_INFO_SIGN_PUBLICKEY)) Msg = SecureBinaryData(MSGRAW) Sig = SecureBinaryData(hex_to_binary(SIGHEX)) isVerified = CryptoECDSA().VerifyData(Msg, Sig, Pub) if not isVerified: LOGERROR('Signed data block failed verification!') return '' else: LOGINFO('Signature on signed data block is GOOD!') return MSGRAW
def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join(self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join(self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa'*32) self.privKey2 = SecureBinaryData('\x33'*32) self.chainstr = SecureBinaryData('\xee'*32) theIV = SecureBinaryData(hex_to_binary('77'*16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) TheBDM.registerWallet(self.wallet)
def createNewWalletFromWizard(self): entropy = None if self.walletCreationPage.isManualEncryption(): entropy = SecureBinaryData( int_to_binary(self.manualEntropyPage.pageFrame.getEntropy())) else: entropy = self.main.getExtraEntropyForKeyGen() self.newWallet = PyBtcWallet().createNewWallet( securePassphrase=self.setPassphrasePage.pageFrame.getPassphrase(), kdfTargSec=self.walletCreationPage.pageFrame.getKdfSec(), kdfMaxMem=self.walletCreationPage.pageFrame.getKdfBytes(), shortLabel=self.walletCreationPage.pageFrame.getName(), longLabel=self.walletCreationPage.pageFrame.getDescription(), doRegisterWithBDM=False, extraEntropy=entropy, ) self.newWallet.unlock(securePassphrase=SecureBinaryData( self.setPassphrasePage.pageFrame.getPassphrase())) # We always want to fill the address pool, right away. fillPoolProgress = DlgProgress(self, self.main, HBar=1, \ Title="Creating Wallet") fillPoolProgress.exec_(self.newWallet.fillAddressPool, doRegister=False, Progress=fillPoolProgress.UpdateHBar) # Reopening from file helps make sure everything is correct -- don't # let the user use a wallet that triggers errors on reading it wltpath = self.newWallet.walletPath walletFromDisk = PyBtcWallet().readWalletFile(wltpath) self.main.addWalletToApplication(walletFromDisk, walletIsNew=True)
def verifyZipSignature(outerZipFilePath): result = MODULE_ZIP_STATUS.Invalid try: dataToSign = None signature = None outerZipFile = ZipFile(outerZipFilePath) # look for a zip file in the name list. # There should only be 2 files in this zip: # The inner zip file and the sig file if len(outerZipFile.namelist()) == 3: dataToSign = sha256( sha256(outerZipFile.read(INNER_ZIP_FILENAME)) + sha256(outerZipFile.read(PROPERTIES_FILENAME))) signature = outerZipFile.read(SIGNATURE_FILENAME) if dataToSign and signature: """ Signature file contains multiple lines, of the form "key=value\n" The last line is the hex-encoded signature, which is over the source code + everything in the sig file up to the last line. The key-value lines may contain properties such as signature validity times/expiration, contact info of author, etc. """ dataToSignSBD = SecureBinaryData(dataToSign) sigSBD = SecureBinaryData(hex_to_binary(signature.strip())) publicKeySBD = SecureBinaryData( hex_to_binary(ARMORY_INFO_SIGN_PUBLICKEY)) result = MODULE_ZIP_STATUS.Valid if CryptoECDSA().VerifyData(dataToSignSBD, sigSBD, publicKeySBD) else \ MODULE_ZIP_STATUS.Unsigned except: # if anything goes wrong an invalid zip file indicator will get returned pass return result
def buildCorruptWallet(self, walletPath): crpWlt = PyBtcWallet() crpWlt.createNewWallet(walletPath, securePassphrase='testing', doRegisterWithBDM=False) #not registering with the BDM, have to fill the wallet address pool manually crpWlt.fillAddressPool(100) #grab the last computed address lastaddr = crpWlt.addrMap[crpWlt.lastComputedChainAddr160] #corrupt the pubkey PubKey = hex_to_binary( '0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455' ) lastaddr.binPublicKey65 = SecureBinaryData(PubKey) crpWlt.addrMap[crpWlt.lastComputedChainAddr160] = lastaddr crpWlt.fillAddressPool(200) #insert a gap and inconsistent encryption newAddr = PyBtcAddress() newAddr.chaincode = lastaddr.chaincode newAddr.chainIndex = 250 PrivKey = hex_to_binary( 'e3b0c44298fc1c149afbf4c8996fb92427ae41e5978fe51ca495991b7852b855') newAddr.binPrivKey32_Plain = SecureBinaryData(PrivKey) newAddr.binPublicKey65 = CryptoECDSA().ComputePublicKey( \ newAddr.binPrivKey32_Plain) newAddr.addrStr20 = newAddr.binPublicKey65.getHash160() newAddr.isInitialized = True crpWlt.addrMap[newAddr.addrStr20] = newAddr crpWlt.lastComputedChainAddr160 = newAddr.addrStr20 crpWlt.fillAddressPool(250) lastAddr = crpWlt.addrMap[crpWlt.lastComputedChainAddr160] PrivKey = hex_to_binary( 'e3b0c44298fc1c149afbf4c8996fb92427ae41e5978fe51ca495991b00000000') lastAddr.binPrivKey32_Plain = SecureBinaryData(PrivKey) lastAddr.binPublicKey65 = CryptoECDSA().ComputePublicKey( \ lastAddr.binPrivKey32_Plain) lastAddr.keyChanged = True crpWlt.kdfKey = crpWlt.kdf.DeriveKey(SecureBinaryData('testing')) lastAddr.lock(secureKdfOutput=crpWlt.kdfKey) lastAddr.useEncryption = True crpWlt.fillAddressPool(350) #TODO: corrupt a private key #break an address entry at binary level return crpWlt.uniqueIDB58
def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join( self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join( self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa' * 32) self.privKey2 = SecureBinaryData('\x33' * 32) self.chainstr = SecureBinaryData('\xee' * 32) theIV = SecureBinaryData(hex_to_binary('77' * 16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) TheBDM.registerWallet(self.wallet)
def sweepImportedAddrs(masterWallet): setupTheBDM() recipValuePairs = [] utxoList = [] for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: addr160 = importedAddr.getAddr160() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) # get total value totalAvailable = sum([u.getValue() for u in utxoList]) fee = calcMinSuggestedFees(utxoList, totalAvailable, MIN_RELAY_TX_FEE, 1)[1] totalSpend = totalAvailable - fee if totalSpend<0: print '***ERROR: The fees are greater than the funds being swept!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalSpend )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] ustx = UnsignedTransaction().createFromTxOutSelection(utxoList, scrPairs) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signTxDistProposal(ustx) pytx = ustx.getPyTxSignedIfPossible() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print ustx.serializeAscii() return pytx
def createNewWalletFromWizard(self): self.newWallet = PyBtcWallet().createNewWallet( \ securePassphrase=self.setPassphrasePage.pageFrame.getPassphrase(), \ kdfTargSec=self.walletCreationPage.pageFrame.getKdfSec(), \ kdfMaxMem=self.walletCreationPage.pageFrame.getKdfBytes(), \ shortLabel=self.walletCreationPage.pageFrame.getName(), \ longLabel=self.walletCreationPage.pageFrame.getDescription(), \ doRegisterWithBDM=False, \ extraEntropy=self.main.getExtraEntropyForKeyGen()) self.newWallet.unlock(securePassphrase=SecureBinaryData( self.setPassphrasePage.pageFrame.getPassphrase())) # We always want to fill the address pool, right away. fillpool = lambda: self.newWallet.fillAddressPool(doRegister=False) DlgExecLongProcess(fillpool, 'Creating Wallet...', self, self).exec_() # Reopening from file helps make sure everything is correct -- don't # let the user use a wallet that triggers errors on reading it wltpath = self.newWallet.walletPath walletFromDisk = PyBtcWallet().readWalletFile(wltpath) self.main.addWalletToApplication(walletFromDisk, walletIsNew=True) if TheBDM.getBDMState() in ('Uninitialized', 'Offline'): TheBDM.registerWallet(walletFromDisk, isFresh=True, wait=False) else: self.main.newWalletList.append([walletFromDisk, True])
def testVerifyEncryptionKey(self): testAddr = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, publicKey65=PUBLIC_KEY) theIV = SecureBinaryData(hex_to_binary(INIT_VECTOR)) testAddr.enableKeyEncryption(theIV) self.assertFalse(testAddr.verifyEncryptionKey(FAKE_KDF_OUTPUT1)) testAddr.lock(FAKE_KDF_OUTPUT1) self.assertTrue(testAddr.verifyEncryptionKey(FAKE_KDF_OUTPUT1)) self.assertFalse(testAddr.verifyEncryptionKey(FAKE_KDF_OUTPUT2))
def importAddrsToMasterWallet(masterWallet, walletList, addrsPerWallet, masterWalletName): masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) for wallet in walletList: for i in range(addrsPerWallet): addr = wallet.getNextUnusedAddress() masterWallet.importExternalAddressData(privKey = addr.binPrivKey32_Plain, pubKey = addr.binPublicKey65) return masterWallet
def distributeBtc(masterWallet, amount, sendingAddrList): pytx = None setupTheBDM() try: recipValuePairs = [] utxoList = [] for sendingAddr in sendingAddrList: addr160 = sendingAddr.getAddr160() # Make sure the sending addresses are in the masterWallet if not masterWallet.hasAddr(addr160): raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: recipValuePairs.append((importedAddr.getAddr160(),amount)) totalSpend = len(recipValuePairs)*amount fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))[1] # Get the necessary utxo list selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee) # get total value totalAvailable = sum([u.getValue() for u in selectedUtxoList]) totalChange = totalAvailable - (totalSpend + fee) # Make sure there are funds to cover the transaction. if totalChange < 0: print '***ERROR: you are trying to spend more than your balance!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] # we're providing a key map for the inputs. pubKeyMap = {} for utxo in selectedUtxoList: scrType = getTxOutScriptType(utxo.getScript()) if scrType in CPP_TXOUT_STDSINGLESIG: scrAddr = utxo.getRecipientScrAddr() a160 = scrAddr_to_hash160(scrAddr)[1] addrObj = masterWallet.getAddrByHash160(a160) if addrObj: pubKeyMap[scrAddr] = addrObj.binPublicKey65.toBinStr() ustx = UnsignedTransaction().createFromTxOutSelection(selectedUtxoList, scrPairs, pubKeyMap) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signUnsignedTx(ustx) pytx = ustx.getPyTxSignedIfPossible() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print ustx.serializeAscii() finally: TheBDM.beginCleanShutdown() return pytx
def makePubKey(self, byte): """ The input byte will be repeated 32 times, then treated as the x-value of a compressed pubkey. Uncompress it to get a real pubkey. We do this so that we have a valid public key for our tests, in which the validity of our 65-byte keys are checked """ sbd33 = SecureBinaryData('\x02' + byte*32) return CryptoECDSA().UncompressPoint(sbd33).toBinStr()
def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join(self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join(self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa'*32) self.privKey2 = SecureBinaryData('\x33'*32) self.chainstr = SecureBinaryData('\xee'*32) theIV = SecureBinaryData(hex_to_binary('77'*16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') #register a callback TheBDM.registerCppNotification(self.armoryDTestCallback) #flag to check on wallet scan status self.walletIsScanned = False #create the wallet self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) #register it self.wallet.registerWallet() #wait on scan for 2 min then raise if the scan hasn't finished yet i = 0 while not self.walletIsScanned: time.sleep(0.5) i += 1 if i >= 60*4: raise RuntimeError("Timeout waiting for TheBDM to register the wallet.")
def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join( self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join( self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa' * 32) self.privKey2 = SecureBinaryData('\x33' * 32) self.chainstr = SecureBinaryData('\xee' * 32) theIV = SecureBinaryData(hex_to_binary('77' * 16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') #register a callback TheBDM.registerCppNotification(self.armoryDTestCallback) #flag to check on wallet scan status self.walletIsScanned = False #create the wallet self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) #register it self.wallet.registerWallet() #wait on scan for 2 min then raise if the scan hasn't finished yet i = 0 while not self.walletIsScanned: time.sleep(0.5) i += 1 if i >= 60 * 4: raise RuntimeError( "Timeout waiting for TheBDM to register the wallet.")
def setUp(self): self.shortlabel = 'TestWallet1' self.wltID = '3VB8XSoY' if USE_TESTNET else '3VB8XSmd' self.fileA = os.path.join(ARMORY_HOME_DIR, 'armory_%s_.wallet' % self.wltID) self.fileB = os.path.join(ARMORY_HOME_DIR, 'armory_%s_backup.wallet' % self.wltID) self.fileAupd = os.path.join( ARMORY_HOME_DIR, 'armory_%s_backup_unsuccessful.wallet' % self.wltID) self.fileBupd = os.path.join( ARMORY_HOME_DIR, 'armory_%s_update_unsuccessful.wallet' % self.wltID) self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa' * 32) self.privKey2 = SecureBinaryData('\x33' * 32) self.chainstr = SecureBinaryData('\xee' * 32) theIV = SecureBinaryData(hex_to_binary('77' * 16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') self.wlt = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=self.shortlabel)
def signZipFile(zipFilePath, propertiesDictionary=None): if propertiesDictionary: # Create an empty properties file pass # if it's a string treat it like a file name and open it # else if ti's a dictionary save it to a file and use that. # Read the contents of the Zip File and the properties file zipFileData = None propertiesFileData = None dataToSign = sha256(sha256(zipFileData) + sha256(propertiesFileData)) dataToSignSBD = SecureBinaryData(dataToSign) # get the privKeySBD privKeySBD = None signature = CryptoECDSA().SignData(dataToSignSBD, privKeySBD, ENABLE_DETSIGN)
def distributeBtc(masterWallet, amount, sendingAddrList): pytx = None setupTheBDM() try: recipValuePairs = [] utxoList = [] for sendingAddr in sendingAddrList: addr160 = sendingAddr.getAddr160() # Make sure the sending addresses are in the masterWallet if not masterWallet.hasAddr(addr160): raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: recipValuePairs.append((importedAddr.getAddr160(),amount)) totalSpend = len(recipValuePairs)*amount fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))[1] # Get the necessary utxo list selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee) # get total value totalAvailable = sum([u.getValue() for u in selectedUtxoList]) totalChange = totalAvailable - (totalSpend + fee) # Make sure there are funds to cover the transaction. if totalChange < 0: print '***ERROR: you are trying to spend more than your balance!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] txdp = PyTxDistProposal().createFromTxOutSelection(selectedUtxoList, scrPairs) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signTxDistProposal(txdp) pytx = txdp.prepareFinalTx() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print txdp.serializeAscii() finally: TheBDM.execCleanShutdown() return pytx
def spawnDB(self, dataDir, dbDir): pargs = [self.dbExecutable] pargs.append('--db-type="' + ARMORY_DB_TYPE + '"') if USE_TESTNET: pargs.append('--testnet') if USE_REGTEST: pargs.append('--regtest'); blocksdir = os.path.join(self.satoshiHome, 'blocks') if not os.path.exists(blocksdir): raise self.BadPath, "Invalid blockdata path" randBase58 = SecureBinaryData().GenerateRandom(32).toBinStr() spawnId = binary_to_base58(randBase58) pargs.append('--spawnId="' + spawnId + '"') pargs.append('--satoshi-datadir="' + blocksdir + '"') pargs.append('--datadir="' + dataDir + '"') pargs.append('--dbdir="' + dbDir + '"') if CLI_OPTIONS.rebuild: pargs.append('--rebuild') elif CLI_OPTIONS.rescan: pargs.append('--rescan') elif CLI_OPTIONS.rescanBalance: pargs.append('--rescanSSH') if ARMORY_RAM_USAGE != -1: pargs.append('--ram-usage=' + ARMORY_RAM_USAGE) if ARMORY_THREAD_COUNT != -1: pargs.append('--thread-count=' + ARMORY_THREAD_COUNT) kargs = {} if OS_WINDOWS: #import win32process kargs['shell'] = True #kargs['creationflags'] = win32process.CREATE_NO_WINDOW launchProcess(pargs, **kargs) return spawnId
def testTouch(self): testAddr = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, publicKey65=PUBLIC_KEY) theIV = SecureBinaryData(hex_to_binary(INIT_VECTOR)) testAddr.enableKeyEncryption(theIV) rightNow = RightNow() testAddr.touch(rightNow) self.assertEqual(testAddr.timeRange[0], long(rightNow)) self.assertEqual(testAddr.timeRange[1], long(rightNow)) testAddr.touch(0) self.assertEqual(testAddr.timeRange[0], long(0)) self.assertEqual(testAddr.timeRange[1], long(rightNow)) testAddr.touch(blkNum=TEST_BLOCK_NUM) self.assertEqual(testAddr.blkRange[0], TEST_BLOCK_NUM) self.assertEqual(testAddr.blkRange[1], TOP_TIAB_BLOCK) testAddr.touch(blkNum=0) self.assertEqual(testAddr.blkRange[0], 0) self.assertEqual(testAddr.blkRange[1], TOP_TIAB_BLOCK) # Cover the case where the blkRange[0] starts at 0 testAddr.touch(blkNum=TEST_BLOCK_NUM) self.assertEqual(testAddr.blkRange[0], TEST_BLOCK_NUM) self.assertEqual(testAddr.blkRange[1], TOP_TIAB_BLOCK)
def searchForPassword(self, segList, segOrdList=[]): if len(segOrdList) == 0: segOrdList = [range(len(segList))] passwordCount = self.countPasswords(segList, segOrdList) startTime = RightNow() found = False result = None for i, p in enumerate(self.passwordGenerator(segList, segOrdList)): isValid = self.wallet.verifyPassphrase(SecureBinaryData(p)) if isValid: # If the passphrase was wrong, it would error out, and not continue print 'Passphrase found!' print '' print '\t', p print '' print 'Thanks for using this script. If you recovered coins because of it, ' print 'please consider donating :) ' print ' 1ArmoryXcfq7TnCSuZa9fQjRYwJ4bkRKfv' print '' found = True open('FOUND_PASSWORD.txt', 'w').write(p) result = p break elif i % 100 == 0: telapsed = (RightNow() - startTime) / 3600. print('%d/%d passphrases tested... (%0.1f hours so far)' % (i, passwordCount, telapsed)).rjust(40) print p, if i % 10 == 9: print if not found: print '' print 'Script finished!' print 'Sorry, none of the provided passphrases were correct :(' print '' return result
def testWalletRecovery(self): #run recovery on broken wallet recThread = PyBtcWalletRecovery().RecoverWallet(self.corruptWallet, \ 'testing', RECOVERMODE.Full, \ returnError = 'Dict') recThread.join() brkWltResult = recThread.output self.assertTrue(len(brkWltResult['sequenceGaps'])==1, \ "Sequence Gap Undetected") self.assertTrue(len(brkWltResult['forkedPublicKeyChain'])==3, \ "Address Chain Forks Undetected") self.assertTrue(len(brkWltResult['unmatchedPair'])==100, \ "Unmatched Priv/Pub Key Undetected") self.assertTrue(len(brkWltResult['misc'])==50, \ "Wallet Encryption Inconsistency Undetected") self.assertTrue(len(brkWltResult['importedErr'])==50, \ "Unexpected Errors Found") self.assertTrue(brkWltResult['nErrors']==204, \ "Unexpected Errors Found") #check obfuscated keys yield the valid key #grab root key badWlt = PyBtcWallet() badWlt.readWalletFile(self.corruptWallet, False, False) rootAddr = badWlt.addrMap['ROOT'] SecurePassphrase = SecureBinaryData('testing') secureKdfOutput = badWlt.kdf.DeriveKey(SecurePassphrase) #HMAC Q rootAddr.unlock(secureKdfOutput) Q = rootAddr.binPrivKey32_Plain.toBinStr() nonce = 0 while 1: hmacQ = HMAC256(Q, 'LogMult%d' % nonce) if binary_to_int(hmacQ, BIGENDIAN) < SECP256K1_ORDER: hmacQ = SecureBinaryData(hmacQ) break nonce = nonce + 1 #Bad Private Keys import operator badKeys = [ addrObj for addrObj in (sorted(badWlt.addrMap.values(), key=operator.attrgetter('chainIndex'))) ] #run through obdsPrivKey for i in range(0, len(brkWltResult['privMult'])): obfsPKey = SecureBinaryData( hex_to_binary(brkWltResult['privMult'][i])) pKey = CryptoECDSA().ECMultiplyScalars(obfsPKey.toBinStr(), \ hmacQ.toBinStr()) try: badKeys[i + 201].unlock(secureKdfOutput) except: continue self.assertTrue(binary_to_hex(pKey) == \ badKeys[i+201].binPrivKey32_Plain.toHexStr(), \ 'key mult error') #run recovery on recovered wallet recThread = PyBtcWalletRecovery().RecoverWallet( \ 'armory_%s_RECOVERED.wallet' % self.wltID, \ 'testing', RECOVERMODE.Full, \ returnError = 'Dict') recThread.join() rcvWltResult = recThread.output self.assertTrue(len(rcvWltResult['importedErr'])==50, \ "Unexpected Errors Found") self.assertTrue(rcvWltResult['nErrors']==50, \ "Unexpected Errors Found") self.assertTrue(len(rcvWltResult['negativeImports'])==99, \ "Missing neg Imports") # Running tests with "python <module name>" will NOT work for any Armory tests # You must run tests with "python -m unittest <module name>" or run all tests with "python -m unittest discover" # if __name__ == "__main__": # unittest.main()
def readBitcoinConf(self, makeIfDNE=False): LOGINFO('Reading groestlcoin.conf file') bitconf = os.path.join(self.satoshiRoot, 'groestlcoin.conf') if not os.path.exists(bitconf): if not makeIfDNE: raise self.BitcoinDotConfError, 'Could not find groestlcoin.conf' else: LOGINFO('No groestlcoin.conf available. Creating it...') touchFile(bitconf) # Guarantee that bitcoin.conf file has very strict permissions if OS_WINDOWS: if OS_VARIANT[0].lower() == 'xp': LOGERROR('Cannot set permissions correctly in XP!') LOGERROR('Please confirm permissions on the following file ') LOGERROR('are set to exclusive access only for your user ') LOGERROR( '(it usually is, but Groestlcoin Armory cannot guarantee it ' ) LOGERROR('on XP systems):') LOGERROR(' %s', bitconf) else: LOGINFO('Setting permissions on groestlcoin.conf') import ctypes username_u16 = ctypes.create_unicode_buffer(u'\0', 512) str_length = ctypes.c_int(512) ctypes.windll.Advapi32.GetUserNameW(ctypes.byref(username_u16), ctypes.byref(str_length)) CLI_OPTIONS.disableConfPermis = True #!!!GRS if not CLI_OPTIONS.disableConfPermis: import win32process LOGINFO('Setting permissions on groestlcoin.conf') cmd_icacls = [ u'icacls', bitconf, u'/inheritance:r', u'/grant:r', u'%s:F' % username_u16.value ] kargs = {} kargs['shell'] = True kargs['creationflags'] = win32process.CREATE_NO_WINDOW icacls_out = subprocess_check_output(cmd_icacls, **kargs) LOGINFO('icacls returned: %s', icacls_out) else: LOGWARN( 'Skipped setting permissions on groestlcoin.conf file') else: if not CLI_OPTIONS.disableConfPermis: LOGINFO('Setting permissions on groestlcoin.conf') os.chmod(bitconf, stat.S_IRUSR | stat.S_IWUSR) else: LOGWARN('Skipped setting permissions on groestlcoin.conf file') with open(bitconf, 'r') as f: # Find the last character of the each line: either a newline or '#' endchr = lambda line: line.find('#') if line.find( '#') > 1 else len(line) # Reduce each line to a list of key,value pairs separated with '=' allconf = [l[:endchr(l)].strip().split('=') for l in f.readlines()] # Need to convert to (x[0],x[1:]) in case the password has '=' in it allconfPairs = [[x[0], '='.join(x[1:])] for x in allconf if len(x) > 1] # Convert the list of pairs to a dictionary self.bitconf = dict(allconfPairs) # Look for rpcport, use default if not there self.bitconf['rpcport'] = int( self.bitconf.get('rpcport', BITCOIN_RPC_PORT)) # We must have a username and password. If not, append to file if not self.bitconf.has_key('rpcuser'): LOGDEBUG('No rpcuser: creating one') with open(bitconf, 'a') as f: f.write('\n') f.write('rpcuser=generated_by_armory\n') self.bitconf['rpcuser'] = '******' if not self.bitconf.has_key('rpcpassword'): LOGDEBUG('No rpcpassword: creating one') with open(bitconf, 'a') as f: randBase58 = SecureBinaryData().GenerateRandom(32).toBinStr() randBase58 = binary_to_base58(randBase58) f.write('\n') f.write('rpcpassword=%s' % randBase58) self.bitconf['rpcpassword'] = randBase58 if not isASCII(self.bitconf['rpcuser']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcuser)!') if not isASCII(self.bitconf['rpcpassword']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcpassword)!') self.bitconf['host'] = '127.0.0.1'
class ArmoryDTest(unittest.TestCase): def removeFileList(self, fileList): for f in fileList: if os.path.exists(f): os.remove(f) @classmethod def setUpClass(self): # This is not a UI so no need to worry about the main thread being blocked. # Any UI that uses this Daemon can put the call to the Daemon on it's own thread. TheBDM.Reset() TheBDM.setBlocking(True) TheBDM.setOnlineMode(True) while not TheBDM.getBDMState()=='BlockchainReady': time.sleep(2) def setUp(self): self.fileA = os.path.join(ARMORY_HOME_DIR, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(ARMORY_HOME_DIR, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join(ARMORY_HOME_DIR, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join(ARMORY_HOME_DIR, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa'*32) self.privKey2 = SecureBinaryData('\x33'*32) self.chainstr = SecureBinaryData('\xee'*32) theIV = SecureBinaryData(hex_to_binary('77'*16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) TheBDM.registerWallet(self.wallet) def tearDown(self): self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # Can't test with actual transactions in this environment. See ARMORY-34. # This wallet has no txs # def testListunspent(self): # actualResult = self.jsonServer.jsonrpc_listunspent() # self.assertEqual(actualResult, []) def testImportprivkey(self): originalLength = len(self.wallet.linearAddr160List) self.jsonServer.jsonrpc_importprivkey(self.privKey2) self.assertEqual(len(self.wallet.linearAddr160List), originalLength+1) def testGettxout(self): txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 0) self.assertEquals(TX_ID1_OUTPUT0_VALUE, txOut.value) txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 1) self.assertEquals(TX_ID1_OUTPUT1_VALUE, txOut.value) # Cannot unit test actual balances. Only verify that getreceivedbyaddress return a 0 result. def testGetreceivedbyaddress(self): a160 = hash160(self.wallet.getNextUnusedAddress().binPublicKey65.toBinStr()) testAddr = hash160_to_addrStr(a160) result = self.jsonServer.jsonrpc_getreceivedbyaddress(testAddr) self.assertEqual(result, 0) def testGetrawtransaction(self): actualRawTx = self.jsonServer.jsonrpc_getrawtransaction(TX_ID1) pyTx = PyTx().unserialize(hex_to_binary(actualRawTx)) self.assertEquals(TX_ID1, binary_to_hex(pyTx.getHash(), BIGENDIAN)) def testBackupWallet(self): backupTestPath = os.path.join(ARMORY_HOME_DIR, 'armory_%s_.wallet.backup.test' % TEST_WALLET_ID) # Remove backupTestPath in case it exists backupFileList = [backupTestPath, self.fileB] self.removeFileList(backupFileList) # Remove the backup test path that is to be created after tear down. self.addCleanup(self.removeFileList, backupFileList) self.jsonServer.jsonrpc_backupwallet(backupTestPath) self.assertTrue(os.path.exists(backupTestPath)) self.wallet.backupWalletFile() self.assertTrue(os.path.exists(self.fileB)) def testDecoderawtransaction(self): actualDD = self.jsonServer.jsonrpc_decoderawtransaction(RAW_TX1) # Test specific values pulled from bitcoin daemon's output for the test raw TX expectScriptStr = 'OP_DUP OP_HASH160 PUSHDATA(20) [be17ec0fc1f8aa029223dbe5f53109d0faf8c797] OP_EQUALVERIFY OP_CHECKSIG' self.assertEqual(actualDD['locktime'], 0) self.assertEqual(actualDD['version'], 1) self.assertEqual(actualDD['vin'][0]['sequence'], 4294967295L) self.assertEqual(actualDD['vin'][0]['scriptSig']['hex'], '') self.assertEqual(actualDD['vin'][0]['scriptSig']['asm'], '') self.assertEqual(actualDD['vin'][0]['vout'], 1201) self.assertEqual(actualDD['vin'][0]['txid'], 'e450dc7394f8432d89c68d0df6a5506cb81eac60c977bfc7932633aaf835a31f') self.assertEqual(actualDD['vin'][1]['vout'], 294) self.assertEqual(actualDD['vin'][1]['txid'], '8867f0f84e80588ed00a05e604487442546ef42ab4c93445a09b00a6d487e74b') self.assertEqual(actualDD['vout'][0]['value'], 0.0001944) self.assertEqual(actualDD['vout'][0]['n'], 0) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['reqSigs'], 1) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['hex'], '76a914be17ec0fc1f8aa029223dbe5f53109d0faf8c79788ac') self.assertEqual(actualDD['vout'][0]['scriptPubKey']['addresses'], ['mxr5Le3bt7dfbFqmpK6saUYPt5xtcDB7Yw']) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['asm'], expectScriptStr) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][1]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][2]['scriptPubKey']['type'], 'Non-Standard') def testDumpprivkey(self): testPrivKey = self.privKey.toBinStr() hash160 = convertKeyDataToAddress(testPrivKey) addr58 = hash160_to_addrStr(hash160) # Verify that a bogus addrss Raises InvalidBitcoinAddress Exception self.assertRaises(InvalidBitcoinAddress, self.jsonServer.jsonrpc_dumpprivkey, 'bogus') # verify that the root private key is not found self.assertRaises(PrivateKeyNotFound, self.jsonServer.jsonrpc_dumpprivkey, addr58) # verify that the first private key can be found firstHash160 = self.wallet.getNextUnusedAddress().getAddr160() firstAddr58 = hash160_to_addrStr(firstHash160) actualPrivateKey = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58) expectedPrivateKey = self.wallet.getAddrByHash160(firstHash160).serializePlainPrivateKey() self.assertEqual(actualPrivateKey, expectedPrivateKey) # Verify that a locked wallet Raises WalletUnlockNeeded Exception kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.wallet.changeWalletEncryption( securePassphrase=self.passphrase ) self.wallet.lock() self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_dumpprivkey, addr58) def testEncryptwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) # Verify that a locked wallet Raises WalletUnlockNeeded Exception self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_encryptwallet, PASSPHRASE1) def testUnlockwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) self.jsonServer.jsonrpc_unlockwallet(PASSPHRASE1, UNLOCK_TIMEOUT) self.assertFalse(self.wallet.isLocked) time.sleep(UNLOCK_TIMEOUT+1) self.wallet.checkWalletLockTimeout() self.assertTrue(self.wallet.isLocked) def testGetWalletInfo(self): wltInfo = self.jsonServer.jsonrpc_getwalletinfo() self.assertEqual(wltInfo['name'], TEST_WALLET_NAME) self.assertEqual(wltInfo['description'], TEST_WALLET_DESCRIPTION) self.assertEqual(wltInfo['balance'], AmountToJSON(self.wallet.getBalance('Spend'))) self.assertEqual(wltInfo['keypoolsize'], self.wallet.addrPoolSize) self.assertEqual(wltInfo['numaddrgen'], len(self.wallet.addrMap)) self.assertEqual(wltInfo['highestusedindex'], self.wallet.highestUsedChainIndex) # This should always return 0 balance # Need to create our own test net to test with balances def testGetBalance(self): for ballanceType in ['spendable','spend', 'unconf', \ 'unconfirmed', 'total', 'ultimate','unspent', 'full']: self.assertEqual(self.jsonServer.jsonrpc_getbalance(ballanceType), AmountToJSON(self.wallet.getBalance(ballanceType))) self.assertEqual(self.jsonServer.jsonrpc_getbalance('bogus'), -1)
def jsonrpc_encryptwallet(self, passphrase): if self.wallet.isLocked: raise WalletUnlockNeeded self.wallet.changeWalletEncryption( securePassphrase=SecureBinaryData(passphrase) ) self.wallet.lock()
def testEncryptedAddress(self): # test serialization and unserialization of an empty PyBtcAddrss # Should serialize to a string that starts with 20 bytes of zeros # Unserialize should throw an UnserializeError caused by checksum mismatch emptyBtcAddr = PyBtcAddress() emptyBtcAddrSerialized = emptyBtcAddr.serialize() self.assertEqual(emptyBtcAddrSerialized[:20], hex_to_binary('00'*20)) self.assertRaises(UnserializeError, PyBtcAddress().unserialize, emptyBtcAddrSerialized) # Test non-crashing testAddr1 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20) testAddr2 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, chksum=PRIVATE_CHECKSUM) testAddr3 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, publicKey65=PUBLIC_KEY) testAddr4 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, publicKey65=PUBLIC_KEY, skipCheck=True) testAddr5 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, skipPubCompute=True) testString = testAddr1.toString() self.assertTrue(len(testString) > 0) testAddr = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20, publicKey65=PUBLIC_KEY) serializedAddr1 = testAddr.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr1) serializedRetest1 = retestAddr.serialize() self.assertEqual(serializedAddr1, serializedRetest1) theIV = SecureBinaryData(hex_to_binary(INIT_VECTOR)) testAddr.enableKeyEncryption(theIV) testAddr.lock(FAKE_KDF_OUTPUT1) self.assertTrue(testAddr.useEncryption) self.assertTrue(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) serializedAddr2 = testAddr.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr2) serializedRetest2 = retestAddr.serialize() self.assertEqual(serializedAddr2, serializedRetest2) testAddr.unlock(FAKE_KDF_OUTPUT1) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) testAddr.changeEncryptionKey(None, FAKE_KDF_OUTPUT1) self.assertTrue(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) # Save off this data for a later test addr20_1 = testAddr.getAddr160() encryptedKey1 = testAddr.binPrivKey32_Encr encryptionIV1 = testAddr.binInitVect16 plainPubKey1 = testAddr.binPublicKey65 # OP(Key1 --> Unencrypted) testAddr.changeEncryptionKey(FAKE_KDF_OUTPUT1, None) self.assertFalse(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), '') # OP(Unencrypted --> Key2) if not testAddr.isKeyEncryptionEnabled(): testAddr.enableKeyEncryption(theIV) testAddr.changeEncryptionKey(None, FAKE_KDF_OUTPUT2) self.assertTrue(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR2) # Save off this data for a later test addr20_2 = testAddr.getAddr160() encryptedKey2 = testAddr.binPrivKey32_Encr encryptionIV2 = testAddr.binInitVect16 plainPubKey2 = testAddr.binPublicKey65 # OP(Key2 --> Key1) testAddr.changeEncryptionKey(FAKE_KDF_OUTPUT2, FAKE_KDF_OUTPUT1) self.assertTrue(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) # OP(Key1 --> Lock --> Key2) testAddr.lock(FAKE_KDF_OUTPUT1) testAddr.changeEncryptionKey(FAKE_KDF_OUTPUT1, FAKE_KDF_OUTPUT2) self.assertTrue(testAddr.useEncryption) self.assertTrue(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR2) # OP(Key2 --> Lock --> Unencrypted) testAddr.changeEncryptionKey(FAKE_KDF_OUTPUT2, None) self.assertFalse(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), '') # Encryption Key Tests: self.assertEqual(testAddr.serializePlainPrivateKey(), PRIVATE_KEY.toBinStr()) # Test loading pre-encrypted key data testAddr = PyBtcAddress().createFromEncryptedKeyData(addr20_1, encryptedKey1, encryptionIV1) self.assertTrue(testAddr.useEncryption) self.assertTrue(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) # OP(EncrAddr --> Unlock1) testAddr.unlock(FAKE_KDF_OUTPUT1) self.assertTrue(testAddr.useEncryption) self.assertFalse(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) # OP(Unlock1 --> Lock1) testAddr.lock() self.assertTrue(testAddr.useEncryption) self.assertTrue(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR1) # OP(Lock1 --> Lock2) testAddr.changeEncryptionKey(FAKE_KDF_OUTPUT1, FAKE_KDF_OUTPUT2) self.assertTrue(testAddr.useEncryption) self.assertTrue(testAddr.isLocked) self.assertEqual(testAddr.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(testAddr.binPrivKey32_Encr.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR2) # Test serializing locked wallet from pre-encrypted data' serializedAddr = testAddr.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) ############################################################################# # Now testing chained-key (deterministic) address generation # Test chained priv key generation # Starting with plain key data chaincode = SecureBinaryData(hex_to_binary('ee'*32)) addr0 = PyBtcAddress().createFromPlainKeyData(PRIVATE_KEY, ADDRESS_20) addr0.markAsRootAddr(chaincode) pub0 = addr0.binPublicKey65 # Test serializing address-chain-root serializedAddr = addr0.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) self.assertEqual(retestAddr.binPrivKey32_Plain.toHexStr(), PRIVATE_KEY.toHexStr()) # Generate chained PRIVATE key address # OP(addr[0] --> addr[1]) addr1 = addr0.extendAddressChain() self.assertEqual(addr1.binPrivKey32_Plain.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR3) # OP(addr[0] --> addr[1]) [again]' addr1a = addr0.extendAddressChain() self.assertEqual(addr1a.binPrivKey32_Plain.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR3) # OP(addr[1] --> addr[2]) addr2 = addr1.extendAddressChain() pub2 = addr2.binPublicKey65.copy() priv2 = addr2.binPrivKey32_Plain.copy() self.assertEqual(priv2.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR4) # Addr1.PRIVATE_KEY == Addr1a.PRIVATE_KEY:', self.assertEqual(addr1.binPublicKey65, addr1a.binPublicKey65) # Test serializing priv-key-chained', serializedAddr = addr2.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) ############################################################################# # Generate chained PUBLIC key address # addr[0] addr0 = PyBtcAddress().createFromPublicKeyData(pub0) addr0.markAsRootAddr(chaincode) self.assertEqual(addr0.chainIndex, -1) self.assertEqual(addr0.chaincode, chaincode) # Test serializing pub-key-only-root', serializedAddr = addr0.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) # OP(addr[0] --> addr[1])' addr1 = addr0.extendAddressChain() self.assertEqual(addr1.binPrivKey32_Plain.toHexStr(), '') # OP(addr[1] --> addr[2])' addr2 = addr1.extendAddressChain() pub2a = addr2.binPublicKey65.copy() self.assertEqual(addr2.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(pub2a.toHexStr(), TEST_PUB_KEY1) # Addr2.PublicKey == Addr2a.PublicKey:' # Test serializing pub-key-from-chain' serializedAddr = addr2.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) ############################################################################# # Generate chained keys from locked addresses addr0 = PyBtcAddress().createFromPlainKeyData( PRIVATE_KEY, \ willBeEncr=True, IV16=theIV) addr0.markAsRootAddr(chaincode) # OP(addr[0] plain) # Test serializing unlocked addr-chain-root serializedAddr = addr0.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) self.assertFalse(retestAddr.useEncryption) # OP(addr[0] locked) addr0.lock(FAKE_KDF_OUTPUT1) self.assertEqual(addr0.binPrivKey32_Plain.toHexStr(), '') # OP(addr[0] w/Key --> addr[1]) addr1 = addr0.extendAddressChain(FAKE_KDF_OUTPUT1, newIV=theIV) self.assertEqual(addr1.binPrivKey32_Plain.toHexStr(), '') # OP(addr[1] w/Key --> addr[2]) addr2 = addr1.extendAddressChain(FAKE_KDF_OUTPUT1, newIV=theIV) addr2.unlock(FAKE_KDF_OUTPUT1) priv2a = addr2.binPrivKey32_Plain.copy() addr2.lock() self.assertEqual(addr2.binPrivKey32_Plain.toHexStr(), '') # Addr2.priv == Addr2a.priv: self.assertEqual(priv2, priv2a) # Test serializing chained address from locked root serializedAddr = addr2.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) ############################################################################# # Generate chained keys from locked addresses, no unlocking addr0 = PyBtcAddress().createFromPlainKeyData( PRIVATE_KEY, \ willBeEncr=True, IV16=theIV) addr0.markAsRootAddr(chaincode) # OP(addr[0] locked) addr0.lock(FAKE_KDF_OUTPUT1) self.assertEqual(addr0.binPrivKey32_Plain.toHexStr(), '') # OP(addr[0] locked --> addr[1] locked)' addr1 = addr0.extendAddressChain(newIV=theIV) self.assertEqual(addr1.binPrivKey32_Plain.toHexStr(), '') # OP(addr[1] locked --> addr[2] locked) addr2 = addr1.extendAddressChain(newIV=theIV) pub2b = addr2.binPublicKey65.copy() self.assertEqual(addr2.binPrivKey32_Plain.toHexStr(), '') self.assertEqual(pub2b.toHexStr(), TEST_PUB_KEY1) # Addr2.Pub == Addr2b.pub: # Test serializing priv-key-bearing address marked for unlock serializedAddr = addr2.serialize() retestAddr = PyBtcAddress().unserialize(serializedAddr) serializedRetest = retestAddr.serialize() self.assertEqual(serializedAddr, serializedRetest) addr2.unlock(FAKE_KDF_OUTPUT1) priv2b = addr2.binPrivKey32_Plain.copy() # OP(addr[2] locked --> unlocked) self.assertEqual(priv2b.toHexStr(), TEST_ADDR1_PRIV_KEY_ENCR4) addr2.lock() # OP(addr[2] unlocked --> locked)' # Addr2.priv == Addr2b.priv: self.assertEqual(priv2, priv2b)
def jsonrpc_unlockwallet(self, passphrase, timeout): self.wallet.unlock( securePassphrase=SecureBinaryData(passphrase), tempKeyLifetime=timeout)
class ArmoryDTest(unittest.TestCase): def removeFileList(self, fileList): for f in fileList: if os.path.exists(f): os.remove(f) @classmethod def setUpClass(self): # This is not a UI so no need to worry about the main thread being blocked. # Any UI that uses this Daemon can put the call to the Daemon on it's own thread. TheBDM.setBlocking(True) TheBDM.setOnlineMode(True) while not TheBDM.getBDMState() == 'BlockchainReady': time.sleep(2) def setUp(self): self.fileA = os.path.join(ARMORY_HOME_DIR, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(ARMORY_HOME_DIR, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join( ARMORY_HOME_DIR, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join( ARMORY_HOME_DIR, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa' * 32) self.privKey2 = SecureBinaryData('\x33' * 32) self.chainstr = SecureBinaryData('\xee' * 32) theIV = SecureBinaryData(hex_to_binary('77' * 16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) TheBDM.registerWallet(self.wallet) def tearDown(self): self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # Can't test with actual transactions in this environment. See ARMORY-34. # This wallet has no txs def testListunspent(self): actualResult = self.jsonServer.jsonrpc_listunspent() self.assertEqual(actualResult, []) def testImportprivkey(self): originalLength = len(self.wallet.linearAddr160List) self.jsonServer.jsonrpc_importprivkey(self.privKey2) self.assertEqual(len(self.wallet.linearAddr160List), originalLength + 1) def testGettxout(self): txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 0) self.assertEquals(TX_ID1_OUTPUT0_VALUE, txOut.value) txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 1) self.assertEquals(TX_ID1_OUTPUT1_VALUE, txOut.value) # Cannot unit test actual balances. Only verify that getreceivedbyaddress return a 0 result. def testGetreceivedbyaddress(self): a160 = hash160( self.wallet.getNextUnusedAddress().binPublicKey65.toBinStr()) testAddr = hash160_to_addrStr(a160) result = self.jsonServer.jsonrpc_getreceivedbyaddress(testAddr) self.assertEqual(result, 0) def testGetrawtransaction(self): actualRawTx = self.jsonServer.jsonrpc_getrawtransaction(TX_ID1) pyTx = PyTx().unserialize(hex_to_binary(actualRawTx)) self.assertEquals(TX_ID1, binary_to_hex(pyTx.getHash(), BIGENDIAN)) def testBackupWallet(self): backupTestPath = os.path.join( ARMORY_HOME_DIR, 'armory_%s_.wallet.backup.test' % TEST_WALLET_ID) # Remove backupTestPath in case it exists backupFileList = [backupTestPath, self.fileB] self.removeFileList(backupFileList) # Remove the backup test path that is to be created after tear down. self.addCleanup(self.removeFileList, backupFileList) self.jsonServer.jsonrpc_backupwallet(backupTestPath) self.assertTrue(os.path.exists(backupTestPath)) self.wallet.backupWalletFile() self.assertTrue(os.path.exists(self.fileB)) def testDecoderawtransaction(self): actualDD = self.jsonServer.jsonrpc_decoderawtransaction(RAW_TX1) # Test specific values pulled from bitcoin daemon's output for the test raw TX expectScriptStr = 'OP_DUP OP_HASH160 PUSHDATA(20) [be17ec0fc1f8aa029223dbe5f53109d0faf8c797] OP_EQUALVERIFY OP_CHECKSIG' self.assertEqual(actualDD['locktime'], 0) self.assertEqual(actualDD['version'], 1) self.assertEqual(actualDD['vin'][0]['sequence'], 4294967295L) self.assertEqual(actualDD['vin'][0]['scriptSig']['hex'], '') self.assertEqual(actualDD['vin'][0]['scriptSig']['asm'], '') self.assertEqual(actualDD['vin'][0]['vout'], 1201) self.assertEqual( actualDD['vin'][0]['txid'], 'e450dc7394f8432d89c68d0df6a5506cb81eac60c977bfc7932633aaf835a31f') self.assertEqual(actualDD['vin'][1]['vout'], 294) self.assertEqual( actualDD['vin'][1]['txid'], '8867f0f84e80588ed00a05e604487442546ef42ab4c93445a09b00a6d487e74b') self.assertEqual(actualDD['vout'][0]['value'], 0.0001944) self.assertEqual(actualDD['vout'][0]['n'], 0) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['reqSigs'], 1) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['hex'], '76a914be17ec0fc1f8aa029223dbe5f53109d0faf8c79788ac') self.assertEqual(actualDD['vout'][0]['scriptPubKey']['addresses'], ['mxr5Le3bt7dfbFqmpK6saUYPt5xtcDB7Yw']) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['asm'], expectScriptStr) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][1]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][2]['scriptPubKey']['type'], 'Non-Standard') def testDumpprivkey(self): testPrivKey = self.privKey.toBinStr() hash160 = convertKeyDataToAddress(testPrivKey) addr58 = hash160_to_addrStr(hash160) # Verify that a bogus addrss Raises InvalidBitcoinAddress Exception self.assertRaises(InvalidBitcoinAddress, self.jsonServer.jsonrpc_dumpprivkey, 'bogus') # verify that the root private key is not found self.assertRaises(PrivateKeyNotFound, self.jsonServer.jsonrpc_dumpprivkey, addr58) # verify that the first private key can be found firstHash160 = self.wallet.getNextUnusedAddress().getAddr160() firstAddr58 = hash160_to_addrStr(firstHash160) actualPrivateKey = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58) expectedPrivateKey = self.wallet.getAddrByHash160( firstHash160).serializePlainPrivateKey() self.assertEqual(actualPrivateKey, expectedPrivateKey) # Verify that a locked wallet Raises WalletUnlockNeeded Exception kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.wallet.changeWalletEncryption(securePassphrase=self.passphrase) self.wallet.lock() self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_dumpprivkey, addr58) def testEncryptwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) # Verify that a locked wallet Raises WalletUnlockNeeded Exception self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_encryptwallet, PASSPHRASE1) def testUnlockwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) self.jsonServer.jsonrpc_unlockwallet(PASSPHRASE1, UNLOCK_TIMEOUT) self.assertFalse(self.wallet.isLocked) time.sleep(UNLOCK_TIMEOUT + 1) self.wallet.checkWalletLockTimeout() self.assertTrue(self.wallet.isLocked) def testGetWalletInfo(self): wltInfo = self.jsonServer.jsonrpc_getwalletinfo() self.assertEqual(wltInfo['name'], TEST_WALLET_NAME) self.assertEqual(wltInfo['description'], TEST_WALLET_DESCRIPTION) self.assertEqual(wltInfo['balance'], AmountToJSON(self.wallet.getBalance('Spend'))) self.assertEqual(wltInfo['keypoolsize'], self.wallet.addrPoolSize) self.assertEqual(wltInfo['numaddrgen'], len(self.wallet.addrMap)) self.assertEqual(wltInfo['highestusedindex'], self.wallet.highestUsedChainIndex) # This should always return 0 balance # Need to create our own test net to test with balances def testGetBalance(self): for ballanceType in ['spendable','spend', 'unconf', \ 'unconfirmed', 'total', 'ultimate','unspent', 'full']: self.assertEqual( self.jsonServer.jsonrpc_getbalance(ballanceType), AmountToJSON(self.wallet.getBalance(ballanceType))) self.assertEqual(self.jsonServer.jsonrpc_getbalance('bogus'), -1)
def testWalletRecovery(self): #run recovery on broken wallet recThread = PyBtcWalletRecovery().RecoverWallet(self.corruptWallet, \ 'testing', RECOVERMODE.Full, \ returnError = 'Dict') recThread.join() brkWltResult = recThread.output self.assertTrue(len(brkWltResult['sequenceGaps'])==1, \ "Sequence Gap Undetected") self.assertTrue(len(brkWltResult['forkedPublicKeyChain'])==3, \ "Address Chain Forks Undetected") self.assertTrue(len(brkWltResult['unmatchedPair'])==100, \ "Unmatched Priv/Pub Key Undetected") self.assertTrue(len(brkWltResult['misc'])==50, \ "Wallet Encryption Inconsistency Undetected") self.assertTrue(len(brkWltResult['importedErr'])==50, \ "Unexpected Errors Found") self.assertTrue(brkWltResult['nErrors']==204, \ "Unexpected Errors Found") #check obfuscated keys yield the valid key #grab root key badWlt = PyBtcWallet() badWlt.readWalletFile(self.corruptWallet, False, False) rootAddr = badWlt.addrMap['ROOT'] SecurePassphrase = SecureBinaryData('testing') secureKdfOutput = badWlt.kdf.DeriveKey(SecurePassphrase) #HMAC Q rootAddr.unlock(secureKdfOutput) Q = rootAddr.binPrivKey32_Plain.toBinStr() nonce = 0 while 1: hmacQ = HMAC256(Q, 'LogMult%d' % nonce) if binary_to_int(hmacQ, BIGENDIAN) < SECP256K1_ORDER: hmacQ = SecureBinaryData(hmacQ) break nonce = nonce +1 #Bad Private Keys import operator badKeys = [addrObj for addrObj in (sorted(badWlt.addrMap.values(), key=operator.attrgetter('chainIndex')))] #run through obdsPrivKey for i in range(0, len(brkWltResult['privMult'])): obfsPKey = SecureBinaryData( hex_to_binary(brkWltResult['privMult'][i])) pKey = CryptoECDSA().ECMultiplyScalars(obfsPKey.toBinStr(), \ hmacQ.toBinStr()) try: badKeys[i+201].unlock(secureKdfOutput) except: continue self.assertTrue(binary_to_hex(pKey) == \ badKeys[i+201].binPrivKey32_Plain.toHexStr(), \ 'key mult error') #run recovery on recovered wallet recThread = PyBtcWalletRecovery().RecoverWallet( \ 'armory_%s_RECOVERED.wallet' % self.wltID, \ 'testing', RECOVERMODE.Full, \ returnError = 'Dict') recThread.join() rcvWltResult = recThread.output self.assertTrue(len(rcvWltResult['importedErr'])==50, \ "Unexpected Errors Found") self.assertTrue(rcvWltResult['nErrors']==50, \ "Unexpected Errors Found") self.assertTrue(len(rcvWltResult['negativeImports'])==99, \ "Missing neg Imports") # Running tests with "python <module name>" will NOT work for any Armory tests # You must run tests with "python -m unittest <module name>" or run all tests with "python -m unittest discover" # if __name__ == "__main__": # unittest.main()
class ArmoryDTest(TiabTest): def removeFileList(self, fileList): for f in fileList: if os.path.exists(f): os.remove(f) def armoryDTestCallback(self, action, args): if action == REFRESH_ACTION: self.walletIsScanned = True def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join(self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join(self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa'*32) self.privKey2 = SecureBinaryData('\x33'*32) self.chainstr = SecureBinaryData('\xee'*32) theIV = SecureBinaryData(hex_to_binary('77'*16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') #register a callback TheBDM.registerCppNotification(self.armoryDTestCallback) #flag to check on wallet scan status self.walletIsScanned = False #create the wallet self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) #register it self.wallet.registerWallet() #wait on scan for 2 min then raise if the scan hasn't finished yet i = 0 while not self.walletIsScanned: time.sleep(0.5) i += 1 if i >= 60*4: raise RuntimeError("Timeout waiting for TheBDM to register the wallet.") def tearDown(self): TheBDM.unregisterCppNotification(self.armoryDTestCallback) self.wallet.unregisterWallet() self.removeFileList([self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # Can't test with actual transactions in this environment. See ARMORY-34. # This wallet has no txs # def testListunspent(self): # actualResult = self.jsonServer.jsonrpc_listunspent() # self.assertEqual(actualResult, []) def testImportprivkey(self): originalLength = len(self.wallet.linearAddr160List) self.jsonServer.jsonrpc_importprivkey(binary_to_hex(self.privKey2.toBinStr())) self.assertEqual(len(self.wallet.linearAddr160List), originalLength+1) def testGettxout(self): txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 0) self.assertEquals(txOut['value'],TX_ID1_OUTPUT0_VALUE) txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 1) self.assertEquals(txOut['value'],TX_ID1_OUTPUT1_VALUE) def testGetreceivedbyaddress(self): a160 = hash160(self.wallet.getNextUnusedAddress().binPublicKey65.toBinStr()) testAddr = hash160_to_addrStr(a160) result = self.jsonServer.jsonrpc_getreceivedbyaddress(testAddr) self.assertEqual(result, 0) def testGetrawtransaction(self): actualRawTx = self.jsonServer.jsonrpc_getrawtransaction(TX_ID1) pyTx = PyTx().unserialize(hex_to_binary(actualRawTx)) self.assertEquals(TX_ID1, binary_to_hex(pyTx.getHash(), BIGENDIAN)) def testBackupWallet(self): backupTestPath = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet.backup.test' % TEST_WALLET_ID) # Remove backupTestPath in case it exists backupFileList = [backupTestPath, self.fileB] self.removeFileList(backupFileList) # Remove the backup test path that is to be created after tear down. self.addCleanup(self.removeFileList, backupFileList) self.jsonServer.jsonrpc_backupwallet(backupTestPath) self.assertTrue(os.path.exists(backupTestPath)) self.wallet.backupWalletFile() self.assertTrue(os.path.exists(self.fileB)) def testDecoderawtransaction(self): actualDD = self.jsonServer.jsonrpc_decoderawtransaction(RAW_TX1) # Test specific values pulled from bitcoin daemon's output for the test raw TX expectScriptStr = 'OP_DUP OP_HASH160 PUSHDATA(20) [62d978319c7d7ac6cceed722c3d08aa81b371012] OP_EQUALVERIFY OP_CHECKSIG' self.assertEqual(actualDD['locktime'], 0) self.assertEqual(actualDD['version'], 1) self.assertEqual(len(actualDD['vin']), 1) self.assertEqual(actualDD['vin'][0]['sequence'], 4294967295L) self.assertEqual(actualDD['vin'][0]['scriptSig']['hex'], '4830450220081341a4e803c7c8e64c3a3fd285dca34c9f7c71c4dfc2b576d761c5783ce735022100eea66ba382d00e628d86fc5bc1928a93765e26fd8252c4d01efe22147c12b91a01410458fec9d580b0c6842cae00aecd96e89af3ff56f5be49dae425046e64057e0f499acc35ec10e1b544e0f01072296c6fa60a68ea515e59d24ff794cf8923cd30f4') self.assertEqual(actualDD['vin'][0]['vout'], 1) self.assertEqual(actualDD['vin'][0]['txid'], '04b865ecf5fca3a56f6ce73a571a09a668f4b7aa5a7547a5f51fae08eadcdbb5') self.assertEqual(len(actualDD['vout']), 2) self.assertEqual(actualDD['vout'][0]['value'], 20.0) self.assertEqual(actualDD['vout'][0]['n'], 0) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['reqSigs'], 1) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['hex'], '76a91462d978319c7d7ac6cceed722c3d08aa81b37101288ac') self.assertEqual(actualDD['vout'][0]['scriptPubKey']['addresses'], ['mpXd2u8fPVYdL1Nf9bZ4EFnqhkNyghGLxL']) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['asm'], expectScriptStr) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][1]['scriptPubKey']['type'], 'Standard (PKH)') def testDumpprivkey(self): testPrivKey = self.privKey.toBinStr() hash160 = convertKeyDataToAddress(testPrivKey) addr58 = hash160_to_addrStr(hash160) # Verify that a bogus addrss Raises InvalidBitcoinAddress Exception result = self.jsonServer.jsonrpc_dumpprivkey('bogus', 'hex') self.assertEqual(result['Error Type'],'InvalidBitcoinAddress') result = self.jsonServer.jsonrpc_dumpprivkey(addr58, 'hex') self.assertEqual(result['Error Type'],'PrivateKeyNotFound') # verify that the first private key can be found firstHash160 = self.wallet.getNextUnusedAddress().getAddr160() firstAddr58 = hash160_to_addrStr(firstHash160) actualPrivateKeyHex = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58, \ 'hex') actualPrivateKeyB58 = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58, \ 'base58') self.privKey = self.wallet.getAddrByHash160(firstHash160).serializePlainPrivateKey() expectedPrivateKeyHex = binary_to_hex(self.privKey) expectedPrivateKeyB58 = privKey_to_base58(self.privKey) self.assertEqual(actualPrivateKeyHex, expectedPrivateKeyHex) self.assertEqual(actualPrivateKeyB58, expectedPrivateKeyB58) # Verify that a locked wallet Raises WalletUnlockNeeded Exception kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.wallet.changeWalletEncryption( securePassphrase=self.passphrase ) self.wallet.lock() result = self.jsonServer.jsonrpc_dumpprivkey(addr58, 'hex') self.assertEqual(result['Error Type'],'WalletUnlockNeeded') def testEncryptwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) # Verify that a locked wallet Raises WalletUnlockNeeded Exception # self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_encryptwallet, PASSPHRASE1) result = self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) print result def testUnlockwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) self.jsonServer.jsonrpc_walletpassphrase(PASSPHRASE1, UNLOCK_TIMEOUT) self.assertFalse(self.wallet.isLocked) time.sleep(UNLOCK_TIMEOUT+1) self.wallet.checkWalletLockTimeout() self.assertTrue(self.wallet.isLocked) def testGetWalletInfo(self): wltInfo = self.jsonServer.jsonrpc_getwalletinfo() self.assertEqual(wltInfo['name'], TEST_WALLET_NAME) self.assertEqual(wltInfo['description'], TEST_WALLET_DESCRIPTION) self.assertEqual(wltInfo['balance'], AmountToJSON(self.wallet.getBalance('Spend'))) self.assertEqual(wltInfo['keypoolsize'], self.wallet.addrPoolSize) self.assertEqual(wltInfo['numaddrgen'], len(self.wallet.addrMap)) self.assertEqual(wltInfo['highestusedindex'], self.wallet.highestUsedChainIndex) # This should always return 0 balance # Need to create our own test net to test with balances def testGetBalance(self): for ballanceType in ['spendable','spend', 'unconf', \ 'unconfirmed', 'total', 'ultimate','unspent', 'full']: self.assertEqual(self.jsonServer.jsonrpc_getbalance(ballanceType), AmountToJSON(self.wallet.getBalance(ballanceType)))
class ArmoryDTest(TiabTest): def removeFileList(self, fileList): for f in fileList: if os.path.exists(f): os.remove(f) def armoryDTestCallback(self, action, args): if action == REFRESH_ACTION: self.walletIsScanned = True def setUp(self): self.verifyBlockHeight() self.fileA = os.path.join(self.armoryHomeDir, 'armory_%s_.wallet' % TEST_WALLET_ID) self.fileB = os.path.join(self.armoryHomeDir, 'armory_%s_backup.wallet' % TEST_WALLET_ID) self.fileAupd = os.path.join( self.armoryHomeDir, 'armory_%s_backup_unsuccessful.wallet' % TEST_WALLET_ID) self.fileBupd = os.path.join( self.armoryHomeDir, 'armory_%s_update_unsuccessful.wallet' % TEST_WALLET_ID) self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # We need a controlled test, so we script the all the normally-random stuff self.privKey = SecureBinaryData('\xaa' * 32) self.privKey2 = SecureBinaryData('\x33' * 32) self.chainstr = SecureBinaryData('\xee' * 32) theIV = SecureBinaryData(hex_to_binary('77' * 16)) self.passphrase = SecureBinaryData('A self.passphrase') self.passphrase2 = SecureBinaryData('A new self.passphrase') #register a callback TheBDM.registerCppNotification(self.armoryDTestCallback) #flag to check on wallet scan status self.walletIsScanned = False #create the wallet self.wallet = PyBtcWallet().createNewWallet(withEncrypt=False, \ plainRootKey=self.privKey, \ chaincode=self.chainstr, \ IV=theIV, \ shortLabel=TEST_WALLET_NAME, \ longLabel=TEST_WALLET_DESCRIPTION, armoryHomeDir = self.armoryHomeDir) self.jsonServer = Armory_Json_Rpc_Server(self.wallet) #register it self.wallet.registerWallet() #wait on scan for 2 min then raise if the scan hasn't finished yet i = 0 while not self.walletIsScanned: time.sleep(0.5) i += 1 if i >= 60 * 4: raise RuntimeError( "Timeout waiting for TheBDM to register the wallet.") def tearDown(self): TheBDM.unregisterCppNotification(self.armoryDTestCallback) self.wallet.unregisterWallet() self.removeFileList( [self.fileA, self.fileB, self.fileAupd, self.fileBupd]) # Can't test with actual transactions in this environment. See ARMORY-34. # This wallet has no txs # def testListunspent(self): # actualResult = self.jsonServer.jsonrpc_listunspent() # self.assertEqual(actualResult, []) def testImportprivkey(self): originalLength = len(self.wallet.linearAddr160List) self.jsonServer.jsonrpc_importprivkey( binary_to_hex(self.privKey2.toBinStr())) self.assertEqual(len(self.wallet.linearAddr160List), originalLength + 1) # Requires Supernode @SkipTest def testGettxout(self): txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 0) self.assertEquals(txOut['value'], TX_ID1_OUTPUT0_VALUE) txOut = self.jsonServer.jsonrpc_gettxout(TX_ID1, 1) self.assertEquals(txOut['value'], TX_ID1_OUTPUT1_VALUE) def testGetreceivedbyaddress(self): a160 = hash160( self.wallet.getNextUnusedAddress().binPublicKey65.toBinStr()) testAddr = hash160_to_addrStr(a160) result = self.jsonServer.jsonrpc_getreceivedbyaddress(testAddr) self.assertEqual(result, 0) # Requires Supernode @SkipTest def testGetrawtransaction(self): actualRawTx = self.jsonServer.jsonrpc_getrawtransaction(TX_ID1) pyTx = PyTx().unserialize(hex_to_binary(actualRawTx)) self.assertEquals(TX_ID1, binary_to_hex(pyTx.getHash(), BIGENDIAN)) def testBackupWallet(self): backupTestPath = os.path.join( self.armoryHomeDir, 'armory_%s_.wallet.backup.test' % TEST_WALLET_ID) # Remove backupTestPath in case it exists backupFileList = [backupTestPath, self.fileB] self.removeFileList(backupFileList) # Remove the backup test path that is to be created after tear down. self.addCleanup(self.removeFileList, backupFileList) self.jsonServer.jsonrpc_backupwallet(backupTestPath) self.assertTrue(os.path.exists(backupTestPath)) self.wallet.backupWalletFile() self.assertTrue(os.path.exists(self.fileB)) def testDecoderawtransaction(self): actualDD = self.jsonServer.jsonrpc_decoderawtransaction(RAW_TX1) # Test specific values pulled from bitcoin daemon's output for the test raw TX expectScriptStr = 'OP_DUP OP_HASH160 PUSHDATA(20) [62d978319c7d7ac6cceed722c3d08aa81b371012] OP_EQUALVERIFY OP_CHECKSIG' self.assertEqual(actualDD['locktime'], 0) self.assertEqual(actualDD['version'], 1) self.assertEqual(len(actualDD['vin']), 1) self.assertEqual(actualDD['vin'][0]['sequence'], 4294967295L) self.assertEqual( actualDD['vin'][0]['scriptSig']['hex'], '4830450220081341a4e803c7c8e64c3a3fd285dca34c9f7c71c4dfc2b576d761c5783ce735022100eea66ba382d00e628d86fc5bc1928a93765e26fd8252c4d01efe22147c12b91a01410458fec9d580b0c6842cae00aecd96e89af3ff56f5be49dae425046e64057e0f499acc35ec10e1b544e0f01072296c6fa60a68ea515e59d24ff794cf8923cd30f4' ) self.assertEqual(actualDD['vin'][0]['vout'], 1) self.assertEqual( actualDD['vin'][0]['txid'], '04b865ecf5fca3a56f6ce73a571a09a668f4b7aa5a7547a5f51fae08eadcdbb5') self.assertEqual(len(actualDD['vout']), 2) self.assertEqual(actualDD['vout'][0]['value'], 20.0) self.assertEqual(actualDD['vout'][0]['n'], 0) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['reqSigs'], 1) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['hex'], '76a91462d978319c7d7ac6cceed722c3d08aa81b37101288ac') self.assertEqual(actualDD['vout'][0]['scriptPubKey']['addresses'], ['mpXd2u8fPVYdL1Nf9bZ4EFnqhkNyghGLxL']) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['asm'], expectScriptStr) self.assertEqual(actualDD['vout'][0]['scriptPubKey']['type'], 'Standard (PKH)') self.assertEqual(actualDD['vout'][1]['scriptPubKey']['type'], 'Standard (PKH)') def testDumpprivkey(self): testPrivKey = self.privKey.toBinStr() hash160 = convertKeyDataToAddress(testPrivKey) addr58 = hash160_to_addrStr(hash160) # Verify that a bogus addrss Raises InvalidBitcoinAddress Exception result = self.jsonServer.jsonrpc_dumpprivkey('bogus', 'hex') self.assertEqual(result['Error Type'], 'InvalidBitcoinAddress') result = self.jsonServer.jsonrpc_dumpprivkey(addr58, 'hex') self.assertEqual(result['Error Type'], 'PrivateKeyNotFound') # verify that the first private key can be found firstHash160 = self.wallet.getNextUnusedAddress().getAddr160() firstAddr58 = hash160_to_addrStr(firstHash160) actualPrivateKeyHex = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58, \ 'hex') actualPrivateKeyB58 = self.jsonServer.jsonrpc_dumpprivkey(firstAddr58, \ 'base58') self.privKey = self.wallet.getAddrByHash160( firstHash160).serializePlainPrivateKey() expectedPrivateKeyHex = binary_to_hex(self.privKey) expectedPrivateKeyB58 = privKey_to_base58(self.privKey) self.assertEqual(actualPrivateKeyHex, expectedPrivateKeyHex) self.assertEqual(actualPrivateKeyB58, expectedPrivateKeyB58) # Verify that a locked wallet Raises WalletUnlockNeeded Exception kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.wallet.changeWalletEncryption(securePassphrase=self.passphrase) self.wallet.lock() result = self.jsonServer.jsonrpc_dumpprivkey(addr58, 'hex') self.assertEqual(result['Error Type'], 'WalletUnlockNeeded') def testEncryptwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) # Verify that a locked wallet Raises WalletUnlockNeeded Exception # self.assertRaises(WalletUnlockNeeded, self.jsonServer.jsonrpc_encryptwallet, PASSPHRASE1) result = self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) print result def testUnlockwallet(self): kdfParams = self.wallet.computeSystemSpecificKdfParams(0.1) self.wallet.changeKdfParams(*kdfParams) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.assertTrue(self.wallet.isLocked) self.jsonServer.jsonrpc_walletpassphrase(PASSPHRASE1, UNLOCK_TIMEOUT) self.assertFalse(self.wallet.isLocked) time.sleep(UNLOCK_TIMEOUT + 1) self.wallet.checkWalletLockTimeout() self.assertTrue(self.wallet.isLocked) def testGetWalletInfo(self): wltInfo = self.jsonServer.jsonrpc_getwalletinfo() self.assertEqual(wltInfo['name'], TEST_WALLET_NAME) self.assertEqual(wltInfo['description'], TEST_WALLET_DESCRIPTION) self.assertEqual(wltInfo['balance'], AmountToJSON(self.wallet.getBalance('Spend'))) self.assertEqual(wltInfo['keypoolsize'], self.wallet.addrPoolSize) self.assertEqual(wltInfo['numaddrgen'], len(self.wallet.addrMap)) self.assertEqual(wltInfo['highestusedindex'], self.wallet.highestUsedChainIndex) # This should always return 0 balance # Need to create our own test net to test with balances def testGetBalance(self): for ballanceType in ['spendable','spend', 'unconf', \ 'unconfirmed', 'total', 'ultimate','unspent', 'full']: self.assertEqual( self.jsonServer.jsonrpc_getbalance(ballanceType), AmountToJSON(self.wallet.getBalance(ballanceType)))
def readBitcoinConf(self, makeIfDNE=False): LOGINFO('Reading bitcoin.conf file') bitconf = os.path.join( self.satoshiHome, 'bitcoin.conf' ) if not os.path.exists(bitconf): if not makeIfDNE: raise self.BitcoinDotConfError, 'Could not find bitcoin.conf' else: LOGINFO('No bitcoin.conf available. Creating it...') touchFile(bitconf) # Guarantee that bitcoin.conf file has very strict permissions if OS_WINDOWS: if OS_VARIANT[0].lower()=='xp': LOGERROR('Cannot set permissions correctly in XP!') LOGERROR('Please confirm permissions on the following file ') LOGERROR('are set to exclusive access only for your user ') LOGERROR('(it usually is, but Armory cannot guarantee it ') LOGERROR('on XP systems):') LOGERROR(' %s', bitconf) else: LOGINFO('Setting permissions on bitcoin.conf') import win32api username = win32api.GetUserName() LOGINFO('Setting permissions on bitcoin.conf') cmd_icacls = ['icacls',bitconf,'/inheritance:r','/grant:r', '%s:F' % username] icacls_out = subprocess_check_output(cmd_icacls, shell=True) LOGINFO('icacls returned: %s', icacls_out) else: LOGINFO('Setting permissions on bitcoin.conf') os.chmod(bitconf, stat.S_IRUSR | stat.S_IWUSR) with open(bitconf,'r') as f: # Find the last character of the each line: either a newline or '#' endchr = lambda line: line.find('#') if line.find('#')>1 else len(line) # Reduce each line to a list of key,value pairs separated with '=' allconf = [l[:endchr(l)].strip().split('=') for l in f.readlines()] # Need to convert to (x[0],x[1:]) in case the password has '=' in it allconfPairs = [[x[0], '='.join(x[1:])] for x in allconf if len(x)>1] # Convert the list of pairs to a dictionary self.bitconf = dict(allconfPairs) # Look for rpcport, use default if not there self.bitconf['rpcport'] = int(self.bitconf.get('rpcport', BITCOIN_RPC_PORT)) # We must have a username and password. If not, append to file if not self.bitconf.has_key('rpcuser'): LOGDEBUG('No rpcuser: creating one') with open(bitconf,'a') as f: f.write('\n') f.write('rpcuser=generated_by_armory\n') self.bitconf['rpcuser'] = '******' if not self.bitconf.has_key('rpcpassword'): LOGDEBUG('No rpcpassword: creating one') with open(bitconf,'a') as f: randBase58 = SecureBinaryData().GenerateRandom(32).toBinStr() randBase58 = binary_to_base58(randBase58) f.write('\n') f.write('rpcpassword=%s' % randBase58) self.bitconf['rpcpassword'] = randBase58 if not isASCII(self.bitconf['rpcuser']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcuser)!') if not isASCII(self.bitconf['rpcpassword']): LOGERROR('Non-ASCII character in bitcoin.conf (rpcpassword)!') self.bitconf['host'] = '127.0.0.1'
def testPyBtcWallet(self): self.wlt.addrPoolSize = 5 # No block chain loaded so this should return -1 # self.assertEqual(self.wlt.detectHighestUsedIndex(True), -1) self.assertEqual(self.wlt.kdfKey, None) self.assertEqual(binary_to_hex(self.wlt.addrMap['ROOT'].addrStr20), WALLET_ROOT_ADDR) ############################################################################# # (1) Getting a new address: newAddr = self.wlt.getNextUnusedAddress() self.wlt.pprint(indent=' ' * 5) self.assertEqual(binary_to_hex(newAddr.addrStr20), NEW_UNUSED_ADDR) # (1) Re-reading wallet from file, compare the two wallets wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) self.assertTrue(self.wlt.isEqualTo(wlt2)) ############################################################################# # (2)Testing unencrypted wallet import-address' originalLength = len(self.wlt.linearAddr160List) self.wlt.importExternalAddressData(privKey=self.privKey2) self.assertEqual(len(self.wlt.linearAddr160List), originalLength + 1) # (2) Re-reading wallet from file, compare the two wallets wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) self.assertTrue(self.wlt.isEqualTo(wlt2)) # (2a)Testing deleteImportedAddress # Wallet size before delete:', os.path.getsize(self.wlt.walletPath) # Addresses before delete:', len(self.wlt.linearAddr160List) toDelete160 = convertKeyDataToAddress(self.privKey2) self.wlt.deleteImportedAddress(toDelete160) self.assertEqual(len(self.wlt.linearAddr160List), originalLength) # (2a) Reimporting address for remaining tests # Wallet size before reimport:', os.path.getsize(self.wlt.walletPath) self.wlt.importExternalAddressData(privKey=self.privKey2) self.assertEqual(len(self.wlt.linearAddr160List), originalLength + 1) # (2b)Testing ENCRYPTED wallet import-address privKey3 = SecureBinaryData('\xbb' * 32) privKey4 = SecureBinaryData('\x44' * 32) self.chainstr2 = SecureBinaryData('\xdd' * 32) theIV2 = SecureBinaryData(hex_to_binary('66' * 16)) self.passphrase2 = SecureBinaryData('hello') wltE = PyBtcWallet().createNewWallet(withEncrypt=True, \ plainRootKey=privKey3, \ securePassphrase=self.passphrase2, \ chaincode=self.chainstr2, \ IV=theIV2, \ shortLabel=self.shortlabel) # We should have thrown an error about importing into a locked wallet... self.assertRaises(WalletLockError, wltE.importExternalAddressData, privKey=self.privKey2) wltE.unlock(securePassphrase=self.passphrase2) wltE.importExternalAddressData(privKey=self.privKey2) # (2b) Re-reading wallet from file, compare the two wallets wlt2 = PyBtcWallet().readWalletFile(wltE.walletPath) self.assertTrue(wltE.isEqualTo(wlt2)) # (2b) Unlocking wlt2 after re-reading locked-import-wallet wlt2.unlock(securePassphrase=self.passphrase2) self.assertFalse(wlt2.isLocked) ############################################################################# # Now play with encrypted wallets # *********************************************************************' # (3)Testing conversion to encrypted wallet kdfParams = self.wlt.computeSystemSpecificKdfParams(0.1) self.wlt.changeKdfParams(*kdfParams) self.assertEqual(self.wlt.kdf.getSalt(), kdfParams[2]) self.wlt.changeWalletEncryption(securePassphrase=self.passphrase) self.assertEqual(self.wlt.kdf.getSalt(), kdfParams[2]) # (3) Re-reading wallet from file, compare the two wallets' wlt2 = PyBtcWallet().readWalletFile(self.wlt.getWalletPath()) self.assertTrue(self.wlt.isEqualTo(wlt2)) # NOTE: this isEqual operation compares the serializations # of the wallet addresses, which only contains the # encrypted versions of the private keys. However, # self.wlt is unlocked and contains the plaintext keys, too # while wlt2 does not. self.wlt.lock() for key in self.wlt.addrMap: self.assertTrue(self.wlt.addrMap[key].isLocked) self.assertEqual( self.wlt.addrMap[key].binPrivKey32_Plain.toHexStr(), '') ############################################################################# # (4)Testing changing self.passphrase on encrypted wallet', self.wlt.unlock(securePassphrase=self.passphrase) for key in self.wlt.addrMap: self.assertFalse(self.wlt.addrMap[key].isLocked) self.assertNotEqual( self.wlt.addrMap[key].binPrivKey32_Plain.toHexStr(), '') # ...to same self.passphrase' origKdfKey = self.wlt.kdfKey self.wlt.changeWalletEncryption(securePassphrase=self.passphrase) self.assertEqual(origKdfKey, self.wlt.kdfKey) # (4)And now testing new self.passphrase...' self.wlt.changeWalletEncryption(securePassphrase=self.passphrase2) self.assertNotEqual(origKdfKey, self.wlt.kdfKey) # (4) Re-reading wallet from file, compare the two wallets' wlt2 = PyBtcWallet().readWalletFile(self.wlt.getWalletPath()) self.assertTrue(self.wlt.isEqualTo(wlt2)) ############################################################################# # (5)Testing changing KDF on encrypted wallet' self.wlt.unlock(securePassphrase=self.passphrase2) MEMORY_REQT_BYTES = 1024 NUM_ITER = 999 SALT_ALL_0 = '00' * 32 self.wlt.changeKdfParams(MEMORY_REQT_BYTES, NUM_ITER, hex_to_binary(SALT_ALL_0), self.passphrase2) self.assertEqual(self.wlt.kdf.getMemoryReqtBytes(), MEMORY_REQT_BYTES) self.assertEqual(self.wlt.kdf.getNumIterations(), NUM_ITER) self.assertEqual(self.wlt.kdf.getSalt().toHexStr(), SALT_ALL_0) self.wlt.changeWalletEncryption(securePassphrase=self.passphrase2) # I don't know why this shouldn't be '' # Commenting out because it's a broken assertion # self.assertNotEqual(origKdfKey.toHexStr(), '') # (5) Get new address from locked wallet' # Locking wallet' self.wlt.lock() for i in range(10): self.wlt.getNextUnusedAddress() self.assertEqual(len(self.wlt.addrMap), originalLength + 13) # (5) Re-reading wallet from file, compare the two wallets' wlt2 = PyBtcWallet().readWalletFile(self.wlt.getWalletPath()) self.assertTrue(self.wlt.isEqualTo(wlt2)) ############################################################################# # !!! #forkOnlineWallet() # (6)Testing forking encrypted wallet for online mode' self.wlt.forkOnlineWallet('OnlineVersionOfEncryptedWallet.bin') wlt2.readWalletFile('OnlineVersionOfEncryptedWallet.bin') for key in wlt2.addrMap: self.assertTrue(self.wlt.addrMap[key].isLocked) self.assertEqual( self.wlt.addrMap[key].binPrivKey32_Plain.toHexStr(), '') # (6)Getting a new addresses from both wallets' for i in range(self.wlt.addrPoolSize * 2): self.wlt.getNextUnusedAddress() wlt2.getNextUnusedAddress() newaddr1 = self.wlt.getNextUnusedAddress() newaddr2 = wlt2.getNextUnusedAddress() self.assertTrue(newaddr1.getAddr160() == newaddr2.getAddr160()) self.assertEqual(len(wlt2.addrMap), 3 * originalLength + 14) # (6) Re-reading wallet from file, compare the two wallets wlt3 = PyBtcWallet().readWalletFile( 'OnlineVersionOfEncryptedWallet.bin') self.assertTrue(wlt3.isEqualTo(wlt2)) ############################################################################# # (7)Testing removing wallet encryption' # Wallet is locked? ', self.wlt.isLocked self.wlt.unlock(securePassphrase=self.passphrase2) self.wlt.changeWalletEncryption(None) for key in self.wlt.addrMap: self.assertFalse(self.wlt.addrMap[key].isLocked) self.assertNotEqual( self.wlt.addrMap[key].binPrivKey32_Plain.toHexStr(), '') # (7) Re-reading wallet from file, compare the two wallets' wlt2 = PyBtcWallet().readWalletFile(self.wlt.getWalletPath()) self.assertTrue(self.wlt.isEqualTo(wlt2)) ############################################################################# # \n' # *********************************************************************' # (8)Doing interrupt tests to test wallet-file-update recovery' def hashfile(fn): f = open(fn, 'r') d = hash256(f.read()) f.close() return binary_to_hex(d[:8]) def verifyFileStatus(fileAExists = True, fileBExists = True, \ fileAupdExists = True, fileBupdExists = True): self.assertEqual(os.path.exists(self.fileA), fileAExists) self.assertEqual(os.path.exists(self.fileB), fileBExists) self.assertEqual(os.path.exists(self.fileAupd), fileAupdExists) self.assertEqual(os.path.exists(self.fileBupd), fileBupdExists) correctMainHash = hashfile(self.fileA) try: self.wlt.interruptTest1 = True self.wlt.getNextUnusedAddress() except InterruptTestError: # Interrupted!' pass self.wlt.interruptTest1 = False # (8a)Interrupted getNextUnusedAddress on primary file update' verifyFileStatus(True, True, False, True) # (8a)Do consistency check on the wallet' self.wlt.doWalletFileConsistencyCheck() verifyFileStatus(True, True, False, False) self.assertEqual(correctMainHash, hashfile(self.fileA)) try: self.wlt.interruptTest2 = True self.wlt.getNextUnusedAddress() except InterruptTestError: # Interrupted!' pass self.wlt.interruptTest2 = False # (8b)Interrupted getNextUnusedAddress on between primary/backup update' verifyFileStatus(True, True, True, True) # (8b)Do consistency check on the wallet' self.wlt.doWalletFileConsistencyCheck() verifyFileStatus(True, True, False, False) self.assertEqual(hashfile(self.fileA), hashfile(self.fileB)) # (8c) Try interrupting at state 3' verifyFileStatus(True, True, False, False) try: self.wlt.interruptTest3 = True self.wlt.getNextUnusedAddress() except InterruptTestError: # Interrupted!' pass self.wlt.interruptTest3 = False # (8c)Interrupted getNextUnusedAddress on backup file update' verifyFileStatus(True, True, True, False) # (8c)Do consistency check on the wallet' self.wlt.doWalletFileConsistencyCheck() verifyFileStatus(True, True, False, False) self.assertEqual(hashfile(self.fileA), hashfile(self.fileB)) ############################################################################# # \n' # *********************************************************************' # (9)Checksum-based byte-error correction tests!' # (9)Start with a good primary and backup file...' # (9a)Open primary wallet, change second byte in KDF' wltfile = open(self.wlt.walletPath, 'r+b') wltfile.seek(326) wltfile.write('\xff') wltfile.close() # (9a)Byte changed, file hashes:' verifyFileStatus(True, True, False, False) # (9a)Try to read wallet from file, should correct KDF error, write fix' wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) verifyFileStatus(True, True, False, False) self.assertNotEqual(hashfile(self.fileA), hashfile(self.fileB)) # \n' # *********************************************************************' # (9b)Change a byte in each checksummed field in root addr' wltfile = open(self.wlt.walletPath, 'r+b') wltfile.seek(838) wltfile.write('\xff') wltfile.seek(885) wltfile.write('\xff') wltfile.seek(929) wltfile.write('\xff') wltfile.seek(954) wltfile.write('\xff') wltfile.seek(1000) wltfile.write('\xff') wltfile.close() # (9b) New file hashes...' verifyFileStatus(True, True, False, False) # (9b)Try to read wallet from file, should correct address errors' wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) verifyFileStatus(True, True, False, False) self.assertNotEqual(hashfile(self.fileA), hashfile(self.fileB)) # \n' # *********************************************************************' # (9c)Change a byte in each checksummed field, of first non-root addr' wltfile = open(self.wlt.walletPath, 'r+b') wltfile.seek(1261 + 21 + 838) wltfile.write('\xff') wltfile.seek(1261 + 21 + 885) wltfile.write('\xff') wltfile.seek(1261 + 21 + 929) wltfile.write('\xff') wltfile.seek(1261 + 21 + 954) wltfile.write('\xff') wltfile.seek(1261 + 21 + 1000) wltfile.write('\xff') wltfile.close() # (9c) New file hashes...' verifyFileStatus(True, True, False, False) # (9c)Try to read wallet from file, should correct address errors' wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) verifyFileStatus(True, True, False, False) self.assertNotEqual(hashfile(self.fileA), hashfile(self.fileB)) # \n' # *********************************************************************' # (9d)Now butcher the CHECKSUM, see if correction works' wltfile = open(self.wlt.walletPath, 'r+b') wltfile.seek(977) wltfile.write('\xff') wltfile.close() # (9d) New file hashes...' verifyFileStatus(True, True, False, False) # (9d)Try to read wallet from file, should correct address errors' wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) verifyFileStatus(True, True, False, False) self.assertNotEqual(hashfile(self.fileA), hashfile(self.fileB)) # *******' # (9z) Test comment I/O' comment1 = 'This is my normal unit-testing address.' comment2 = 'This is fake tx... no tx has this hash.' comment3 = comment1 + ' Corrected!' hash1 = '\x1f' * 20 # address160 hash2 = '\x2f' * 32 # tx hash self.wlt.setComment(hash1, comment1) self.wlt.setComment(hash2, comment2) self.wlt.setComment(hash1, comment3) wlt2 = PyBtcWallet().readWalletFile(self.wlt.walletPath) c3 = wlt2.getComment(hash1) c2 = wlt2.getComment(hash2) self.assertEqual(c3, comment3) self.assertEqual(c2, comment2)
checkAddrStrValid, hash256, UnserializeError, hash160_to_addrStr from armoryengine.PyBtcAddress import PyBtcAddress sys.argv.append('--nologging') INIT_VECTOR = '77'*16 TEST_ADDR1_PRIV_KEY_ENCR1 = '500c41607d79c766859e6d9726ef1ea0fdf095922f3324454f6c4c34abcb23a5' TEST_ADDR1_PRIV_KEY_ENCR2 = '7966cf5886494246cc5aaf7f1a4a2777cd6126612e7029d79ef9df47f6d6927d' TEST_ADDR1_PRIV_KEY_ENCR3 = '0db5c1e9a8d1ebc0525bdb534626033b948804a9a34871d67bf58a3df11d6888' TEST_ADDR1_PRIV_KEY_ENCR4 = '5db1314a20ae9fc978477ab3fe16ab17b246d813a541ecdd4143fcf082b19407' TEST_PUB_KEY1 = '046c35e36776e997883ad4269dcc0696b10d68f6864ae73b8ad6ad03e879e43062a0139095ece3bd653b809fa7e8c7d78ffe6fac75a84c8283d8a000890bfc879d' # Create an address to use for all subsequent tests PRIVATE_KEY = SecureBinaryData(hex_to_binary('aa'*32)) PRIVATE_CHECKSUM = PRIVATE_KEY.getHash256()[:4] PUBLIC_KEY = CryptoECDSA().ComputePublicKey(PRIVATE_KEY) ADDRESS_20 = PUBLIC_KEY.getHash160() TEST_BLOCK_NUM = 100 # We pretend that we plugged some passphrases through a KDF FAKE_KDF_OUTPUT1 = SecureBinaryData( hex_to_binary('11'*32) ) FAKE_KDF_OUTPUT2 = SecureBinaryData( hex_to_binary('22'*32) ) class PyBtcAddressTest(TiabTest): # TODO: This test needs more verification of the results. def testEncryptedAddress(self):