Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 5th, 2012  |  syntax: None  |  size: 3.44 KB  |  hits: 10  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #! /usr/bin/python
  2.  
  3. # ignoblekey.pyw, version 2
  4.  
  5. # To run this program install Python 2.6 from <http://www.python.org/download/>
  6. # Save this script file as ignoblekey.pyw and double-click on it to run it.
  7.  
  8. # Revision history:
  9. #   1 - Initial release
  10. #   2 - Add some missing code
  11.  
  12. """
  13. Retrieve B&N DesktopReader EPUB user AES key.
  14. """
  15.  
  16. from __future__ import with_statement
  17.  
  18. __license__ = 'GPL v3'
  19.  
  20. import sys
  21. import os
  22. import binascii
  23. import glob
  24. import Tkinter
  25. import Tkconstants
  26. import tkMessageBox
  27. import traceback
  28.  
  29. BN_KEY_KEY = 'uhk00000000'
  30. BN_APPDATA_DIR = r'Barnes & Noble\DesktopReader'
  31.  
  32. class IgnobleError(Exception):
  33.     pass
  34.  
  35. def retrieve_key(inpath, outpath):
  36.     # The B&N DesktopReader 'ClientAPI' file is just a sqlite3 DB.  Requiring
  37.     # users to install sqlite3 and bindings seems like overkill for retrieving
  38.     # one value, so we go in hot and dirty.
  39.     with open(inpath, 'rb') as f:
  40.         data = f.read()
  41.     if BN_KEY_KEY not in data:
  42.         raise IgnobleError('B&N user key not found; unexpected DB format?')
  43.     index = data.rindex(BN_KEY_KEY) + len(BN_KEY_KEY) + 1
  44.     data = data[index:index + 40]
  45.     for i in xrange(20, len(data)):
  46.         try:
  47.             keyb64 = data[:i]
  48.             if len(keyb64.decode('base64')) == 20:
  49.                 break
  50.         except binascii.Error:
  51.             pass
  52.     else:
  53.         raise IgnobleError('Problem decoding key; unexpected DB format?')
  54.     with open(outpath, 'wb') as f:
  55.         f.write(keyb64 + '\n')
  56.  
  57. def cli_main(argv=sys.argv):
  58.     progname = os.path.basename(argv[0])
  59.     args = argv[1:]
  60.     if len(args) != 2:
  61.         sys.stderr.write("USAGE: %s CLIENTDB KEYFILE" % (progname,))
  62.         return 1
  63.     inpath, outpath = args
  64.     retrieve_key(inpath, outpath)
  65.     return 0
  66.  
  67. def find_bnclientdb_path():
  68.     appdata = os.environ['APPDATA']
  69.     bndir = os.path.join(appdata, BN_APPDATA_DIR)
  70.     if not os.path.isdir(bndir):
  71.         raise IgnobleError('Could not locate B&N Reader installation')
  72.     dbpath = glob.glob(os.path.join(bndir, 'ClientAPI_*.db'))
  73.     if len(dbpath) == 0:
  74.         raise IgnobleError('Problem locating B&N Reader DB')
  75.     return sorted(dbpath)[-1]
  76.  
  77. class ExceptionDialog(Tkinter.Frame):
  78.     def __init__(self, root, text):
  79.         Tkinter.Frame.__init__(self, root, border=5)
  80.         label = Tkinter.Label(self, text="Unexpected error:",
  81.                               anchor=Tkconstants.W, justify=Tkconstants.LEFT)
  82.         label.pack(fill=Tkconstants.X, expand=0)
  83.         self.text = Tkinter.Text(self)
  84.         self.text.pack(fill=Tkconstants.BOTH, expand=1)
  85.         self.text.insert(Tkconstants.END, text)
  86.  
  87. def gui_main(argv=sys.argv):
  88.     root = Tkinter.Tk()
  89.     root.withdraw()
  90.     progname = os.path.basename(argv[0])
  91.     keypath = 'bnepubkey.b64'
  92.     try:
  93.         dbpath = find_bnclientdb_path()
  94.         retrieve_key(dbpath, keypath)
  95.     except IgnobleError, e:
  96.         tkMessageBox.showerror("Ignoble Key", "Error: " + str(e))
  97.         return 1
  98.     except Exception:
  99.         root.wm_state('normal')
  100.         root.title('Ignoble Key')
  101.         text = traceback.format_exc()
  102.         ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1)
  103.         root.mainloop()
  104.         return 1
  105.     tkMessageBox.showinfo(
  106.         "Ignoble Key", "Key successfully retrieved to %s" % (keypath))
  107.     return 0
  108.  
  109. if __name__ == '__main__':
  110.     if len(sys.argv) > 1:
  111.         sys.exit(cli_main())
  112.     sys.exit(gui_main())