mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-20 13:08:55 +00:00
Compare commits
9 Commits
fb8b003444
...
v10.0.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9bad26d4b | ||
|
|
2a1413297e | ||
|
|
815f880e34 | ||
|
|
9ae77c438f | ||
|
|
abc5de018e | ||
|
|
133e67fa03 | ||
|
|
f86cff285b | ||
|
|
a553a71f45 | ||
|
|
740b46546f |
8
.github/ISSUE_TEMPLATE/QUESTION.yml
vendored
8
.github/ISSUE_TEMPLATE/QUESTION.yml
vendored
@@ -10,16 +10,16 @@ body:
|
||||
id: calibre-version
|
||||
attributes:
|
||||
label: Which version of Calibre are you running?
|
||||
description: "Example: 5.32"
|
||||
placeholder: "5.32"
|
||||
description: "Example: 6.23"
|
||||
placeholder: "6.23"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: plugin-version
|
||||
attributes:
|
||||
label: Which version of the DeDRM plugin are you running?
|
||||
description: "Example: v10.0.0"
|
||||
placeholder: "v10.0.0"
|
||||
description: "Example: v10.0.2"
|
||||
placeholder: "v10.0.2"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
||||
45
.github/workflows/main.yml
vendored
45
.github/workflows/main.yml
vendored
@@ -9,8 +9,10 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Package
|
||||
run: python3 make_release.py
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@@ -18,3 +20,46 @@ jobs:
|
||||
path: |
|
||||
DeDRM_tools_*.zip
|
||||
DeDRM_tools.zip
|
||||
|
||||
# - name: Delete old release
|
||||
# uses: cb80/delrel@latest
|
||||
# with:
|
||||
# tag: autorelease
|
||||
# token: ${{ github.token }}
|
||||
#
|
||||
# - name: Delete old tag
|
||||
# uses: dev-drprasad/delete-tag-and-release@v1.0
|
||||
# with:
|
||||
# tag_name: autorelease
|
||||
# github_token: ${{ github.token }}
|
||||
# delete_release: true
|
||||
#
|
||||
# - name: Prepare release
|
||||
# run: cp DeDRM_tools.zip DeDRM_alpha_${{ github.sha }}.zip
|
||||
#
|
||||
# - name: Auto-release
|
||||
# id: autorelease
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# with:
|
||||
# tag_name: autorelease
|
||||
# token: ${{ github.token }}
|
||||
# name: Automatic alpha release with latest changes
|
||||
# body: |
|
||||
# This release is automatically generated by Github for each commit.
|
||||
#
|
||||
# This means, every time a change is made to this repo, this release will be updated to contain an untested copy of the plugin at that stage. This will contain the most up-to-date code, but it's not tested at all and may be broken.
|
||||
#
|
||||
# Last update based on Git commit ${{ github.sha }}.
|
||||
# prerelease: true
|
||||
# draft: true
|
||||
# files: DeDRM_alpha_${{ github.sha }}.zip
|
||||
#
|
||||
# - name: Make release public
|
||||
# uses: irongut/EditRelease@v1.2.0
|
||||
# with:
|
||||
# token: ${{ github.token }}
|
||||
# id: ${{ steps.autorelease.outputs.id }}
|
||||
# draft: false
|
||||
# prerelease: true
|
||||
#
|
||||
#
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -67,7 +67,11 @@ List of changes since the fork of Apprentice Harper's repository:
|
||||
- Fix Nook Study key retrieval code (partially fixes #50).
|
||||
- Make the plugin work on Calibre 6 (Qt 6). (fixes #54 and #98) If you're running Calibre 6 and you notice any issues, please open a bug report.
|
||||
|
||||
## Fixes on master (not yet released):
|
||||
## Fixes in v10.0.9 (RC for v10.1.0, 2023-08-02):
|
||||
|
||||
Note that versions v10.0.4(s), v10.0.5(s) and v10.0.6(s) were released by other people in various forks, so I have decided to make a larger version jump so there are no conflicting version numbers / different builds with the same version number.
|
||||
|
||||
This is v10.0.9, a release candidate for v10.1.0. I don't expect there to be major issues / bugs, but since a lot of code has changed in the last year I wanted to get some "extended testing" before this becomes v10.1.0.
|
||||
|
||||
- Fix a bug introduced with #48 that breaks DeDRM'ing on Calibre 4 (fixes #101).
|
||||
- Fix some more Calibre-6 bugs in the Obok plugin (should fix #114).
|
||||
@@ -89,3 +93,10 @@ List of changes since the fork of Apprentice Harper's repository:
|
||||
- PDF: Ignore invalid PDF objids unless the script is running in strict mode. Fixes some PDFs, apparently. Fixes #233.
|
||||
- Bugfix: EPUBs with remaining content in the encryption.xml after decryption weren't written correctly.
|
||||
- Support for Adobe's 'aes128-cbc-uncompressed' encryption method (fixes #242).
|
||||
- Two bugfixes for Amazon DeDRM from Satuoni ( https://github.com/noDRM/DeDRM_tools/issues/315#issuecomment-1508305428 ) and andrewc12 ( https://github.com/andrewc12/DeDRM_tools/commit/d9233d61f00d4484235863969919059f4d0b2057 ) that might make the plugin work with newer versions.
|
||||
- Fix font decryption not working with some books (fixes #347), thanks for the patch @bydioeds.
|
||||
- Fix a couple unicode errors for Python2 in Kindle and Nook code.
|
||||
|
||||
## Fixes on master (not yet released):
|
||||
|
||||
- (none)
|
||||
|
||||
@@ -17,7 +17,7 @@ p {margin-top: 0}
|
||||
|
||||
<body>
|
||||
|
||||
<h1>DeDRM Plugin <span class="version">(v10.0.3)</span></h1>
|
||||
<h1>DeDRM Plugin <span class="version">(v10.0.9 / v10.1.0 RC1)</span></h1>
|
||||
|
||||
<p>This plugin removes DRM from ebooks when they are imported into calibre. If you already have DRMed ebooks in your calibre library, you will need to remove them and import them again.</p>
|
||||
|
||||
@@ -26,6 +26,8 @@ p {margin-top: 0}
|
||||
<h3>Installation</h3>
|
||||
<p>You have obviously managed to install the plugin, as otherwise you wouldn’t be reading this help file. However, you should also delete any older DRM removal plugins, as this DeDRM plugin replaces the five older plugins: Kindle and Mobipocket DeDRM (K4MobiDeDRM), Ignoble Epub DeDRM (ignobleepub), Inept Epub DeDRM (ineptepub), Inept PDF DeDRM (ineptepub) and eReader PDB 2 PML (eReaderPDB2PML).</p>
|
||||
|
||||
<p>This plugin (in versions v10.0.0 and above) will automatically replace the older 7.X and below versions from Apprentice Alf and Apprentice Harper.</p>
|
||||
|
||||
<h3>Configuration</h3>
|
||||
<p>On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Digital Editions need to be generated separately (see the Linux section below).</p>
|
||||
|
||||
@@ -60,7 +62,7 @@ p {margin-top: 0}
|
||||
<li>And probably many more.</li>
|
||||
</ul>
|
||||
|
||||
<h3>For additional help read the <a href="https://github.com/noDRM/DeDRM_tools/blob/master/FAQs.md">FAQs</a> at <a href="https://github.com/noDRM/DeDRM_tools">NoDRM's GitHub repository</a> (or the corresponding <a href="https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md">FAQs</a> at <a href="https://github.com/apprenticeharper/DeDRM_tools/">Apprentice Harpers’s GitHub repository</a>). You can <a href="https://github.com/noDRM/DeDRM_tools/issues">open issue reports</a>related to this fork at NoDRM's GitHub repository.</h3>
|
||||
<h4>For additional help read the <a href="https://github.com/noDRM/DeDRM_tools/blob/master/FAQs.md">FAQs</a> at <a href="https://github.com/noDRM/DeDRM_tools">NoDRM's GitHub repository</a> (or the corresponding <a href="https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md">FAQs</a> at <a href="https://github.com/apprenticeharper/DeDRM_tools/">Apprentice Harpers’s GitHub repository</a>). You can <a href="https://github.com/noDRM/DeDRM_tools/issues">open issue reports</a> related to this fork at NoDRM's GitHub repository.</h4>
|
||||
|
||||
|
||||
<h2>Linux Systems Only</h2>
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import print_function
|
||||
|
||||
# __init__.py for DeDRM_plugin
|
||||
# Copyright © 2008-2020 Apprentice Harper et al.
|
||||
# Copyright © 2021 NoDRM
|
||||
# Copyright © 2021-2023 NoDRM
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
@@ -82,6 +82,7 @@ __docformat__ = 'restructuredtext en'
|
||||
# 10.0.0 - First forked version by NoDRM. See CHANGELOG.md for details.
|
||||
# 10.0.1 - Fixes a bug in the watermark code.
|
||||
# 10.0.2 - Fix Kindle for Mac & update Adobe key retrieval
|
||||
# For changes made in 10.0.3 and above, see the CHANGELOG.md file
|
||||
|
||||
"""
|
||||
Decrypt DRMed ebooks.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#@@CALIBRE_COMPAT_CODE@@
|
||||
|
||||
PLUGIN_NAME = "DeDRM"
|
||||
__version__ = '10.0.3'
|
||||
__version__ = '10.0.9'
|
||||
|
||||
PLUGIN_VERSION_TUPLE = tuple([int(x) for x in __version__.split(".")])
|
||||
PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# epubfontdecrypt.py
|
||||
# Copyright © 2021 by noDRM
|
||||
# Copyright © 2021-2023 by noDRM
|
||||
|
||||
# Released under the terms of the GNU General Public Licence, version 3
|
||||
# <http://www.gnu.org/licenses/>
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
# Revision history:
|
||||
# 1 - Initial release
|
||||
# 2 - Bugfix for multiple book IDs, reported at #347
|
||||
|
||||
"""
|
||||
Decrypts / deobfuscates font files in EPUB files
|
||||
@@ -18,7 +19,7 @@ Decrypts / deobfuscates font files in EPUB files
|
||||
from __future__ import print_function
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__version__ = "1"
|
||||
__version__ = "2"
|
||||
|
||||
import os
|
||||
import traceback
|
||||
@@ -193,9 +194,10 @@ def decryptFontsBook(inpath, outpath):
|
||||
pass
|
||||
|
||||
try:
|
||||
identify_element = container.find(packageNS("metadata")).find(metadataDCNS("identifier"))
|
||||
if (secret_key_name is None or secret_key_name == identify_element.get("id")):
|
||||
font_master_key = identify_element.text
|
||||
identify_elements = container.find(packageNS("metadata")).findall(metadataDCNS("identifier"))
|
||||
for element in identify_elements:
|
||||
if (secret_key_name is None or secret_key_name == element.get("id")):
|
||||
font_master_key = element.text
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -54,15 +54,26 @@ def getNookLogFiles():
|
||||
paths = set()
|
||||
if 'LOCALAPPDATA' in os.environ.keys():
|
||||
# Python 2.x does not return unicode env. Use Python 3.x
|
||||
path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
|
||||
if sys.version_info[0] == 2:
|
||||
path = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
|
||||
else:
|
||||
path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
|
||||
if os.path.isdir(path):
|
||||
paths.add(path)
|
||||
if 'USERPROFILE' in os.environ.keys():
|
||||
# Python 2.x does not return unicode env. Use Python 3.x
|
||||
path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Local"
|
||||
if sys.version_info[0] == 2:
|
||||
path = winreg.ExpandEnvironmentStrings(u"%USERPROFILE%")+u"\\AppData\\Local"
|
||||
else:
|
||||
path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Local"
|
||||
|
||||
if os.path.isdir(path):
|
||||
paths.add(path)
|
||||
path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Roaming"
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
path = winreg.ExpandEnvironmentStrings(u"%USERPROFILE%")+u"\\AppData\\Roaming"
|
||||
else:
|
||||
path = winreg.ExpandEnvironmentStrings("%USERPROFILE%")+"\\AppData\\Roaming"
|
||||
if os.path.isdir(path):
|
||||
paths.add(path)
|
||||
# User Shell Folders show take precedent over Shell Folders if present
|
||||
|
||||
@@ -57,6 +57,7 @@ except ImportError:
|
||||
# Windows-friendly choice: pylzma wheels
|
||||
import pylzma as lzma
|
||||
|
||||
from kfxtables import *
|
||||
|
||||
TID_NULL = 0
|
||||
TID_BOOLEAN = 1
|
||||
@@ -769,6 +770,7 @@ def pkcs7unpad(msg, blocklen):
|
||||
|
||||
|
||||
# every VoucherEnvelope version has a corresponding "word" and magic number, used in obfuscating the shared secret
|
||||
# 4-digit versions use their own obfuscation/scramble. It does not seem to depend on the "word" and number
|
||||
OBFUSCATION_TABLE = {
|
||||
"V1": (0x00, None),
|
||||
"V2": (0x05, b'Antidisestablishmentarianism'),
|
||||
@@ -779,26 +781,26 @@ OBFUSCATION_TABLE = {
|
||||
"V7": (0x05, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V8": (0x09, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V9": (0x05, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V10": (0x07, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V10": (0x07, b'z3\n\x039\x12\x13`\x06=v;\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V11": (0x05, b'L=\nhVm\x07go\n6\x14\x06\x16L\r\x02\x0b\x0c\x1b\x04#p\t'),
|
||||
"V12": (0x06, b',n\x1d\rl\x13\x1c\x13\x16p\x14\x07U\x0c\x1f\x19w\x16\x16\x1d5T'),
|
||||
"V12": (0x06, b';n\x1d\rl\x13\x1c\x13\x16p\x14\x07U\x0c\x1f\x19w\x16\x16\x1d5T'),
|
||||
"V13": (0x07, b'I\x05\t\x08\x03r)\x01$N\x0fr3n\x0b062D\x0f\x13'),
|
||||
"V14": (0x05, b"\x03\x02\x1c9\x19\x15\x15q\x1057\x08\x16\x0cF\x1b.Fw\x01\x12\x03\x13\x02\x17S'hk6"),
|
||||
"V15": (0x0A, b'&,4B\x1dcI\x0bU\x03I\x07\x04\x1c\t\x05c\x07%ws\x0cj\t\x1a\x08\x0f'),
|
||||
"V16": (0x0A, b'\x06\x18`h,b><\x06PqR\x02Zc\x034\n\x16\x1e\x18\x06#e'),
|
||||
"V16": (0x0A, b'\x06\x18`h;b><\x06PqR\x02Zc\x034\n\x16\x1e\x18\x06#e'),
|
||||
"V17": (0x07, b'y\r\x12\x08fw.[\x02\t\n\x13\x11\x0c\x11b\x1e8L\x10(\x13<Jx6c\x0f'),
|
||||
"V18": (0x07, b'I\x0b\x0e,\x19\x1aIa\x10s\x19g\\\x1b\x11!\x18yf\x0f\t\x1d7[bSp\x03'),
|
||||
"V18": (0x07, b'I\x0b\x0e;\x19\x1aIa\x10s\x19g\\\x1b\x11!\x18yf\x0f\t\x1d7[bSp\x03'),
|
||||
"V19": (0x05, b'\n6>)N\x02\x188\x016s\x13\x14\x1b\x16jeN\n\x146\x04\x18\x1c\x0c\x19\x1f,\x02]'),
|
||||
"V20": (0x08, b'_\r\x01\x12]\\\x14*\x17i\x14\r\t!\x1e,~hZ\x12jK\x17\x1e*1'),
|
||||
"V20": (0x08, b'_\r\x01\x12]\\\x14*\x17i\x14\r\t!\x1e;~hZ\x12jK\x17\x1e*1'),
|
||||
"V21": (0x07, b'e\x1d\x19|\ty\x1di|N\x13\x0e\x04\x1bj<h\x13\x15k\x12\x08=\x1f\x16~\x13l'),
|
||||
"V22": (0x08, b'?\x17yi$k7Pc\tEo\x0c\x07\x07\t\x1f,*i\x12\x0cI0\x10I\x1a?2\x04'),
|
||||
"V23": (0x08, b'\x16+db\x13\x04\x18\rc%\x14\x17\x0f\x13F\x0c[\t9\x1ay\x01\x1eH'),
|
||||
"V24": (0x06, b'|6\\\x1a\r\x10\nP\x07\x0fu\x1f\t,\rr`uv\\~55\x11]N'),
|
||||
"V25": (0x09, b'\x07\x14w\x1e,^y\x01:\x08\x07\x1fr\tU#j\x16\x12\x1eB\x04\x16=\x06fZ\x07\x02\x06'),
|
||||
"V24": (0x06, b'|6\\\x1a\r\x10\nP\x07\x0fu\x1f\t;\rr`uv\\~55\x11]N'),
|
||||
"V25": (0x09, b'\x07\x14w\x1e;^y\x01:\x08\x07\x1fr\tU#j\x16\x12\x1eB\x04\x16=\x06fZ\x07\x02\x06'),
|
||||
"V26": (0x06, b'\x03IL\x1e"K\x1f\x0f\x1fp0\x01`X\x02z0`\x03\x0eN\x07'),
|
||||
"V27": (0x07, b'Xk\x10y\x02\x18\x10\x17\x1d,\x0e\x05e\x10\x15"e\x0fh(\x06s\x1c\x08I\x0c\x1b\x0e'),
|
||||
"V28": (0x0A, b'6P\x1bs\x0f\x06V.\x1cM\x14\x02\n\x1b\x07{P0:\x18zaU\x05'),
|
||||
"V9708": (0x05, b'\x1diIm\x08a\x17\x1e!am\x1d\x1aQ.\x16!\x06*\}x04\x11\t\x06\x04?'),
|
||||
"V9708": (0x05, b'\x1diIm\x08a\x17\x1e!am\x1d\x1aQ.\x16!\x06*\x04\x11\t\x06\x04?'),
|
||||
"V1031": (0x08, b'Antidisestablishmentarianism'),
|
||||
"V2069": (0x07, b'Floccinaucinihilipilification'),
|
||||
"V9041": (0x06, b'>\x14\x0c\x12\x10-\x13&\x18U\x1d\x05Rlt\x03!\x19\x1b\x13\x04]Y\x19,\t\x1b'),
|
||||
@@ -807,10 +809,367 @@ OBFUSCATION_TABLE = {
|
||||
"V9479": (0x09, b'\x10\x1bJ\x18\nh!\x10"\x03>Z\'\r\x01]W\x06\x1c\x1e?\x0f\x13'),
|
||||
"V9888": (0x05, b"K\x0c6\x1d\x1a\x17pO}Rk\x1d'w1^\x1f$\x1c{C\x02Q\x06\x1d`"),
|
||||
"V4648": (0x07, b'X.\x0eW\x1c*K\x12\x12\t\n\n\x17Wx\x01\x02Yf\x0f\x18\x1bVXPi\x01'),
|
||||
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v;\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
|
||||
}
|
||||
|
||||
|
||||
#common str: "PIDv3AESAES/CBC/PKCS5PaddingHmacSHA256"
|
||||
class workspace(object):
|
||||
def __init__(self,initial_list):
|
||||
self.work=initial_list
|
||||
def shuffle(self,shuflist):
|
||||
ll=len(shuflist)
|
||||
rt=[]
|
||||
for i in range(ll):
|
||||
rt.append(self.work[shuflist[i]])
|
||||
self.work=rt
|
||||
def sbox(self,table,matrix,skplist=[]): #table is list of 4-byte integers
|
||||
offset=0
|
||||
nwork=list(self.work)
|
||||
wo=0
|
||||
toff=0
|
||||
while offset<0x6000:
|
||||
uv5=table[toff+nwork[wo+0]]
|
||||
uv1=table[toff+nwork[wo+1]+0x100]
|
||||
uv2=table[toff+nwork[wo+2]+0x200]
|
||||
uv3=table[toff+nwork[wo+3]+0x300]
|
||||
moff=0
|
||||
if 0 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+(uv1>>0x1c)|( (uv5>>0x18)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+(uv3>>0x1c)|( (uv2>>0x18)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x18)&0xf) |( (uv5>>0x14)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x18)&0xf) |( (uv2>>0x14)&0xf0)]
|
||||
moff+=0x100
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+0]=rnib1*0x10+rnib2
|
||||
if 1 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0x14)&0xf)|( (uv5>>0x10)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0x14)&0xf)|( (uv2>>0x10)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x10)&0xf) |( (uv5>>0xc)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x10)&0xf) |( (uv2>>0xc)&0xf0)]
|
||||
moff+=0x100
|
||||
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+1]=rnib1*0x10+rnib2
|
||||
if 2 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0xc)&0xf)|( (uv5>>0x8)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0xc)&0xf)|( (uv2>>0x8)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1>>0x8)&0xf) |( (uv5>>0x4)&0xf0)]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3>>0x8)&0xf) |( (uv2>>0x4)&0xf0)]
|
||||
moff+=0x100
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+2]=rnib1*0x10+rnib2
|
||||
if 3 in skplist:
|
||||
moff+=0x400
|
||||
else:
|
||||
nib1=matrix[moff+offset+((uv1>>0x4)&0xf)|( (uv5)&0xf0)]
|
||||
moff+=0x100
|
||||
nib2=matrix[moff+offset+((uv3>>0x4)&0xf)|( (uv2)&0xf0)]
|
||||
moff+=0x100
|
||||
nib3=matrix[moff+offset+((uv1)&0xf)|( (uv5<<4)&0xf0) ]
|
||||
moff+=0x100
|
||||
nib4=matrix[moff+offset+((uv3)&0xf)|( (uv2<<4)&0xf0) ]
|
||||
moff+=0x100
|
||||
##############
|
||||
rnib1=matrix[moff+offset+nib1*0x10+nib2]
|
||||
moff+=0x100
|
||||
rnib2=matrix[moff+offset+nib3*0x10+nib4]
|
||||
moff+=0x100
|
||||
nwork[wo+3]=rnib1*0x10+rnib2
|
||||
offset = offset + 0x1800
|
||||
wo+=4
|
||||
toff+=0x400
|
||||
self.work=nwork
|
||||
def lookup(self,ltable):
|
||||
for a in range(len(self.work)):
|
||||
self.work[a]=ltable[a]
|
||||
def exlookup(self,ltable):
|
||||
lookoffs=0
|
||||
for a in range(len(self.work)):
|
||||
self.work[a]=ltable[self.work[a]+lookoffs]
|
||||
lookoffs+=0x100
|
||||
def mask(self, chunk):
|
||||
out=[]
|
||||
for a in range(len(chunk)):
|
||||
self.work[a]=self.work[a]^chunk[a]
|
||||
out.append(self.work[a])
|
||||
return out
|
||||
|
||||
def process_V9708(st):
|
||||
#e9c457a7dae6aa24365e7ef219b934b17ed58ee7d5329343fc3aea7860ed51f9a73de14351c9
|
||||
ws=workspace([0x11]*16)
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a06ea70,d0x6a0dab50)
|
||||
ws.sbox(d0x6a073a70,d0x6a0dab50)
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a072a70)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16;
|
||||
return bytes(out)
|
||||
|
||||
def process_V1031(st):
|
||||
#d53efea7fdd0fda3e1e0ebbae87cad0e8f5ef413c471c3ae81f39222a9ec8b8ed582e045918c
|
||||
ws=workspace([0x06,0x18,0x60,0x68,0x3b,0x62,0x3e,0x3c,0x06,0x50,0x71,0x52,0x02,0x5a,0x63,0x03])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0797c0,d0x6a0dab50,[3])
|
||||
ws.sbox(d0x6a07e7c0,d0x6a0dab50,[3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0797c0,d0x6a0dab50,[3])
|
||||
ws.sbox(d0x6a07e7c0,d0x6a0dab50,[3])
|
||||
ws.exlookup(d0x6a07d7c0)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
#break
|
||||
return bytes(out)
|
||||
|
||||
def process_V2069(st):
|
||||
#8e6196d754a304c9354e91b5d79f07b048026d31c7373a8691e513f2c802c706742731caa858
|
||||
ws=workspace([0x79,0x0d,0x12,0x08,0x66,0x77,0x2e,0x5b,0x02,0x09,0x0a,0x13,0x11,0x0c,0x11,0x62])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a084498,d0x6a0dab50,[2])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a089498,d0x6a0dab50,[2])
|
||||
ws.sbox(d0x6a089498,d0x6a0dab50,[2])
|
||||
ws.sbox(d0x6a084498,d0x6a0dab50,[2])
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a088498)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def process_V9041(st):
|
||||
#11f7db074b24e560dfa6fae3252b383c3b936e51f6ded570dc936cb1da9f4fc4a97ec686e7d8
|
||||
ws=workspace([0x49,0x0b,0x0e,0x3b,0x19,0x1a,0x49,0x61,0x10,0x73,0x19,0x67,0x5c,0x1b,0x11,0x21])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a094170,d0x6a0dab50,[1])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a08f170,d0x6a0dab50,[1])
|
||||
ws.sbox(d0x6a08f170,d0x6a0dab50,[1])
|
||||
ws.sbox(d0x6a094170,d0x6a0dab50,[1])
|
||||
|
||||
ws.exlookup(d0x6a093170)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
#break
|
||||
return bytes(out)
|
||||
|
||||
def process_V3646(st):
|
||||
#d468aa362b44479282291983243b38197c4b4aa24c2c58e62c76ec4b81e08556ca0c54301664
|
||||
ws=workspace([0x0a,0x36,0x3e,0x29,0x4e,0x02,0x18,0x38,0x01,0x36,0x73,0x13,0x14,0x1b,0x16,0x6a])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.sbox(d0x6a099e48,d0x6a0dab50,[2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a09ee48,d0x6a0dab50,[2,3])
|
||||
ws.exlookup(d0x6a09de48)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def process_V6052(st):
|
||||
#d683c8c4e4f46ae45812196f37e218eabce0fae08994f25fabb01d3e569b8bf3866b99d36f57
|
||||
ws=workspace([0x5f,0x0d,0x01,0x12,0x5d,0x5c,0x14,0x2a,0x17,0x69,0x14,0x0d,0x09,0x21,0x1e,0x3b])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a9b20,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0a4b20,d0x6a0dab50,[1,3])
|
||||
|
||||
ws.exlookup(d0x6a0a8b20)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V9479(st):
|
||||
#925635db434bccd3f4791eb87b89d2dfc7c93be06e794744eb9de58e6d721e696980680ab551
|
||||
ws=workspace([0x65,0x1d,0x19,0x7c,0x09,0x79,0x1d,0x69,0x7c,0x4e,0x13,0x0e,0x04,0x1b,0x6a,0x3c ])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.sbox(d0x6a0af7f8,d0x6a0dab50,[1,2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0b47f8,d0x6a0dab50,[1,2,3])
|
||||
ws.exlookup(d0x6a0b37f8)
|
||||
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V9888(st):
|
||||
#54c470723f8c105ba0186b6319050869de673ce31a5ec15d4439921d4cd05c5e860cb2a41fea
|
||||
ws=workspace([0x3f,0x17,0x79,0x69,0x24,0x6b,0x37,0x50,0x63,0x09,0x45,0x6f,0x0c,0x07,0x07,0x09])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
|
||||
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
|
||||
ws.exlookup(d0x6a0be4d0)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V4648(st):
|
||||
#705bd4cd8b61d4596ef4ca40774d68e71f1f846c6e94bd23fd26e5c127e0beaa650a50171f1b
|
||||
ws=workspace([0x16,0x2b,0x64,0x62,0x13,0x04,0x18,0x0d,0x63,0x25,0x14,0x17,0x0f,0x13,0x46,0x0c])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0ca1a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
|
||||
ws.shuffle(repl)
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a0c91a8)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
def process_V5683(st):
|
||||
#1f5af733423e5104afb9d5594e682ecf839a776257f33747c9beee671c57ab3f84943f69d8fd
|
||||
ws=workspace([0x7c,0x36,0x5c,0x1a,0x0d,0x10,0x0a,0x50,0x07,0x0f,0x75,0x1f,0x09,0x3b,0x0d,0x72])
|
||||
repl=[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]
|
||||
remln=len(st)
|
||||
sto=0
|
||||
out=[]
|
||||
while(remln>0):
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.sbox(d0x6a0d4e80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
|
||||
ws.shuffle(repl)
|
||||
ws.exlookup(d0x6a0d3e80)
|
||||
dat=ws.mask(st[sto:sto+16])
|
||||
out+=dat
|
||||
sto+=16
|
||||
remln-=16
|
||||
return bytes(out)
|
||||
|
||||
|
||||
# def a2hex(arr):
|
||||
# ax=[]
|
||||
# ha="0123456789abcdef"
|
||||
# for a in arr:
|
||||
# if a<0: a=256+a
|
||||
# ax.append(ha[(a>>4)]+ha[a%16])
|
||||
# return "".join(ax)
|
||||
#
|
||||
# def memhex(adr,sz):
|
||||
# emu=EmulatorHelper(currentProgram)
|
||||
# arr=emu.readMemory(getAddress(adr),sz)
|
||||
# return a2hex(arr)
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
# obfuscate shared secret according to the VoucherEnvelope version
|
||||
def obfuscate(secret, version):
|
||||
if version == 1: # v1 does not use obfuscation
|
||||
@@ -835,6 +1194,107 @@ def obfuscate(secret, version):
|
||||
return obfuscated
|
||||
|
||||
|
||||
|
||||
# scramble() and obfuscate2() from https://github.com/andrewc12/DeDRM_tools/commit/d9233d61f00d4484235863969919059f4d0b2057
|
||||
|
||||
def scramble(st,magic):
|
||||
ret=bytearray(len(st))
|
||||
padlen=len(st)
|
||||
for counter in range(len(st)):
|
||||
ivar2=(padlen//2)-2*(counter%magic)+magic+counter-1
|
||||
ret[ivar2%padlen]=st[counter]
|
||||
return ret
|
||||
|
||||
|
||||
def obfuscate2(secret, version):
|
||||
if version == 1: # v1 does not use obfuscation
|
||||
return secret
|
||||
magic, word = OBFUSCATION_TABLE["V%d" % version]
|
||||
# extend secret so that its length is divisible by the magic number
|
||||
if len(secret) % magic != 0:
|
||||
secret = secret + b'\x00' * (magic - len(secret) % magic)
|
||||
obfuscated = bytearray(len(secret))
|
||||
wordhash = bytearray(hashlib.sha256(word).digest()[16:])
|
||||
#print(wordhash.hex())
|
||||
shuffled = bytearray(scramble(secret,magic))
|
||||
for i in range(0, len(secret)):
|
||||
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
|
||||
return obfuscated
|
||||
|
||||
# scramble3() and obfuscate3() from https://github.com/Satsuoni/DeDRM_tools/commit/da6b6a0c911b6d45fe1b13042b690daebc1cc22f
|
||||
|
||||
def scramble3(st,magic):
|
||||
ret=bytearray(len(st))
|
||||
padlen=len(st)
|
||||
divs = padlen // magic
|
||||
cntr = 0
|
||||
iVar6 = 0
|
||||
offset = 0
|
||||
if (0 < ((magic - 1) + divs)):
|
||||
while True:
|
||||
if (offset & 1) == 0 :
|
||||
uVar4 = divs - 1
|
||||
if offset < divs:
|
||||
iVar3 = 0
|
||||
uVar4 = offset
|
||||
else:
|
||||
iVar3 = (offset - divs) + 1
|
||||
if uVar4>=0:
|
||||
iVar5 = uVar4 * magic
|
||||
index = ((padlen - 1) - cntr)
|
||||
while True:
|
||||
if (magic <= iVar3): break
|
||||
ret[index] = st[iVar3 + iVar5]
|
||||
iVar3 = iVar3 + 1
|
||||
cntr = cntr + 1
|
||||
uVar4 = uVar4 - 1
|
||||
iVar5 = iVar5 - magic
|
||||
index -= 1
|
||||
if uVar4<=-1: break
|
||||
else:
|
||||
if (offset < magic):
|
||||
iVar3 = 0
|
||||
else :
|
||||
iVar3 = (offset - magic) + 1
|
||||
if (iVar3 < divs):
|
||||
uVar4 = offset
|
||||
if (magic <= offset):
|
||||
uVar4 = magic - 1
|
||||
|
||||
index = ((padlen - 1) - cntr)
|
||||
iVar5 = iVar3 * magic
|
||||
while True:
|
||||
if (uVar4 < 0) : break
|
||||
iVar3 += 1
|
||||
ret[index] = st[uVar4 + iVar5]
|
||||
uVar4 -= 1
|
||||
index=index-1
|
||||
iVar5 = iVar5 + magic;
|
||||
cntr += 1;
|
||||
if iVar3>=divs: break
|
||||
offset = offset + 1
|
||||
if offset >= ((magic - 1) + divs) :break
|
||||
return ret
|
||||
|
||||
#not sure if the third variant is used anywhere, but it is in Kindle, so I tried to add it
|
||||
def obfuscate3(secret, version):
|
||||
if version == 1: # v1 does not use obfuscation
|
||||
return secret
|
||||
magic, word = OBFUSCATION_TABLE["V%d" % version]
|
||||
# extend secret so that its length is divisible by the magic number
|
||||
if len(secret) % magic != 0:
|
||||
secret = secret + b'\x00' * (magic - len(secret) % magic)
|
||||
#secret = bytearray(secret)
|
||||
obfuscated = bytearray(len(secret))
|
||||
wordhash = bytearray(hashlib.sha256(word).digest())
|
||||
#print(wordhash.hex())
|
||||
shuffled=bytearray(scramble3(secret,magic))
|
||||
#print(shuffled)
|
||||
# shuffle secret and xor it with the first half of the word hash
|
||||
for i in range(0, len(secret)):
|
||||
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
|
||||
return obfuscated
|
||||
|
||||
class DrmIonVoucher(object):
|
||||
envelope = None
|
||||
version = None
|
||||
@@ -878,18 +1338,34 @@ class DrmIonVoucher(object):
|
||||
else:
|
||||
_assert(False, "Unknown lock parameter: %s" % param)
|
||||
|
||||
sharedsecret = obfuscate(shared, self.version)
|
||||
|
||||
key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
|
||||
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
|
||||
b = aes.decrypt(self.ciphertext)
|
||||
b = pkcs7unpad(b, 16)
|
||||
# i know that version maps to scramble pretty much 1 to 1, but there was precendent where they changed it, so...
|
||||
sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version),
|
||||
process_V9708(shared), process_V1031(shared), process_V2069(shared), process_V9041(shared),
|
||||
process_V3646(shared), process_V6052(shared), process_V9479(shared), process_V9888(shared),
|
||||
process_V4648(shared), process_V5683(shared)]
|
||||
|
||||
decrypted=False
|
||||
ex=None
|
||||
for sharedsecret in sharedsecrets:
|
||||
key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
|
||||
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
|
||||
try:
|
||||
b = aes.decrypt(self.ciphertext)
|
||||
b = pkcs7unpad(b, 16)
|
||||
self.drmkey = BinaryIonParser(BytesIO(b))
|
||||
addprottable(self.drmkey)
|
||||
|
||||
self.drmkey = BinaryIonParser(BytesIO(b))
|
||||
addprottable(self.drmkey)
|
||||
_assert(self.drmkey.hasnext() and self.drmkey.next() == TID_LIST and self.drmkey.gettypename() == "com.amazon.drm.KeySet@1.0",
|
||||
"Expected KeySet, got %s" % self.drmkey.gettypename())
|
||||
decrypted=True
|
||||
|
||||
_assert(self.drmkey.hasnext() and self.drmkey.next() == TID_LIST and self.drmkey.gettypename() == "com.amazon.drm.KeySet@1.0",
|
||||
"Expected KeySet, got %s" % self.drmkey.gettypename())
|
||||
print("Decryption succeeded")
|
||||
break
|
||||
except Exception as ex:
|
||||
print("Decryption failed, trying next fallback ")
|
||||
if not decrypted:
|
||||
raise ex
|
||||
|
||||
self.drmkey.stepin()
|
||||
while self.drmkey.hasnext():
|
||||
|
||||
5771
DeDRM_plugin/kfxtables.py
Normal file
5771
DeDRM_plugin/kfxtables.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -279,7 +279,10 @@ if iswindows:
|
||||
path = ""
|
||||
if 'LOCALAPPDATA' in os.environ.keys():
|
||||
# Python 2.x does not return unicode env. Use Python 3.x
|
||||
path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
|
||||
if sys.version_info[0] == 2:
|
||||
path = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
|
||||
else:
|
||||
path = winreg.ExpandEnvironmentStrings("%LOCALAPPDATA%")
|
||||
# this is just another alternative.
|
||||
# path = getEnvironmentVariable('LOCALAPPDATA')
|
||||
if not os.path.isdir(path):
|
||||
|
||||
@@ -7,6 +7,18 @@ from __future__ import absolute_import, print_function
|
||||
|
||||
# Copyright © 2021 NoDRM
|
||||
|
||||
"""
|
||||
|
||||
NOTE: This code is not functional (yet). I started working on it a while ago
|
||||
to make a standalone version of the plugins that could work without Calibre,
|
||||
too, but for now there's only a rough code structure and no working code yet.
|
||||
|
||||
Currently, to use these plugins, you will need to use Calibre. Hopwfully that'll
|
||||
change in the future.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
OPT_SHORT_TO_LONG = [
|
||||
["c", "config"],
|
||||
["e", "extract"],
|
||||
|
||||
@@ -8,6 +8,17 @@ from __future__ import absolute_import, print_function
|
||||
|
||||
# Taken from Calibre code - Copyright © 2008, Kovid Goyal kovid@kovidgoyal.net, GPLv3
|
||||
|
||||
"""
|
||||
|
||||
NOTE: This code is not functional (yet). I started working on it a while ago
|
||||
to make a standalone version of the plugins that could work without Calibre,
|
||||
too, but for now there's only a rough code structure and no working code yet.
|
||||
|
||||
Currently, to use these plugins, you will need to use Calibre. Hopwfully that'll
|
||||
change in the future.
|
||||
|
||||
"""
|
||||
|
||||
#@@CALIBRE_COMPAT_CODE@@
|
||||
|
||||
import sys, os, codecs, json
|
||||
|
||||
@@ -8,6 +8,17 @@ from __future__ import absolute_import, print_function
|
||||
|
||||
# Copyright © 2021 NoDRM
|
||||
|
||||
"""
|
||||
|
||||
NOTE: This code is not functional (yet). I started working on it a while ago
|
||||
to make a standalone version of the plugins that could work without Calibre,
|
||||
too, but for now there's only a rough code structure and no working code yet.
|
||||
|
||||
Currently, to use these plugins, you will need to use Calibre. Hopwfully that'll
|
||||
change in the future.
|
||||
|
||||
"""
|
||||
|
||||
#@@CALIBRE_COMPAT_CODE@@
|
||||
|
||||
import os, sys
|
||||
|
||||
@@ -8,6 +8,17 @@ from __future__ import absolute_import, print_function
|
||||
|
||||
# Copyright © 2021 NoDRM
|
||||
|
||||
"""
|
||||
|
||||
NOTE: This code is not functional (yet). I started working on it a while ago
|
||||
to make a standalone version of the plugins that could work without Calibre,
|
||||
too, but for now there's only a rough code structure and no working code yet.
|
||||
|
||||
Currently, to use these plugins, you will need to use Calibre. Hopwfully that'll
|
||||
change in the future.
|
||||
|
||||
"""
|
||||
|
||||
#@@CALIBRE_COMPAT_CODE@@
|
||||
|
||||
import os, sys
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
# topazextract.py
|
||||
# Mostly written by some_updates based on code from many others
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__version__ = '10.0.3'
|
||||
__version__ = '10.0.9'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
#####################################################################
|
||||
@@ -20,7 +20,7 @@ except NameError:
|
||||
PLUGIN_NAME = 'Obok DeDRM'
|
||||
PLUGIN_SAFE_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_')
|
||||
PLUGIN_DESCRIPTION = _('Removes DRM from Kobo kepubs and adds them to the library.')
|
||||
PLUGIN_VERSION_TUPLE = (10, 0, 3)
|
||||
PLUGIN_VERSION_TUPLE = (10, 0, 9)
|
||||
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
|
||||
HELPFILE_NAME = PLUGIN_SAFE_NAME + '_Help.htm'
|
||||
PLUGIN_AUTHORS = 'Anon'
|
||||
|
||||
@@ -168,8 +168,8 @@
|
||||
"""Manage all Kobo books, either encrypted or DRM-free."""
|
||||
from __future__ import print_function
|
||||
|
||||
__version__ = '10.0.1'
|
||||
__about__ = "Obok v{0}\nCopyright © 2012-2022 Physisticated et al.".format(__version__)
|
||||
__version__ = '10.0.9'
|
||||
__about__ = "Obok v{0}\nCopyright © 2012-2023 Physisticated et al.".format(__version__)
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<body>
|
||||
|
||||
<h1>Obok DeDRM Plugin</h1>
|
||||
<h3>(version 10.0.2)</h3>
|
||||
<h3>(version 10.0.9 / 10.1.0 RC1)</h3>
|
||||
|
||||
<h3>Installation:</h3>
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ DeDRM tools for ebooks
|
||||
|
||||
This is a fork of Apprentice Harper's version of the DeDRM tools. Apprentice Harper said that the original version of the plugin [is no longer maintained](https://github.com/apprenticeharper/DeDRM_tools#no-longer-maintained), so I've taken over, merged a bunch of open PRs, and added a ton more features and bugfixes.
|
||||
|
||||
The latest stable (released) version is v10.0.3 which [can be downloaded here](https://github.com/noDRM/DeDRM_tools/releases/tag/v10.0.3).
|
||||
|
||||
Take a look at [the CHANGELOG](https://github.com/noDRM/DeDRM_tools/blob/master/CHANGELOG.md) to see a list of changes since the last version by Apprentice Harper (v7.2.1). This plugin will start with version v10.0.0.
|
||||
|
||||
The v10.0.0 versions of this plugin should both work with Calibre 5.x (Python 3) as well as Calibre 4.x and lower (Python 2). If you encounter issues with this plugin in Calibre 4.x or lower, please open a bug report.
|
||||
|
||||
Reference in New Issue
Block a user