summaryrefslogtreecommitdiffstats
path: root/DeDRM_plugin/ignoblekeyGenPassHash.py
blob: 65d1733075513b995d8eba93c15cbb660f376711 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# ignoblekeyGenPassHash.py
# Copyright © 2009-2022 i♥cabbages, Apprentice Harper et al.

# Released under the terms of the GNU General Public Licence, version 3
# <http://www.gnu.org/licenses/>

# Windows users: Before running this program, you must first install Python.
#   We recommend ActiveState Python 2.7.X for Windows (x86) from
#   http://www.activestate.com/activepython/downloads.
#   You must also install PyCrypto from
#   http://www.voidspace.org.uk/python/modules.shtml#pycrypto
#   (make certain to install the version for Python 2.7).
#   Then save this script file as ignoblekeygen.pyw and double-click on it to run it.
#
# Mac OS X users: Save this script file as ignoblekeygen.pyw.  You can run this
#   program from the command line (python ignoblekeygen.pyw) or by double-clicking
#   it when it has been associated with PythonLauncher.

# Revision history:
#   1 - Initial release
#   2 - Add OS X support by using OpenSSL when available (taken/modified from ineptepub v5)
#   2.1 - Allow Windows versions of libcrypto to be found
#   2.2 - On Windows try PyCrypto first and then OpenSSL next
#   2.3 - Modify interface to allow use of import
#   2.4 - Improvements to UI and now works in plugins
#   2.5 - Additional improvement for unicode and plugin support
#   2.6 - moved unicode_argv call inside main for Windows DeDRM compatibility
#   2.7 - Work if TkInter is missing
#   2.8 - Fix bug in stand-alone use (import tkFileDialog)
#   3.0 - Added Python 3 compatibility for calibre 5.0
#   3.1 - Remove OpenSSL support, only PyCryptodome is supported now

"""
Generate Barnes & Noble EPUB user key from name and credit card number.
"""

__license__ = 'GPL v3'
__version__ = "3.1"

import sys
import os
import hashlib
import base64

try:
    from Cryptodome.Cipher import AES
except ImportError:
    from Crypto.Cipher import AES

from .utilities import SafeUnbuffered

from .argv_utils import unicode_argv

class IGNOBLEError(Exception):
    pass

def normalize_name(name):
    return ''.join(x for x in name.lower() if x != ' ')


def generate_key(name, ccn):
    # remove spaces and case from name and CC numbers.
    name = normalize_name(name)
    ccn = normalize_name(ccn)

    if type(name)==str:
        name = name.encode('utf-8')
    if type(ccn)==str:
        ccn = ccn.encode('utf-8')

    name = name + b'\x00'
    ccn = ccn + b'\x00'

    name_sha = hashlib.sha1(name).digest()[:16]
    ccn_sha = hashlib.sha1(ccn).digest()[:16]
    both_sha = hashlib.sha1(name + ccn).digest()
    crypt = AES.new(ccn_sha, AES.MODE_CBC, name_sha).encrypt(both_sha + (b'\x0c' * 0x0c))
    userkey = hashlib.sha1(crypt).digest()
    return base64.b64encode(userkey)


def cli_main():
    sys.stdout=SafeUnbuffered(sys.stdout)
    sys.stderr=SafeUnbuffered(sys.stderr)
    argv=unicode_argv("ignoblekeyGenPassHash.py")
    progname = os.path.basename(argv[0])
    if len(argv) != 4:
        print("usage: {0} <Name> <CC#> <keyfileout.b64>".format(progname))
        return 1
    name, ccn, keypath = argv[1:]
    userkey = generate_key(name, ccn)
    open(keypath,'wb').write(userkey)
    return 0


def gui_main():
    try:
        import tkinter
        import tkinter.constants
        import tkinter.messagebox
        import tkinter.filedialog
        import traceback
    except:
        return cli_main()

    class DecryptionDialog(tkinter.Frame):
        def __init__(self, root):
            tkinter.Frame.__init__(self, root, border=5)
            self.status = tkinter.Label(self, text="Enter parameters")
            self.status.pack(fill=tkinter.constants.X, expand=1)
            body = tkinter.Frame(self)
            body.pack(fill=tkinter.constants.X, expand=1)
            sticky = tkinter.constants.E + tkinter.constants.W
            body.grid_columnconfigure(1, weight=2)
            tkinter.Label(body, text="Account Name").grid(row=0)
            self.name = tkinter.Entry(body, width=40)
            self.name.grid(row=0, column=1, sticky=sticky)
            tkinter.Label(body, text="CC#").grid(row=1)
            self.ccn = tkinter.Entry(body, width=40)
            self.ccn.grid(row=1, column=1, sticky=sticky)
            tkinter.Label(body, text="Output file").grid(row=2)
            self.keypath = tkinter.Entry(body, width=40)
            self.keypath.grid(row=2, column=1, sticky=sticky)
            self.keypath.insert(2, "bnepubkey.b64")
            button = tkinter.Button(body, text="...", command=self.get_keypath)
            button.grid(row=2, column=2)
            buttons = tkinter.Frame(self)
            buttons.pack()
            botton = tkinter.Button(
                buttons, text="Generate", width=10, command=self.generate)
            botton.pack(side=tkinter.constants.LEFT)
            tkinter.Frame(buttons, width=10).pack(side=tkinter.constants.LEFT)
            button = tkinter.Button(
                buttons, text="Quit", width=10, command=self.quit)
            button.pack(side=tkinter.constants.RIGHT)

        def get_keypath(self):
            keypath = tkinter.filedialog.asksaveasfilename(
                parent=None, title="Select B&N ePub key file to produce",
                defaultextension=".b64",
                filetypes=[('base64-encoded files', '.b64'),
                           ('All Files', '.*')])
            if keypath:
                keypath = os.path.normpath(keypath)
                self.keypath.delete(0, tkinter.constants.END)
                self.keypath.insert(0, keypath)
            return

        def generate(self):
            name = self.name.get()
            ccn = self.ccn.get()
            keypath = self.keypath.get()
            if not name:
                self.status['text'] = "Name not specified"
                return
            if not ccn:
                self.status['text'] = "Credit card number not specified"
                return
            if not keypath:
                self.status['text'] = "Output keyfile path not specified"
                return
            self.status['text'] = "Generating..."
            try:
                userkey = generate_key(name, ccn)
            except Exception as e:
                self.status['text'] = "Error: (0}".format(e.args[0])
                return
            open(keypath,'wb').write(userkey)
            self.status['text'] = "Keyfile successfully generated"

    root = tkinter.Tk()
    root.title("Barnes & Noble ePub Keyfile Generator v.{0}".format(__version__))
    root.resizable(True, False)
    root.minsize(300, 0)
    DecryptionDialog(root).pack(fill=tkinter.constants.X, expand=1)
    root.mainloop()
    return 0

if __name__ == '__main__':
    if len(sys.argv) > 1:
        sys.exit(cli_main())
    sys.exit(gui_main())