mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-21 21:38:56 +00:00
Compare commits
4 Commits
v10.0.9
...
134cd80713
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
134cd80713 | ||
|
|
e82d2b5c9c | ||
|
|
7f6dd84389 | ||
|
|
ad33aea18d |
@@ -99,4 +99,5 @@ This is v10.0.9, a release candidate for v10.1.0. I don't expect there to be maj
|
|||||||
|
|
||||||
## Fixes on master (not yet released):
|
## Fixes on master (not yet released):
|
||||||
|
|
||||||
- (none)
|
- Fix a bug where decrypting a 40-bit RC4 pdf with R=2 didn't work.
|
||||||
|
- Fix a bug where decrypting a 256-bit AES pdf with V=5 didn't work.
|
||||||
|
|||||||
@@ -1366,14 +1366,14 @@ class PDFDocument(object):
|
|||||||
|
|
||||||
def process_with_aes(self, key, encrypt, data, repetitions = 1, iv = None):
|
def process_with_aes(self, key, encrypt, data, repetitions = 1, iv = None):
|
||||||
if iv is None:
|
if iv is None:
|
||||||
keylen = len(key)
|
iv = bytes(bytearray(16))
|
||||||
iv = bytes([0x00]*keylen)
|
|
||||||
|
aes = AES.new(key, AES.MODE_CBC, iv)
|
||||||
|
|
||||||
if not encrypt:
|
if not encrypt:
|
||||||
plaintext = AES.new(key,AES.MODE_CBC,iv, True).decrypt(data)
|
plaintext = aes.decrypt(data)
|
||||||
return plaintext
|
return plaintext
|
||||||
else:
|
else:
|
||||||
aes = AES.new(key, AES.MODE_CBC, iv, False)
|
|
||||||
new_data = bytes(data * repetitions)
|
new_data = bytes(data * repetitions)
|
||||||
crypt = aes.encrypt(new_data)
|
crypt = aes.encrypt(new_data)
|
||||||
return crypt
|
return crypt
|
||||||
@@ -1394,10 +1394,18 @@ class PDFDocument(object):
|
|||||||
raise Exception("K1 < 32 ...")
|
raise Exception("K1 < 32 ...")
|
||||||
#def process_with_aes(self, key: bytes, encrypt: bool, data: bytes, repetitions: int = 1, iv: bytes = None):
|
#def process_with_aes(self, key: bytes, encrypt: bool, data: bytes, repetitions: int = 1, iv: bytes = None):
|
||||||
E = self.process_with_aes(K[:16], True, K1, 64, K[16:32])
|
E = self.process_with_aes(K[:16], True, K1, 64, K[16:32])
|
||||||
K = (hashlib.sha256, hashlib.sha384, hashlib.sha512)[sum(E) % 3](E).digest()
|
E = bytearray(E)
|
||||||
|
|
||||||
|
E_mod_3 = 0
|
||||||
|
for i in range(16):
|
||||||
|
E_mod_3 += E[i]
|
||||||
|
|
||||||
|
E_mod_3 %= 3
|
||||||
|
|
||||||
|
K = (hashlib.sha256, hashlib.sha384, hashlib.sha512)[E_mod_3](E).digest()
|
||||||
|
|
||||||
if round_number >= 64:
|
if round_number >= 64:
|
||||||
ch = int.from_bytes(E[-1:], "big", signed=False)
|
ch = E[-1:][0] # get last byte
|
||||||
if ch <= round_number - 32:
|
if ch <= round_number - 32:
|
||||||
done = True
|
done = True
|
||||||
|
|
||||||
@@ -1478,14 +1486,23 @@ class PDFDocument(object):
|
|||||||
EncMetadata = b'True'
|
EncMetadata = b'True'
|
||||||
if (EncMetadata == ('False' or 'false') or V < 4) and R >= 4:
|
if (EncMetadata == ('False' or 'false') or V < 4) and R >= 4:
|
||||||
hash.update(codecs.decode(b'ffffffff','hex'))
|
hash.update(codecs.decode(b'ffffffff','hex'))
|
||||||
|
|
||||||
|
# Finish hash:
|
||||||
|
hash = hash.digest()
|
||||||
|
|
||||||
if R >= 3:
|
if R >= 3:
|
||||||
# 8
|
# 8
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
hash = hashlib.md5(hash.digest()[:length//8])
|
hash = hashlib.md5(hash[:length//8]).digest()
|
||||||
key = hash.digest()[:length//8]
|
if R == 2:
|
||||||
|
# R=2 only uses first five bytes.
|
||||||
|
key = hash[:5]
|
||||||
|
else:
|
||||||
|
key = hash[:length//8]
|
||||||
|
|
||||||
if R == 2:
|
if R == 2:
|
||||||
# Algorithm 3.4
|
# Algorithm 3.4
|
||||||
u1 = ARC4.new(key).decrypt(password)
|
u1 = ARC4.new(key).decrypt(self.PASSWORD_PADDING)
|
||||||
elif R >= 3:
|
elif R >= 3:
|
||||||
# Algorithm 3.5
|
# Algorithm 3.5
|
||||||
hash = hashlib.md5(self.PASSWORD_PADDING) # 2
|
hash = hashlib.md5(self.PASSWORD_PADDING) # 2
|
||||||
@@ -1498,6 +1515,7 @@ class PDFDocument(object):
|
|||||||
k = b''.join(bytes([c ^ i]) for c in key )
|
k = b''.join(bytes([c ^ i]) for c in key )
|
||||||
x = ARC4.new(k).decrypt(x)
|
x = ARC4.new(k).decrypt(x)
|
||||||
u1 = x+x # 32bytes total
|
u1 = x+x # 32bytes total
|
||||||
|
|
||||||
if R == 2:
|
if R == 2:
|
||||||
is_authenticated = (u1 == U)
|
is_authenticated = (u1 == U)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -327,36 +327,50 @@ class KoboLibrary(object):
|
|||||||
elif sys.platform.startswith('darwin'):
|
elif sys.platform.startswith('darwin'):
|
||||||
self.kobodir = os.path.join(os.environ['HOME'], "Library", "Application Support", "Kobo", "Kobo Desktop Edition")
|
self.kobodir = os.path.join(os.environ['HOME'], "Library", "Application Support", "Kobo", "Kobo Desktop Edition")
|
||||||
elif sys.platform.startswith('linux'):
|
elif sys.platform.startswith('linux'):
|
||||||
|
# Since on Linux, you have to run Kobo Desktop within Wine,
|
||||||
|
# there is no guarantee where Kobo.sqlite (and the rest of
|
||||||
|
# the kobo directory) might be.
|
||||||
|
#
|
||||||
|
# It should also be noted that Kobo Desktop will store all
|
||||||
|
# of it files in the current directory where you run it,
|
||||||
|
# meaning that a user might accidentally create several
|
||||||
|
# Kobo.sqlite files which are all separate and then be
|
||||||
|
# confused why Obok can't find any of the new books. Sadly
|
||||||
|
# there isn't a trivial way to deal with this.
|
||||||
|
|
||||||
#sets ~/.config/calibre as the location to store the kobodir location info file and creates this directory if necessary
|
# We cache the kobodir we find in ~/.config/calibre.
|
||||||
kobodir_cache_dir = os.path.join(os.environ['HOME'], ".config", "calibre")
|
kobodir_cache_dir = os.path.join(os.environ['HOME'], ".config", "calibre", "plugins", "obok")
|
||||||
if not os.path.isdir(kobodir_cache_dir):
|
if not os.path.isdir(kobodir_cache_dir):
|
||||||
os.mkdir(kobodir_cache_dir)
|
os.mkdir(kobodir_cache_dir)
|
||||||
|
kobodir_cache_file = os.path.join(kobodir_cache_dir, "kobo-location")
|
||||||
#appends the name of the file we're storing the kobodir location info to the above path
|
|
||||||
kobodir_cache_file = str(kobodir_cache_dir) + "/" + "kobo location"
|
|
||||||
|
|
||||||
"""if the above file does not exist, recursively searches from the root
|
|
||||||
of the filesystem until kobodir is found and stores the location of kobodir
|
|
||||||
in that file so this loop can be skipped in the future"""
|
|
||||||
original_stdout = sys.stdout
|
|
||||||
if not os.path.isfile(kobodir_cache_file):
|
|
||||||
for root, dirs, files in os.walk('/'):
|
|
||||||
for file in files:
|
|
||||||
if file == 'Kobo.sqlite':
|
|
||||||
kobo_linux_path = str(root)
|
|
||||||
with open(kobodir_cache_file, 'w') as f:
|
|
||||||
sys.stdout = f
|
|
||||||
print(kobo_linux_path, end='')
|
|
||||||
sys.stdout = original_stdout
|
|
||||||
|
|
||||||
f = open(kobodir_cache_file, 'r' )
|
try:
|
||||||
self.kobodir = f.read()
|
# If the cached version exists and the path does really
|
||||||
|
# contain Kobo.sqlite, use that.
|
||||||
|
with open(kobodir_cache_file, "r") as f:
|
||||||
|
cached_kobodir = f.read().strip()
|
||||||
|
assert os.path.isfile(os.path.join(cached_kobodir, "Kobo.sqlite"))
|
||||||
|
self.kobodir = cached_kobodir
|
||||||
|
except (AssertionError, FileNotFoundError):
|
||||||
|
# If there was no cached version, search the entire
|
||||||
|
# filesystem tree for a directory containing
|
||||||
|
# "Kobo.sqlite".
|
||||||
|
#
|
||||||
|
# We first search $HOME to avoid picking another user's
|
||||||
|
# Kobo.sqlite file, but then fallback to / if there was
|
||||||
|
# nothing in $HOME.
|
||||||
|
for candidate_root in (os.environ["HOME"], "/"):
|
||||||
|
for root, _, files in os.walk(candidate_root):
|
||||||
|
if "Kobo.sqlite" in files:
|
||||||
|
with open(kobodir_cache_file, "w") as f:
|
||||||
|
f.write("%s/\n" % (root,))
|
||||||
|
self.kobodir = root
|
||||||
|
break
|
||||||
|
|
||||||
# desktop versions use Kobo.sqlite
|
# Desktop versions use Kobo.sqlite.
|
||||||
kobodb = os.path.join(self.kobodir, "Kobo.sqlite")
|
kobodb = os.path.join(self.kobodir, "Kobo.sqlite")
|
||||||
# check for existence of file
|
# check for existence of file
|
||||||
if (not(os.path.isfile(kobodb))):
|
if not os.path.isfile(kobodb):
|
||||||
# give up here, we haven't found anything useful
|
# give up here, we haven't found anything useful
|
||||||
self.kobodir = u""
|
self.kobodir = u""
|
||||||
kobodb = u""
|
kobodb = u""
|
||||||
@@ -430,7 +444,7 @@ class KoboLibrary(object):
|
|||||||
macaddrs = []
|
macaddrs = []
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
c = re.compile('\s?(' + '[0-9a-f]{2}[:\-]' * 5 + '[0-9a-f]{2})(\s|$)', re.IGNORECASE)
|
c = re.compile('\s?(' + '[0-9a-f]{2}[:\-]' * 5 + '[0-9a-f]{2})(\s|$)', re.IGNORECASE)
|
||||||
try:
|
try:
|
||||||
output = subprocess.Popen('ipconfig /all', shell=True, stdout=subprocess.PIPE, text=True).stdout
|
output = subprocess.Popen('ipconfig /all', shell=True, stdout=subprocess.PIPE, text=True).stdout
|
||||||
for line in output:
|
for line in output:
|
||||||
m = c.search(line)
|
m = c.search(line)
|
||||||
|
|||||||
Reference in New Issue
Block a user