Esempio n. 1
0
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
Esempio n. 2
0
   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)
Esempio n. 3
0
    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)
Esempio n. 4
0
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
Esempio n. 5
0
    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
Esempio n. 6
0
    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)
Esempio n. 7
0
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
Esempio n. 8
0
    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])
Esempio n. 9
0
 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))
Esempio n. 10
0
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
Esempio n. 11
0
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
Esempio n. 12
0
 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.")
Esempio n. 14
0
    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.")
Esempio n. 15
0
    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)
Esempio n. 16
0
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)
Esempio n. 17
0
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
Esempio n. 18
0
   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)
Esempio n. 20
0
    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
Esempio n. 21
0
    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()
Esempio n. 22
0
    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'
Esempio n. 23
0
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)
Esempio n. 24
0
 def jsonrpc_encryptwallet(self, passphrase):
    if self.wallet.isLocked:
       raise WalletUnlockNeeded
    self.wallet.changeWalletEncryption( securePassphrase=SecureBinaryData(passphrase) )
    self.wallet.lock()
Esempio n. 25
0
   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)
Esempio n. 26
0
 def jsonrpc_unlockwallet(self, passphrase, timeout):
    self.wallet.unlock( securePassphrase=SecureBinaryData(passphrase),
                          tempKeyLifetime=timeout)
Esempio n. 27
0
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)))
Esempio n. 30
0
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)))
Esempio n. 31
0
   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'
Esempio n. 32
0
    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)
Esempio n. 33
0
   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):