summaryrefslogtreecommitdiffstats
path: root/DeDRM_plugin
diff options
context:
space:
mode:
authorNoDRM <[email protected]>2022-08-06 20:13:19 +0200
committerNoDRM <[email protected]>2022-08-06 20:13:19 +0200
commit410e086d0828a906cdc8e8e0f6e58b73dc5de9be (patch)
treec76621fd9bddadf403fc0f17006ee78a5c3e38a8 /DeDRM_plugin
parent9276d77f6328866394fcbc568b843c4d2cdd3065 (diff)
Remove AlfCrypto libraries and perform everything in Python
The old AlfCrypto DLL, SO and DYLIB files are ancient, I don't have the systems to recompile them all, they cause issues on ARM Macs, and I doubt with all the Python improvements over the last years that they have a significant performance advantage. And even if that's the case, nobody is importing hundreds of DRM books at the same time so it shouldn't hurt if some decryptions might take a bit longer.
Diffstat (limited to 'DeDRM_plugin')
-rw-r--r--DeDRM_plugin/__init__.py13
-rw-r--r--DeDRM_plugin/alfcrypto.dllbin70144 -> 0 bytes
-rw-r--r--DeDRM_plugin/alfcrypto.py330
-rw-r--r--DeDRM_plugin/alfcrypto64.dllbin52224 -> 0 bytes
-rw-r--r--DeDRM_plugin/alfcrypto_src.zipbin17393 -> 0 bytes
-rw-r--r--DeDRM_plugin/libalfcrypto.dylibbin87160 -> 0 bytes
-rw-r--r--DeDRM_plugin/libalfcrypto32.sobin23859 -> 0 bytes
-rw-r--r--DeDRM_plugin/libalfcrypto64.sobin33417 -> 0 bytes
-rwxr-xr-xDeDRM_plugin/mobidedrm.py49
-rw-r--r--DeDRM_plugin/subasyncio.py148
10 files changed, 89 insertions, 451 deletions
diff --git a/DeDRM_plugin/__init__.py b/DeDRM_plugin/__init__.py
index eaf505a..913d05e 100644
--- a/DeDRM_plugin/__init__.py
+++ b/DeDRM_plugin/__init__.py
@@ -187,15 +187,12 @@ class DeDRM(FileTypePlugin):
os.mkdir(self.alfdir)
# only continue if we've never run this version of the plugin before
self.verdir = os.path.join(self.maindir,PLUGIN_VERSION)
- if not os.path.exists(self.verdir):
- if iswindows:
- names = ["alfcrypto.dll","alfcrypto64.dll"]
- elif isosx:
- names = ["libalfcrypto.dylib"]
- else:
- names = ["libalfcrypto32.so","libalfcrypto64.so","kindlekey.py","adobekey.py","subasyncio.py"]
+ if not os.path.exists(self.verdir) and not iswindows and not isosx:
+
+ names = ["kindlekey.py","adobekey.py","ignoblekeyNookStudy.py"]
+
lib_dict = self.load_resources(names)
- print("{0} v{1}: Copying needed library files from plugin's zip".format(PLUGIN_NAME, PLUGIN_VERSION))
+ print("{0} v{1}: Copying needed Python scripts from plugin's zip".format(PLUGIN_NAME, PLUGIN_VERSION))
for entry, data in lib_dict.items():
file_path = os.path.join(self.alfdir, entry)
diff --git a/DeDRM_plugin/alfcrypto.dll b/DeDRM_plugin/alfcrypto.dll
deleted file mode 100644
index 26d740d..0000000
--- a/DeDRM_plugin/alfcrypto.dll
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/alfcrypto.py b/DeDRM_plugin/alfcrypto.py
index 5a31d09..ecb7916 100644
--- a/DeDRM_plugin/alfcrypto.py
+++ b/DeDRM_plugin/alfcrypto.py
@@ -8,260 +8,90 @@
# pbkdf2.py Copyright © 2009 Daniel Holth <[email protected]>
# pbkdf2.py This code may be freely used and modified for any purpose.
-import sys, os
import hmac
from struct import pack
import hashlib
-
-# interface to needed routines libalfcrypto
-def _load_libalfcrypto():
- import ctypes
- from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \
- Structure, c_ulong, create_string_buffer, addressof, string_at, cast, sizeof
-
- pointer_size = ctypes.sizeof(ctypes.c_voidp)
- name_of_lib = None
- if sys.platform.startswith('darwin'):
- name_of_lib = 'libalfcrypto.dylib'
- elif sys.platform.startswith('win'):
- if pointer_size == 4:
- name_of_lib = 'alfcrypto.dll'
- else:
- name_of_lib = 'alfcrypto64.dll'
- else:
- if pointer_size == 4:
- name_of_lib = 'libalfcrypto32.so'
- else:
- name_of_lib = 'libalfcrypto64.so'
-
- # hard code to local location for libalfcrypto
- libalfcrypto = os.path.join(sys.path[0],name_of_lib)
- if not os.path.isfile(libalfcrypto):
- libalfcrypto = os.path.join(sys.path[0], 'lib', name_of_lib)
- if not os.path.isfile(libalfcrypto):
- libalfcrypto = os.path.join('.',name_of_lib)
- if not os.path.isfile(libalfcrypto):
- raise Exception('libalfcrypto not found at %s' % libalfcrypto)
-
- libalfcrypto = CDLL(libalfcrypto)
-
- c_char_pp = POINTER(c_char_p)
- c_int_p = POINTER(c_int)
-
-
- def F(restype, name, argtypes):
- func = getattr(libalfcrypto, name)
- func.restype = restype
- func.argtypes = argtypes
- return func
-
- # aes cbc decryption
- #
- # struct aes_key_st {
- # unsigned long rd_key[4 *(AES_MAXNR + 1)];
- # int rounds;
- # };
- #
- # typedef struct aes_key_st AES_KEY;
- #
- # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
- #
- #
- # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
- # const unsigned long length, const AES_KEY *key,
- # unsigned char *ivec, const int enc);
-
- AES_MAXNR = 14
-
- class AES_KEY(Structure):
- _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)]
-
- AES_KEY_p = POINTER(AES_KEY)
- AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p, c_int])
- AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p])
-
-
-
- # Pukall 1 Cipher
- # unsigned char *PC1(const unsigned char *key, unsigned int klen, const unsigned char *src,
- # unsigned char *dest, unsigned int len, int decryption);
-
- PC1 = F(c_char_p, 'PC1', [c_char_p, c_ulong, c_char_p, c_char_p, c_ulong, c_ulong])
-
- # Topaz Encryption
- # typedef struct _TpzCtx {
- # unsigned int v[2];
- # } TpzCtx;
- #
- # void topazCryptoInit(TpzCtx *ctx, const unsigned char *key, int klen);
- # void topazCryptoDecrypt(const TpzCtx *ctx, const unsigned char *in, unsigned char *out, int len);
-
- class TPZ_CTX(Structure):
- _fields_ = [('v', c_long * 2)]
-
- TPZ_CTX_p = POINTER(TPZ_CTX)
- topazCryptoInit = F(None, 'topazCryptoInit', [TPZ_CTX_p, c_char_p, c_ulong])
- topazCryptoDecrypt = F(None, 'topazCryptoDecrypt', [TPZ_CTX_p, c_char_p, c_char_p, c_ulong])
-
-
- class AES_CBC(object):
- def __init__(self):
- self._blocksize = 0
- self._keyctx = None
- self._iv = 0
-
- def set_decrypt_key(self, userkey, iv):
- self._blocksize = len(userkey)
- if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) :
- raise Exception('AES CBC improper key used')
- return
- keyctx = self._keyctx = AES_KEY()
- self._iv = iv
- rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx)
- if rv < 0:
- raise Exception('Failed to initialize AES CBC key')
-
- def decrypt(self, data):
- out = create_string_buffer(len(data))
- mutable_iv = create_string_buffer(self._iv, len(self._iv))
- rv = AES_cbc_encrypt(data, out, len(data), self._keyctx, mutable_iv, 0)
- if rv == 0:
- raise Exception('AES CBC decryption failed')
- return out.raw
-
- class Pukall_Cipher(object):
- def __init__(self):
- self.key = None
-
- def PC1(self, key, src, decryption=True):
- self.key = key
- out = create_string_buffer(len(src))
- de = 0
+import aescbc
+
+class Pukall_Cipher(object):
+ def __init__(self):
+ self.key = None
+
+ def PC1(self, key, src, decryption=True):
+ sum1 = 0;
+ sum2 = 0;
+ keyXorVal = 0;
+ if len(key)!=16:
+ raise Exception("PC1: Bad key length")
+ wkey = []
+ for i in range(8):
+ wkey.append(key[i*2]<<8 | key[i*2+1])
+ dst = bytearray(len(src))
+ for i in range(len(src)):
+ temp1 = 0;
+ byteXorVal = 0;
+ for j in range(8):
+ temp1 ^= wkey[j]
+ sum2 = (sum2+j)*20021 + sum1
+ sum1 = (temp1*346)&0xFFFF
+ sum2 = (sum2+sum1)&0xFFFF
+ temp1 = (temp1*20021+1)&0xFFFF
+ byteXorVal ^= temp1 ^ sum2
+ curByte = src[i]
+ if not decryption:
+ keyXorVal = curByte * 257;
+ curByte = ((curByte ^ (byteXorVal >> 8)) ^ byteXorVal) & 0xFF
if decryption:
- de = 1
- rv = PC1(key, len(key), src, out, len(src), de)
- return out.raw
-
- class Topaz_Cipher(object):
- def __init__(self):
- self._ctx = None
-
- def ctx_init(self, key):
- tpz_ctx = self._ctx = TPZ_CTX()
- topazCryptoInit(tpz_ctx, key, len(key))
- return tpz_ctx
-
- def decrypt(self, data, ctx=None):
- if ctx == None:
- ctx = self._ctx
- out = create_string_buffer(len(data))
- topazCryptoDecrypt(ctx, data, out, len(data))
- return out.raw
-
- print("Using Library AlfCrypto DLL/DYLIB/SO")
- return (AES_CBC, Pukall_Cipher, Topaz_Cipher)
-
-
-def _load_python_alfcrypto():
-
- import aescbc
-
- class Pukall_Cipher(object):
- def __init__(self):
- self.key = None
-
- def PC1(self, key, src, decryption=True):
- sum1 = 0;
- sum2 = 0;
- keyXorVal = 0;
- if len(key)!=16:
- raise Exception('Pukall_Cipher: Bad key length.')
- wkey = []
- for i in range(8):
- wkey.append(ord(key[i*2])<<8 | ord(key[i*2+1]))
- dst = ""
- for i in range(len(src)):
- temp1 = 0;
- byteXorVal = 0;
- for j in range(8):
- temp1 ^= wkey[j]
- sum2 = (sum2+j)*20021 + sum1
- sum1 = (temp1*346)&0xFFFF
- sum2 = (sum2+sum1)&0xFFFF
- temp1 = (temp1*20021+1)&0xFFFF
- byteXorVal ^= temp1 ^ sum2
- curByte = ord(src[i])
- if not decryption:
- keyXorVal = curByte * 257;
- curByte = ((curByte ^ (byteXorVal >> 8)) ^ byteXorVal) & 0xFF
- if decryption:
- keyXorVal = curByte * 257;
- for j in range(8):
- wkey[j] ^= keyXorVal;
- dst+=chr(curByte)
- return dst
-
- class Topaz_Cipher(object):
- def __init__(self):
- self._ctx = None
-
- def ctx_init(self, key):
- ctx1 = 0x0CAFFE19E
- if isinstance(key, str):
- key = key.encode('latin-1')
- for keyByte in key:
- ctx2 = ctx1
- ctx1 = ((((ctx1 >>2) * (ctx1 >>7))&0xFFFFFFFF) ^ (keyByte * keyByte * 0x0F902007)& 0xFFFFFFFF )
- self._ctx = [ctx1, ctx2]
- return [ctx1,ctx2]
-
- def decrypt(self, data, ctx=None):
- if ctx == None:
- ctx = self._ctx
- ctx1 = ctx[0]
- ctx2 = ctx[1]
- plainText = ""
- if isinstance(data, str):
- data = data.encode('latin-1')
- for dataByte in data:
- m = (dataByte ^ ((ctx1 >> 3) &0xFF) ^ ((ctx2<<3) & 0xFF)) &0xFF
- ctx2 = ctx1
- ctx1 = (((ctx1 >> 2) * (ctx1 >> 7)) &0xFFFFFFFF) ^((m * m * 0x0F902007) &0xFFFFFFFF)
- plainText += chr(m)
- return plainText
-
- class AES_CBC(object):
- def __init__(self):
- self._key = None
- self._iv = None
- self.aes = None
-
- def set_decrypt_key(self, userkey, iv):
- self._key = userkey
- self._iv = iv
- self.aes = aescbc.AES_CBC(userkey, aescbc.noPadding(), len(userkey))
-
- def decrypt(self, data):
- iv = self._iv
- cleartext = self.aes.decrypt(iv + data)
- return cleartext
-
- print("Using Library AlfCrypto Python")
- return (AES_CBC, Pukall_Cipher, Topaz_Cipher)
-
-
-def _load_crypto():
- AES_CBC = Pukall_Cipher = Topaz_Cipher = None
- cryptolist = (_load_libalfcrypto, _load_python_alfcrypto)
- for loader in cryptolist:
- try:
- AES_CBC, Pukall_Cipher, Topaz_Cipher = loader()
- break
- except (ImportError, Exception):
- pass
- return AES_CBC, Pukall_Cipher, Topaz_Cipher
-
-AES_CBC, Pukall_Cipher, Topaz_Cipher = _load_crypto()
+ keyXorVal = curByte * 257;
+ for j in range(8):
+ wkey[j] ^= keyXorVal;
+ dst[i] = curByte
+ return bytes(dst)
+
+class Topaz_Cipher(object):
+ def __init__(self):
+ self._ctx = None
+
+ def ctx_init(self, key):
+ ctx1 = 0x0CAFFE19E
+ if isinstance(key, str):
+ key = key.encode('latin-1')
+ for keyByte in key:
+ ctx2 = ctx1
+ ctx1 = ((((ctx1 >>2) * (ctx1 >>7))&0xFFFFFFFF) ^ (keyByte * keyByte * 0x0F902007)& 0xFFFFFFFF )
+ self._ctx = [ctx1, ctx2]
+ return [ctx1,ctx2]
+
+ def decrypt(self, data, ctx=None):
+ if ctx == None:
+ ctx = self._ctx
+ ctx1 = ctx[0]
+ ctx2 = ctx[1]
+ plainText = ""
+ if isinstance(data, str):
+ data = data.encode('latin-1')
+ for dataByte in data:
+ m = (dataByte ^ ((ctx1 >> 3) &0xFF) ^ ((ctx2<<3) & 0xFF)) &0xFF
+ ctx2 = ctx1
+ ctx1 = (((ctx1 >> 2) * (ctx1 >> 7)) &0xFFFFFFFF) ^((m * m * 0x0F902007) &0xFFFFFFFF)
+ plainText += chr(m)
+ return plainText
+
+class AES_CBC(object):
+ def __init__(self):
+ self._key = None
+ self._iv = None
+ self.aes = None
+
+ def set_decrypt_key(self, userkey, iv):
+ self._key = userkey
+ self._iv = iv
+ self.aes = aescbc.AES_CBC(userkey, aescbc.noPadding(), len(userkey))
+
+ def decrypt(self, data):
+ iv = self._iv
+ cleartext = self.aes.decrypt(iv + data)
+ return cleartext
class KeyIVGen(object):
diff --git a/DeDRM_plugin/alfcrypto64.dll b/DeDRM_plugin/alfcrypto64.dll
deleted file mode 100644
index 7bef68e..0000000
--- a/DeDRM_plugin/alfcrypto64.dll
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/alfcrypto_src.zip b/DeDRM_plugin/alfcrypto_src.zip
deleted file mode 100644
index 269810c..0000000
--- a/DeDRM_plugin/alfcrypto_src.zip
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/libalfcrypto.dylib b/DeDRM_plugin/libalfcrypto.dylib
deleted file mode 100644
index 01c348c..0000000
--- a/DeDRM_plugin/libalfcrypto.dylib
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/libalfcrypto32.so b/DeDRM_plugin/libalfcrypto32.so
deleted file mode 100644
index 9a5a442..0000000
--- a/DeDRM_plugin/libalfcrypto32.so
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/libalfcrypto64.so b/DeDRM_plugin/libalfcrypto64.so
deleted file mode 100644
index a08ac28..0000000
--- a/DeDRM_plugin/libalfcrypto64.so
+++ /dev/null
Binary files differ
diff --git a/DeDRM_plugin/mobidedrm.py b/DeDRM_plugin/mobidedrm.py
index fe761c4..22cdb35 100755
--- a/DeDRM_plugin/mobidedrm.py
+++ b/DeDRM_plugin/mobidedrm.py
@@ -80,10 +80,7 @@ import sys
import os
import struct
import binascii
-try:
- from alfcrypto import Pukall_Cipher
-except:
- print("AlfCrypto not found. Using python PC1 implementation.")
+from alfcrypto import Pukall_Cipher
from utilities import SafeUnbuffered
@@ -140,41 +137,8 @@ def PC1(key, src, decryption=True):
# if we can get it from alfcrypto, use that
try:
return Pukall_Cipher().PC1(key,src,decryption)
- except NameError:
- pass
- except TypeError:
- pass
-
- # use slow python version, since Pukall_Cipher didn't load
- sum1 = 0;
- sum2 = 0;
- keyXorVal = 0;
- if len(key)!=16:
- DrmException ("PC1: Bad key length")
- wkey = []
- for i in range(8):
- wkey.append(key[i*2]<<8 | key[i*2+1])
- dst = bytearray(len(src))
- for i in range(len(src)):
- temp1 = 0;
- byteXorVal = 0;
- for j in range(8):
- temp1 ^= wkey[j]
- sum2 = (sum2+j)*20021 + sum1
- sum1 = (temp1*346)&0xFFFF
- sum2 = (sum2+sum1)&0xFFFF
- temp1 = (temp1*20021+1)&0xFFFF
- byteXorVal ^= temp1 ^ sum2
- curByte = src[i]
- if not decryption:
- keyXorVal = curByte * 257;
- curByte = ((curByte ^ (byteXorVal >> 8)) ^ byteXorVal) & 0xFF
- if decryption:
- keyXorVal = curByte * 257;
- for j in range(8):
- wkey[j] ^= keyXorVal;
- dst[i] = curByte
- return bytes(dst)
+ except:
+ raise
# accepts unicode returns unicode
def checksumPid(s):
@@ -232,12 +196,7 @@ class MobiBook:
pass
def __init__(self, infile):
- print("MobiDeDrm v{0:s}.\nCopyright © 2008-2020 The Dark Reverser, Apprentice Harper et al.".format(__version__))
-
- try:
- from alfcrypto import Pukall_Cipher
- except:
- print("AlfCrypto not found. Using python PC1 implementation.")
+ print("MobiDeDrm v{0:s}.\nCopyright © 2008-2022 The Dark Reverser, Apprentice Harper et al.".format(__version__))
# initial sanity check on file
self.data_file = open(infile, 'rb').read()
diff --git a/DeDRM_plugin/subasyncio.py b/DeDRM_plugin/subasyncio.py
deleted file mode 100644
index de084d3..0000000
--- a/DeDRM_plugin/subasyncio.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/env python
-# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
-
-import os, sys
-import signal
-import threading
-import subprocess
-from subprocess import Popen, PIPE, STDOUT
-
-# **heavily** chopped up and modfied version of asyncproc.py
-# to make it actually work on Windows as well as Mac/Linux
-# For the original see:
-# "http://www.lysator.liu.se/~bellman/download/"
-# author is "Thomas Bellman <[email protected]>"
-# available under GPL version 3 or Later
-
-# create an asynchronous subprocess whose output can be collected in
-# a non-blocking manner
-
-# What a mess! Have to use threads just to get non-blocking io
-# in a cross-platform manner
-
-# luckily all thread use is hidden within this class
-
-class Process(object):
- def __init__(self, *params, **kwparams):
- if len(params) <= 3:
- kwparams.setdefault('stdin', subprocess.PIPE)
- if len(params) <= 4:
- kwparams.setdefault('stdout', subprocess.PIPE)
- if len(params) <= 5:
- kwparams.setdefault('stderr', subprocess.PIPE)
- self.__pending_input = []
- self.__collected_outdata = []
- self.__collected_errdata = []
- self.__exitstatus = None
- self.__lock = threading.Lock()
- self.__inputsem = threading.Semaphore(0)
- self.__quit = False
-
- self.__process = subprocess.Popen(*params, **kwparams)
-
- if self.__process.stdin:
- self.__stdin_thread = threading.Thread(
- name="stdin-thread",
- target=self.__feeder, args=(self.__pending_input,
- self.__process.stdin))
- self.__stdin_thread.setDaemon(True)
- self.__stdin_thread.start()
-
- if self.__process.stdout:
- self.__stdout_thread = threading.Thread(
- name="stdout-thread",
- target=self.__reader, args=(self.__collected_outdata,
- self.__process.stdout))
- self.__stdout_thread.setDaemon(True)
- self.__stdout_thread.start()
-
- if self.__process.stderr:
- self.__stderr_thread = threading.Thread(
- name="stderr-thread",
- target=self.__reader, args=(self.__collected_errdata,
- self.__process.stderr))
- self.__stderr_thread.setDaemon(True)
- self.__stderr_thread.start()
-
- def pid(self):
- return self.__process.pid
-
- def kill(self, signal):
- self.__process.send_signal(signal)
-
- # check on subprocess (pass in 'nowait') to act like poll
- def wait(self, flag):
- if flag.lower() == 'nowait':
- rc = self.__process.poll()
- else:
- rc = self.__process.wait()
- if rc != None:
- if self.__process.stdin:
- self.closeinput()
- if self.__process.stdout:
- self.__stdout_thread.join()
- if self.__process.stderr:
- self.__stderr_thread.join()
- return self.__process.returncode
-
- def terminate(self):
- if self.__process.stdin:
- self.closeinput()
- self.__process.terminate()
-
- # thread gets data from subprocess stdout
- def __reader(self, collector, source):
- while True:
- data = os.read(source.fileno(), 65536)
- self.__lock.acquire()
- collector.append(data)
- self.__lock.release()
- if data == "":
- source.close()
- break
- return
-
- # thread feeds data to subprocess stdin
- def __feeder(self, pending, drain):
- while True:
- self.__inputsem.acquire()
- self.__lock.acquire()
- if not pending and self.__quit:
- drain.close()
- self.__lock.release()
- break
- data = pending.pop(0)
- self.__lock.release()
- drain.write(data)
-
- # non-blocking read of data from subprocess stdout
- def read(self):
- self.__lock.acquire()
- outdata = "".join(self.__collected_outdata)
- del self.__collected_outdata[:]
- self.__lock.release()
- return outdata
-
- # non-blocking read of data from subprocess stderr
- def readerr(self):
- self.__lock.acquire()
- errdata = "".join(self.__collected_errdata)
- del self.__collected_errdata[:]
- self.__lock.release()
- return errdata
-
- # non-blocking write to stdin of subprocess
- def write(self, data):
- if self.__process.stdin is None:
- raise ValueError("Writing to process with stdin not a pipe")
- self.__lock.acquire()
- self.__pending_input.append(data)
- self.__inputsem.release()
- self.__lock.release()
-
- # close stdinput of subprocess
- def closeinput(self):
- self.__lock.acquire()
- self.__quit = True
- self.__inputsem.release()
- self.__lock.release()