Example #1
0
 def verifySignature(self):
    try:
       sig, msg = readSigBlock(str(self.signedMessageBlockTextEdit.toPlainText()))
       addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE) )
       self.displayVerifiedBox(addrB58, msg)
       self.messageTextEdit.setPlainText(msg)
    except:   
       self.displayInvalidSignatureMessage()
       raise
Example #2
0
 def verifySignature(self):
    try:
       sig, msg = readSigBlock(str(self.signedMessageBlockTextEdit.toPlainText()))
       addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE) )
       self.displayVerifiedBox(addrB58, msg)
       self.messageTextEdit.setPlainText(msg)
    except:   
       self.displayInvalidSignatureMessage()
       raise
   def parseNotificationText(self, fileText):
      self.notifications = {}

      if fileText is None:
         return None
   

      try:
         if SIGNED_BLOCK_HEAD in fileText:
            fileText = readSigBlock(fileText)[1]
      
         notifyLines = [line.strip() for line in fileText.split('\n')][::-1]
      
      
         currID = ''
         readLongDescr = False
         longDescrAccum = ''
         
         while len(notifyLines) > 0:
      
            line = notifyLines.pop()
      
            if not readLongDescr and (line.startswith('#') or len(line)==0):
               continue
      
            if line.upper().startswith('UNIQUEID'):
               currID = line.split(':')[-1].strip()
               self.notifications[currID] = {}
            elif line.upper().startswith('LONGDESCR'):
               readLongDescr = True
            elif line.startswith("*****"):
               readLongDescr = False
               self.notifications[currID]['LONGDESCR'] = longDescrAccum
               longDescrAccum = ''
            elif readLongDescr:
               if len(line.strip())==0:
                  longDescrAccum += '<br><br>'
               else:
                  longDescrAccum += line.strip() + ' '
            else:
               key = line.split(':')[ 0].strip().upper()
               val = line.split(':')[-1].strip()
               self.notifications[currID][key] = val
   
         return self.getNotificationMap()
      except:
         LOGEXCEPT('Failed to parse notifications')
         return None
   def parseDownloadList(self, fileText):
      self.downloadMap = {}

      if fileText is None:
         return {}
   
      def insertLink(mapObj, urlAndHash, keyList):
         if len(keyList)>1:
            if not keyList[0] in mapObj:
               mapObj[keyList[0]] = {}
            insertLink(mapObj[keyList[0]], urlAndHash, keyList[1:])
         else:
            mapObj[keyList[0]] = urlAndHash
   

      try:
         if SIGNED_BLOCK_HEAD in fileText:
            fileText = readSigBlock(fileText)[1]
   
   
         dlLines = [line.strip() for line in fileText.split('\n')][::-1]
      
         while len(dlLines) > 0:
      
            line = dlLines.pop()
      
            if line.startswith('#') or len(line)==0:
               continue
      
            lineLists  = [pc.split(',') for pc in line.split()[:-2]]
            urlAndHash = line.split()[-2:]
      
            APPLIST, VERLIST, OSLIST, SUBOSLIST, BITLIST = range(5)
   
            for app in lineLists[APPLIST]:
               for ver in lineLists[VERLIST]:
                  for opsys in lineLists[OSLIST]:
                     for subOS in lineLists[SUBOSLIST]:
                        for nbit in lineLists[BITLIST]:
                           insertLink(self.downloadMap, 
                                      urlAndHash, 
                                      [app, ver, opsys, subOS, nbit])
      
      
         return self.getNestedDownloadMap()
      except:
         LOGEXCEPT('Failed to parse downloads')
         return None
Example #5
0
    def parseNotificationText(self, fileText):
        self.notifications = {}

        if fileText is None:
            return None

        try:
            if SIGNED_BLOCK_HEAD in fileText:
                fileText = readSigBlock(fileText)[1]

            notifyLines = [line.strip() for line in fileText.split('\n')][::-1]

            currID = ''
            readLongDescr = False
            longDescrAccum = ''

            while len(notifyLines) > 0:

                line = notifyLines.pop()

                if not readLongDescr and (line.startswith('#')
                                          or len(line) == 0):
                    continue

                if line.upper().startswith('UNIQUEID'):
                    currID = line.split(':')[-1].strip()
                    self.notifications[currID] = {}
                elif line.upper().startswith('LONGDESCR'):
                    readLongDescr = True
                elif line.startswith("*****"):
                    readLongDescr = False
                    self.notifications[currID]['LONGDESCR'] = longDescrAccum
                    longDescrAccum = ''
                elif readLongDescr:
                    if len(line.strip()) == 0:
                        longDescrAccum += '<br><br>'
                    else:
                        longDescrAccum += line.strip() + ' '
                else:
                    key = line.split(':')[0].strip().upper()
                    val = line.split(':')[-1].strip()
                    self.notifications[currID][key] = val

            return self.getNotificationMap()
        except:
            LOGEXCEPT('Failed to parse notifications')
            return None
Example #6
0
    def parseDownloadList(self, fileText):
        self.downloadMap = {}

        if fileText is None:
            return {}

        def insertLink(mapObj, urlAndHash, keyList):
            if len(keyList) > 1:
                if not keyList[0] in mapObj:
                    mapObj[keyList[0]] = {}
                insertLink(mapObj[keyList[0]], urlAndHash, keyList[1:])
            else:
                mapObj[keyList[0]] = urlAndHash

        try:
            if SIGNED_BLOCK_HEAD in fileText:
                fileText = readSigBlock(fileText)[1]

            dlLines = [line.strip() for line in fileText.split('\n')][::-1]

            while len(dlLines) > 0:

                line = dlLines.pop()

                if line.startswith('#') or len(line) == 0:
                    continue

                lineLists = [pc.split(',') for pc in line.split()[:-2]]
                urlAndHash = line.split()[-2:]

                APPLIST, VERLIST, OSLIST, SUBOSLIST, BITLIST = range(5)

                for app in lineLists[APPLIST]:
                    for ver in lineLists[VERLIST]:
                        for opsys in lineLists[OSLIST]:
                            for subOS in lineLists[SUBOSLIST]:
                                for nbit in lineLists[BITLIST]:
                                    insertLink(self.downloadMap, urlAndHash,
                                               [app, ver, opsys, subOS, nbit])

            return self.getNestedDownloadMap()
        except:
            LOGEXCEPT('Failed to parse downloads')
            return None
Example #7
0
   def parseChangelogText(self, fileText):
   
      self.changelog = []

      if fileText is None:
         return None

   
      try:
         if SIGNED_BLOCK_HEAD in fileText:
            fileText = readSigBlock(fileText)[1]
      
         versionLines = [line.strip() for line in fileText.split('\n')][::-1]
         
            
         if len(versionLines)==0:
            return None
      
         # All lines have been stripped already
         while len(versionLines) > 0:
            line = versionLines.pop()
      
            if line.startswith('#') or len(line)==0:
               continue
   
      
            if line.startswith('VERSION') and len(line.split())==2:
               self.changelog.append([line.split(' ')[-1], '', []])
            elif line.upper().startswith('RELEASED'):
               self.changelog[-1][1] = line[8:].strip()
            elif line.startswith('-'):
               featureTitle = line[2:]
               self.changelog[-1][2].append([featureTitle, ''])
            else:
               curr = self.changelog[-1][2][-1][-1]
               self.changelog[-1][2][-1][-1] += ('' if len(curr)==0 else ' ') + line
   
            return self.getChangelog()
      except:
         LOGEXCEPT('Failed to parse changelog')
         return None
Example #8
0
    def parseChangelogText(self, fileText):

        self.changelog = []

        if fileText is None:
            return None

        try:
            if SIGNED_BLOCK_HEAD in fileText:
                fileText = readSigBlock(fileText)[1]

            versionLines = [line.strip()
                            for line in fileText.split('\n')][::-1]

            if len(versionLines) == 0:
                return None

            # All lines have been stripped already
            while len(versionLines) > 0:
                line = versionLines.pop()

                if line.startswith('#') or len(line) == 0:
                    continue

                if line.startswith('VERSION') and len(line.split()) == 2:
                    self.changelog.append([line.split(' ')[-1], '', []])
                elif line.upper().startswith('RELEASED'):
                    self.changelog[-1][1] = line[8:].strip()
                elif line.startswith('-'):
                    featureTitle = line[2:]
                    self.changelog[-1][2].append([featureTitle, ''])
                else:
                    curr = self.changelog[-1][2][-1][-1]
                    self.changelog[-1][2][-1][-1] += ('' if len(curr) == 0 else
                                                      ' ') + line

                return self.getChangelog()
        except:
            LOGEXCEPT('Failed to parse changelog')
            return None
Example #9
0
    def __runFetchSequence(self):
        ##### Always decorate the URL with OS, Armory version on the first run
        digestData = self.__fetchAnnounceDigests(not self.firstSuccess.isSet())

        if len(digestData) == 0:
            LOGWARN('Error fetching announce digest')
            return

        self.firstSuccess.set()

        ##### Digests come in signature blocks.  Verify sig using jasvet.
        try:
            sig, msg = readSigBlock(digestData)
            signAddress = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
            if not signAddress == self.validAddrStr:
                LOGERROR('Announce info carried invalid signature!')
                LOGERROR('Signature addr: %s' % signAddress)
                LOGERROR('Expected  address: %s', self.validAddrStr)
                return
        except:
            LOGEXCEPT('Could not verify data in signed message block')
            return

        # Always rewrite file; it's small and will use mtime for info
        with open(os.path.join(self.fetchDir, 'announce.file'), 'w') as f:
            f.write(digestData)

        ##### We have a valid digest, now parse it
        justDownloadedMap = {}
        for row in [line.split() for line in msg.strip().split('\n')]:
            if len(row) == 3:
                justDownloadedMap[row[0]] = [row[1], row[2]]
            else:
                LOGERROR('Malformed announce matrix: %s' % str(row))
                return

        ##### Check whether any of the hashes have changed
        for key, val in justDownloadedMap.iteritems():
            jdURL, jdHash = val[0], val[1]

            if not (key in self.fileHashMap
                    and self.fileHashMap[key] == jdHash):
                LOGINFO('Changed [ "%s" ] == [%s, %s]', key, jdURL, jdHash)
                newData = self.__fetchFile(jdURL)
                if len(newData) == 0:
                    LOGERROR('Failed downloading announce file : %s', key)
                    return
                newHash = binary_to_hex(sha256(newData))
                if not newHash == jdHash:
                    LOGERROR('Downloaded file hash does not match!')
                    LOGERROR('Hash of downloaded data: %s', newHash)
                    return

                filename = os.path.join(self.fetchDir, key + '.file')
                with open(filename, 'wb') as f:
                    f.write(newData)
                self.lastChange = RightNow()
                self.fileHashMap[key] = jdHash

        ##### Clean up as needed
        if self.forceCheckFlag.isSet():
            self.forceIsFinished.set()
            self.forceCheckFlag.clear()
        self.numConsecutiveExceptions = 0
Example #10
0
print 'Please verify the above data to your satisfaction:'
raw_input('Hit <enter> when ready: ')

doSignFile(announcePath, os.path.join(dstAnnounce, announceName))

print '*' * 80
print open(announcePath, 'r').read()
print '*' * 80

print ''
print 'Verifying files'
for fname, vals in fileMappings.iteritems():
    if 'bootstrap' in fname:
        continue
    with open(os.path.join(dstAnnounce, fname), 'rb') as f:
        sig, msg = readSigBlock(f.read())
        addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
        print 'Sign addr for:', vals[0].ljust(longestID + 3), addrB58

print 'Done!'

################################################################################
# GIT SIGN
gittag = 'v%s%s' % (topVerStr, topVerType)
logprint('*' * 80)
logprint('About to tag and sign git repo with:')
logprint('   Tag:   ' + gittag)
logprint('   User:  '******'   Email: ' + gitemail)

gitmsg = raw_input('Put your commit message here: ')
   def __runFetchSequence(self):
      ##### Always decorate the URL with OS, Armory version on the first run
      digestData = self.__fetchAnnounceDigests(not self.firstSuccess.isSet())
   
      if len(digestData)==0:
         LOGWARN('Error fetching announce digest')
         return

      self.firstSuccess.set()

      ##### Digests come in signature blocks.  Verify sig using jasvet.
      try:
         sig, msg = readSigBlock(digestData)
         signAddress = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
         if not signAddress == self.validAddrStr:
            LOGERROR('Announce info carried invalid signature!')
            LOGERROR('Signature addr: %s' % signAddress)
            LOGERROR('Expected  address: %s', self.validAddrStr)
            return 
      except:
         LOGEXCEPT('Could not verify data in signed message block')
         return

      # Always rewrite file; it's small and will use mtime for info
      with open(os.path.join(self.fetchDir, 'announce.file'), 'w') as f:
         f.write(digestData)


      ##### We have a valid digest, now parse it
      justDownloadedMap = {}
      for row in [line.split() for line in msg.strip().split('\n')]:
         if len(row)==3:
            justDownloadedMap[row[0]] = [row[1], row[2]]
         else:
            LOGERROR('Malformed announce matrix: %s' % str(row))
            return
      
      ##### Check whether any of the hashes have changed
      for key,val in justDownloadedMap.iteritems():
         jdURL,jdHash = val[0],val[1]
         
         if not (key in self.fileHashMap and self.fileHashMap[key]==jdHash):
            LOGINFO('Changed [ "%s" ] == [%s, %s]', key, jdURL, jdHash)
            newData = self.__fetchFile(jdURL)
            if len(newData) == 0:
               LOGERROR('Failed downloading announce file : %s', key)
               return
            newHash = binary_to_hex(sha256(newData))
            if not newHash == jdHash:
               LOGERROR('Downloaded file hash does not match!')
               LOGERROR('Hash of downloaded data: %s', newHash)
               return

            filename = os.path.join(self.fetchDir, key+'.file')
            with open(filename, 'wb') as f:
               f.write(newData)
            self.lastChange = RightNow()
            self.fileHashMap[key] = jdHash

      ##### Clean up as needed
      if self.forceCheckFlag.isSet():
         self.forceIsFinished.set()
         self.forceCheckFlag.clear()
      self.numConsecutiveExceptions = 0
Example #12
0
def signAnnounceFiles(wltPath):

    if len(CLI_ARGS) < 1:
        print 'Must specify a wallet file containing the signing key'
        exit(1)

    wltPath = CLI_ARGS[0]
    if not os.path.exists(wltPath):
        print 'Wallet file was not found (%s)' % wltPath
        exit(1)

    inDir = 'unsignedAnnounce'
    outDir = 'signedAnnounce'

    origDLFile = os.path.join(inDir, 'dllinks.txt')
    newDLFile = os.path.join(inDir, 'dllinks_temp.txt')

    ################################################################################
    ################################################################################
    # We may need to compute some installer hashes
    doComputeDLLinks = (len(CLI_ARGS) > 1)
    if doComputeDLLinks:
        instDir = CLI_ARGS[1]
        if not os.path.exists(instDir):
            print 'Installers dir does not exist!'
            exit(1)

        instFileInfo = {}
        with open('dlmap.txt', 'r') as f:
            dlmapLines = [line.strip() for line in f.readlines()]
            verName, verStr, urlPrefix = dlmapLines[0].split()

            for line in dlmapLines[2:]:
                fn, opsys, osver, osarch = line.replace('%ver', verStr).split()
                instFileInfo[fn] = [opsys, osver, osarch]

        OS, OSVER, OSARCH = range(3)
        with open(newDLFile, 'w') as f:
            # Write the existing data from rawfiles/dllinks into temp file
            f.write(open(origDLFile, 'r').read())
            f.write('\n')

            # Now compute hashes of each installer and write info to temp file
            for fn in os.listdir(instDir):
                fullpath = os.path.join(instDir, fn)
                if not fn in instFileInfo:
                    print 'File in installer directory does not match any in info map'
                    print '   File:', fullpath
                    print '   InfoMap:'
                    for filename in instFileInfo:
                        print '      ', filename
                    exit(1)

                fdata = open(fullpath, 'rb').read()
                fhash = binary_to_hex(sha256(fdata))
                outputStr = [
                    verName, verStr, instFileInfo[fn][OS],
                    instFileInfo[fn][OSVER], instFileInfo[fn][OSARCH],
                    os.path.join(urlPrefix, fn), fhash
                ]
                f.write(' '.join(outputStr) + '\n')
    ################################################################################

    ###
    if CLI_OPTIONS.testAnnounceCode:
        signAddress = '1PpAJyNoocJt38Vcf4AfPffaxo76D4AAEe'
        announceName = 'testannounce.txt'
        pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-testing/'
    else:
        signAddress = '1NWvhByxfTXPYNT4zMBmEY3VL8QJQtQoei'
        announceName = 'announce.txt'
        pathPrefix = 'https://s3.amazonaws.com/bitcoinarmory-media/'

    announcePath = os.path.join(outDir, announceName)

    ###
    wlt = PyBtcWallet().readWalletFile(wltPath)
    if not wlt.hasAddr(signAddress):
        print 'Supplied wallet does not have the correct signing key'
        exit(1)

    print 'Must unlock wallet to sign the announce file...'
    while True:
        passwd = SecureBinaryData(getpass.getpass('Wallet passphrase: '))
        if not wlt.verifyPassphrase(passwd):
            print 'Invalid passphrase!'
            continue
        break

    wlt.unlock(securePassphrase=passwd)
    passwd.destroy()
    addrObj = wlt.getAddrByHash160(addrStr_to_hash160(signAddress)[1])

    def doSignFile(inFile, outFile):
        with open(inFile, 'rb') as f:
            sigBlock = ASv1CS(addrObj.binPrivKey32_Plain.toBinStr(), f.read())

        with open(outFile, 'wb') as f:
            f.write(sigBlock)

    fileMappings = {}
    longestID = 0
    longestURL = 0
    print 'Reading file mapping...'
    with open('announcemap.txt', 'r') as f:
        for line in f.readlines():
            fname, fid = line.strip().split()
            inputPath = os.path.join(inDir, fname)
            if not os.path.exists(inputPath):
                print 'ERROR:  Could not find %s-file (%s)' % (fid, inputPath)
                exit(1)
            print '   Map: %s --> %s' % (fname, fid)

    if os.path.exists(outDir):
        print 'Wiping old, announced files...'
        shutil.rmtree(outDir)
    os.mkdir(outDir)

    print 'Signing and copying files to %s directory...' % outDir
    with open('announcemap.txt', 'r') as f:
        for line in f.readlines():
            fname, fid = line.strip().split()

            inputPath = os.path.join(inDir, fname)
            outputPath = os.path.join(outDir, fname)

            # If we're using a modified DL file
            if fname == 'dllinks.txt' and doComputeDLLinks:
                inputPath = newDLFile

            if fname.endswith('.txt'):
                doSignFile(inputPath, outputPath)
            else:
                shutil.copy(inputPath, outputPath)

            fdata = open(outputPath, 'rb').read()
            fhash = binary_to_hex(sha256(fdata))
            fileMappings[fname] = [fid, fhash]
            longestID = max(longestID, len(fid))
            longestURL = max(longestURL, len(pathPrefix + fname))

    print 'Creating digest file...'
    digestFile = open(announcePath, 'w')

    ###
    for fname, vals in fileMappings.iteritems():
        fid = vals[0].ljust(longestID + 3)
        url = (pathPrefix + fname).ljust(longestURL + 3)
        fhash = vals[1]
        digestFile.write('%s %s %s\n' % (fid, url, fhash))
    digestFile.close()

    print ''
    print '------'
    with open(announcePath, 'r') as f:
        dfile = f.read()
        print dfile
    print '------'

    print 'Please verify the above data to your satisfaction:'
    raw_input('Hit <enter> when ready: ')

    doSignFile(announcePath, os.path.join(outDir, announceName))

    print '*' * 80
    print open(announcePath, 'r').read()
    print '*' * 80

    print ''
    print 'Verifying files'
    for fname, vals in fileMappings.iteritems():
        if 'bootstrap' in fname:
            continue
        with open(os.path.join(outDir, fname), 'rb') as f:
            sig, msg = readSigBlock(f.read())
            addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
            print 'Sign addr for:', vals[0].ljust(longestID + 3), addrB58

    print 'Done!'
doSignFile(announcePath, os.path.join(dstAnnounce, announceName))


print '*'*80
print open(announcePath, 'r').read()
print '*'*80


print ''
print 'Verifying files'
for fname,vals in fileMappings.iteritems():
   if 'bootstrap' in fname:
      continue
   with open(os.path.join(dstAnnounce, fname), 'rb') as f:
      sig,msg = readSigBlock(f.read())
      addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
      print 'Sign addr for:', vals[0].ljust(longestID+3), addrB58
   


print 'Done!'



################################################################################
# GIT SIGN
gittag  = 'v%s%s' % (topVerStr, topVerType)
logprint('*'*80)
logprint('About to tag and sign git repo with:')
logprint('   Tag:   ' + gittag)
def signAnnounceFiles(wltPath):
   
   if len(CLI_ARGS)<1:
      print 'Must specify a wallet file containing the signing key'
      exit(1)
   
   wltPath = CLI_ARGS[0]
   if not os.path.exists(wltPath):
      print 'Wallet file was not found (%s)' % wltPath
      exit(1)
   
   
   inDir = 'unsignedAnnounce'
   outDir = 'signedAnnounce'
   
   origDLFile = os.path.join(inDir, 'dllinks.txt')
   newDLFile = os.path.join(inDir, 'dllinks_temp.txt')
   
   ################################################################################
   ################################################################################
   # We may need to compute some installer hashes
   doComputeDLLinks = (len(CLI_ARGS)>1)
   if doComputeDLLinks:
      instDir = CLI_ARGS[1]
      if not os.path.exists(instDir):
         print 'Installers dir does not exist!'
         exit(1)
   
      instFileInfo = {}
      with open('dlmap.txt','r') as f:
         dlmapLines = [line.strip() for line in f.readlines()]
         verName, verStr, urlPrefix = dlmapLines[0].split()
   
         for line in dlmapLines[2:]:
            fn,opsys,osver,osarch = line.replace('%ver',verStr).split()
            instFileInfo[fn] = [opsys, osver, osarch]
   
      OS,OSVER,OSARCH = range(3)
      with open(newDLFile, 'w') as f:
         # Write the existing data from rawfiles/dllinks into temp file
         f.write(open(origDLFile, 'r').read())
         f.write('\n')
   
         # Now compute hashes of each installer and write info to temp file
         for fn in os.listdir(instDir):
            fullpath = os.path.join(instDir, fn)
            if not fn in instFileInfo:
               print 'File in installer directory does not match any in info map'
               print '   File:', fullpath
               print '   InfoMap:'
               for filename in instFileInfo:
                  print '      ', filename
               exit(1)
               
            fdata = open(fullpath, 'rb').read()
            fhash = binary_to_hex(sha256(fdata))
            outputStr = [verName, 
                         verStr, 
                         instFileInfo[fn][OS], 
                         instFileInfo[fn][OSVER], 
                         instFileInfo[fn][OSARCH], 
                         os.path.join(urlPrefix, fn),                       
                         fhash]
            f.write(' '.join(outputStr) + '\n')
   ################################################################################
            
            
            
            
   
   ###
   if CLI_OPTIONS.testAnnounceCode:
      signAddress  = '1PpAJyNoocJt38Vcf4AfPffaxo76D4AAEe'
      announceName = 'testannounce.txt'
      pathPrefix   = 'https://s3.amazonaws.com/bitcoinarmory-testing/'
   else:
      signAddress  = '1NWvhByxfTXPYNT4zMBmEY3VL8QJQtQoei'
      announceName = 'announce.txt'
      pathPrefix   = 'https://s3.amazonaws.com/bitcoinarmory-media/'
   
   
   announcePath = os.path.join(outDir, announceName)
   
   ###
   wlt = PyBtcWallet().readWalletFile(wltPath)
   if not wlt.hasAddr(signAddress):
      print 'Supplied wallet does not have the correct signing key'
      exit(1)
   
   
   
   print 'Must unlock wallet to sign the announce file...'
   while True:
      passwd = SecureBinaryData(getpass.getpass('Wallet passphrase: '))
      if not wlt.verifyPassphrase(passwd):
         print 'Invalid passphrase!'
         continue
      break
   
   wlt.unlock(securePassphrase=passwd)
   passwd.destroy()
   addrObj = wlt.getAddrByHash160(addrStr_to_hash160(signAddress)[1])
   
   def doSignFile(inFile, outFile):
      with open(inFile, 'rb') as f:
         sigBlock = ASv1CS(addrObj.binPrivKey32_Plain.toBinStr(), f.read())
   
      with open(outFile, 'wb') as f:
         f.write(sigBlock)
   
   
   
   fileMappings = {}
   longestID  = 0
   longestURL = 0
   print 'Reading file mapping...'
   with open('announcemap.txt','r') as f:
      for line in f.readlines():
         fname, fid = line.strip().split()
         inputPath = os.path.join(inDir, fname)
         if not os.path.exists(inputPath):
            print 'ERROR:  Could not find %s-file (%s)' % (fid, inputPath)
            exit(1)
         print '   Map: %s --> %s' % (fname, fid)
         
   
   
   if os.path.exists(outDir):
      print 'Wiping old, announced files...'
      shutil.rmtree(outDir)
   os.mkdir(outDir)
   
   
   
   print 'Signing and copying files to %s directory...' % outDir
   with open('announcemap.txt','r') as f:
      for line in f.readlines():
         fname, fid = line.strip().split()
   
         inputPath = os.path.join(inDir, fname)
         outputPath = os.path.join(outDir, fname)
   
         # If we're using a modified DL file
         if fname=='dllinks.txt' and doComputeDLLinks:
            inputPath = newDLFile
   
         if fname.endswith('.txt'):
            doSignFile(inputPath, outputPath)
         else:
            shutil.copy(inputPath, outputPath)
   
   
         fdata = open(outputPath, 'rb').read()
         fhash = binary_to_hex(sha256(fdata))
         fileMappings[fname] = [fid, fhash]
         longestID  = max(longestID,  len(fid))
         longestURL = max(longestURL, len(pathPrefix+fname))
         
   
   
         
   
   print 'Creating digest file...'
   digestFile = open(announcePath, 'w')
   
   ###
   for fname,vals in fileMappings.iteritems():
      fid   = vals[0].ljust(longestID + 3)
      url   = (pathPrefix + fname).ljust(longestURL + 3)
      fhash = vals[1]
      digestFile.write('%s %s %s\n' % (fid, url, fhash))
   digestFile.close()
   
   
   print ''
   print '------'
   with open(announcePath, 'r') as f:
      dfile = f.read()
      print dfile
   print '------'
   
   print 'Please verify the above data to your satisfaction:'
   raw_input('Hit <enter> when ready: ')
      
   
   
   
   doSignFile(announcePath, os.path.join(outDir, announceName))
   
   
   print '*'*80
   print open(announcePath, 'r').read()
   print '*'*80
   
   
   print ''
   print 'Verifying files'
   for fname,vals in fileMappings.iteritems():
      if 'bootstrap' in fname:
         continue
      with open(os.path.join(outDir, fname), 'rb') as f:
         sig,msg = readSigBlock(f.read())
         addrB58 = verifySignature(sig, msg, 'v1', ord(ADDRBYTE))
         print 'Sign addr for:', vals[0].ljust(longestID+3), addrB58
      
   
   
   print 'Done!'