ineptpdf 8.4.51
This commit is contained in:
parent
07ea87edf4
commit
4b3618246b
|
@ -1,7 +1,7 @@
|
||||||
#! /usr/bin/python
|
#! /usr/bin/python
|
||||||
|
|
||||||
# ineptpdf8.4.48.pyw
|
# ineptpdf8.4.51.pyw
|
||||||
# ineptpdf, version 8.4.48
|
# ineptpdf, version 8.4.51
|
||||||
|
|
||||||
# To run this program install Python 2.7 from http://www.python.org/download/
|
# To run this program install Python 2.7 from http://www.python.org/download/
|
||||||
#
|
#
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
# Windows system).
|
# Windows system).
|
||||||
#
|
#
|
||||||
# Save this script file as
|
# Save this script file as
|
||||||
# ineptpdf8.4.48.pyw and double-click on it to run it.
|
# ineptpdf8.4.51.pyw and double-click on it to run it.
|
||||||
|
|
||||||
# Revision history:
|
# Revision history:
|
||||||
# 1 - Initial release
|
# 1 - Initial release
|
||||||
|
@ -103,6 +103,10 @@
|
||||||
# 8.4.46 - script cleanup and optimizations (Tetrachroma)
|
# 8.4.46 - script cleanup and optimizations (Tetrachroma)
|
||||||
# 8.4.47 - script identification change to Adobe Reader (Tetrachroma)
|
# 8.4.47 - script identification change to Adobe Reader (Tetrachroma)
|
||||||
# 8.4.48 - improved tolerance for false file/registry entries (Tetrachroma)
|
# 8.4.48 - improved tolerance for false file/registry entries (Tetrachroma)
|
||||||
|
# 8.4.49 - improved username encryption (Tetrachroma)
|
||||||
|
# 8.4.50 - improved (experimental) APS support (Tetrachroma & Neisklar)
|
||||||
|
# 8.4.51 - automatic APS offline key retrieval (works only for
|
||||||
|
# Onleihe right now) (80ka80 & Tetrachroma)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Decrypts Adobe ADEPT-encrypted and Fileopen PDF files.
|
Decrypts Adobe ADEPT-encrypted and Fileopen PDF files.
|
||||||
|
@ -139,6 +143,7 @@ import traceback
|
||||||
import inspect
|
import inspect
|
||||||
import tempfile
|
import tempfile
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import httplib
|
||||||
try:
|
try:
|
||||||
from Crypto.Cipher import ARC4
|
from Crypto.Cipher import ARC4
|
||||||
# needed for newer pdfs
|
# needed for newer pdfs
|
||||||
|
@ -162,7 +167,7 @@ INPUTFILEPATH = ''
|
||||||
KEYFILEPATH = ''
|
KEYFILEPATH = ''
|
||||||
PASSWORD = ''
|
PASSWORD = ''
|
||||||
DEBUG_MODE = False
|
DEBUG_MODE = False
|
||||||
IVERSION = '8.4.48'
|
IVERSION = '8.4.51'
|
||||||
|
|
||||||
# Do we generate cross reference streams on output?
|
# Do we generate cross reference streams on output?
|
||||||
# 0 = never
|
# 0 = never
|
||||||
|
@ -1333,11 +1338,74 @@ class PDFDocument(object):
|
||||||
self.decipher = self.decrypt_aes
|
self.decipher = self.decrypt_aes
|
||||||
self.ready = True
|
self.ready = True
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def getPrincipalKey(self, k=None, url=None, referer=None):
|
||||||
|
if url == None:
|
||||||
|
url="ssl://edc.bibliothek-digital.de/edcws/services/urn:EDCLicenseService"
|
||||||
|
data1='<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SO'+\
|
||||||
|
'AP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http'+\
|
||||||
|
'://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/'+\
|
||||||
|
'XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns1="'+\
|
||||||
|
'http://edc.adobe.com/edcwebservice" xmlns:impl="http://localhost:8080/axis/s'+\
|
||||||
|
'ervices/urn:EDCLicenseService" xmlns:ns2="http://common.edc.adobe.com" xmlns:ns1="'+\
|
||||||
|
'http://ns.adobe.com/PolicyServer/ws"><SOAP-ENV:Header><EDCSecurity><wsse:Security '+\
|
||||||
|
'xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-'+\
|
||||||
|
'1.0.xsd"><wsse:UsernameToken><wsse:Username>edc_anonymous</wsse:Username&'+\
|
||||||
|
'gt;<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-'+\
|
||||||
|
'token-profile-1.0#PasswordText">edc_anonymous</wsse:Password></wsse:UsernameToken&'+\
|
||||||
|
'gt;</wsse:Security></EDCSecurity><Version>7</Version><Locale>de-de</Locale></SOAP-ENV:Header>'+\
|
||||||
|
'<SOAP-ENV:Body><impl:synchronize><SynchronizationRequest><firstTime>1</firstTime><licenseSeqNum>0</'+\
|
||||||
|
'licenseSeqNum><policySeqNum>1</policySeqNum><revocationSeqNum>0</revocationSeqNum><'+\
|
||||||
|
'watermarkTemplateSeqNum>0</watermarkTemplateSeqNum></SynchronizationRequest></'+\
|
||||||
|
'impl:synchronize></SOAP-ENV:Body></SOAP-ENV:Envelope>'
|
||||||
|
if k not in url[:40]:
|
||||||
|
return None
|
||||||
|
#~ extract host and path:
|
||||||
|
host=re.compile(r'[a-zA-Z]://([^/]+)/.+', re.I).search(url).group(1)
|
||||||
|
urlpath=re.compile(r'[a-zA-Z]://[^/]+(/.+)', re.I).search(url).group(1)
|
||||||
|
|
||||||
|
# open a socket connection on port 80
|
||||||
|
|
||||||
|
conn = httplib.HTTPSConnection(host, 443)
|
||||||
|
|
||||||
|
#~ Headers for request
|
||||||
|
headers={"Accept": "*/*", "Host": host, "User-Agent": "Mozilla/3.0 (compatible; Acrobat EDC SOAP 1.0)",
|
||||||
|
"Content-Type": "text/xml; charset=utf-8", "Cache-Control": "no-cache", "SOAPAction": ""}
|
||||||
|
|
||||||
|
# send data1 and headers
|
||||||
|
try:
|
||||||
|
conn.request("POST", urlpath, data1, headers)
|
||||||
|
except:
|
||||||
|
raise ADEPTError("Could not post request to '"+host+"'.")
|
||||||
|
|
||||||
|
# read respose
|
||||||
|
try:
|
||||||
|
response = conn.getresponse()
|
||||||
|
responsedata=response.read()
|
||||||
|
except:
|
||||||
|
raise ADEPTError("Could not read response from '"+host+"'.")
|
||||||
|
|
||||||
|
# close connection
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
try:
|
||||||
|
key=re.compile(r'PricipalKey"((?!<key>).)*<key[^>]*>(((?!</key>).)*)</key>', re.I).search(responsedata).group(2)
|
||||||
|
|
||||||
|
except :
|
||||||
|
key=None
|
||||||
|
return key
|
||||||
|
|
||||||
def genkey_adobe_ps(self, param):
|
def genkey_adobe_ps(self, param):
|
||||||
# nice little offline principal keys dictionary
|
# nice little offline principal keys dictionary
|
||||||
# global static principal key for German Onleihe / Bibliothek Digital
|
principalkeys = { 'bibliothek-digital.de': 'Dzqx8McQUNd2CDzBVmtnweUxVWlqJTMqyYtiDIc4dZI='.decode('base64')}
|
||||||
principalkeys = { 'bibliothek-digital.de': 'rRwGv2tbpKov1krvv7PO0ws9S436/lArPlfipz5Pqhw='.decode('base64')}
|
for k, v in principalkeys.iteritems():
|
||||||
|
result = self.getPrincipalKey(k)
|
||||||
|
#print result
|
||||||
|
if result != None:
|
||||||
|
principalkeys[k] = result.decode('base64')
|
||||||
|
else:
|
||||||
|
raise ADEPTError("No (Online) PrincipalKey found.")
|
||||||
|
|
||||||
self.is_printable = self.is_modifiable = self.is_extractable = True
|
self.is_printable = self.is_modifiable = self.is_extractable = True
|
||||||
## print 'keyvalue'
|
## print 'keyvalue'
|
||||||
## print len(keyvalue)
|
## print len(keyvalue)
|
||||||
|
@ -1350,27 +1418,39 @@ class PDFDocument(object):
|
||||||
edclist = []
|
edclist = []
|
||||||
for pair in edcdata.split('\n'):
|
for pair in edcdata.split('\n'):
|
||||||
edclist.append(pair)
|
edclist.append(pair)
|
||||||
#print edclist
|
## print edclist
|
||||||
#print 'edcdata decrypted'
|
## print 'edcdata decrypted'
|
||||||
#print edclist[0].decode('base64').encode('hex')
|
## print edclist[0].decode('base64').encode('hex')
|
||||||
#print edclist[1].decode('base64').encode('hex')
|
## print edclist[1].decode('base64').encode('hex')
|
||||||
#print edclist[2].decode('base64').encode('hex')
|
## print edclist[2].decode('base64').encode('hex')
|
||||||
#print edclist[3].decode('base64').encode('hex')
|
## print edclist[3].decode('base64').encode('hex')
|
||||||
#print 'offlinekey'
|
## print 'offlinekey'
|
||||||
#print len(edclist[9].decode('base64'))
|
## print len(edclist[9].decode('base64'))
|
||||||
#print pdrllic
|
## print pdrllic
|
||||||
# principal key request
|
# principal key request
|
||||||
for key in principalkeys:
|
for key in principalkeys:
|
||||||
if key in pdrllic:
|
if key in pdrllic:
|
||||||
principalkey = principalkeys[key]
|
principalkey = principalkeys[key]
|
||||||
else:
|
else:
|
||||||
raise ADEPTError('Cannot find principal key for this pdf')
|
raise ADEPTError('Cannot find principal key for this pdf')
|
||||||
shakey = SHA256.new(principalkey).digest()
|
## print 'minorversion'
|
||||||
|
## print int(edclist[8])
|
||||||
|
# fix for minor version
|
||||||
|
## minorversion = int(edclist[8]) - 100
|
||||||
|
## if minorversion < 1:
|
||||||
|
## minorversion = 1
|
||||||
|
## print int(minorversion)
|
||||||
|
shakey = SHA256.new()
|
||||||
|
shakey.update(principalkey)
|
||||||
|
## for i in range(0,minorversion):
|
||||||
|
## shakey.update(principalkey)
|
||||||
|
shakey = shakey.digest()
|
||||||
|
## shakey = SHA256.new(principalkey).digest()
|
||||||
ivector = 16 * chr(0)
|
ivector = 16 * chr(0)
|
||||||
#print shakey
|
#print shakey
|
||||||
plaintext = AES.new(shakey,AES.MODE_CBC,ivector).decrypt(edclist[9].decode('base64'))
|
plaintext = AES.new(shakey,AES.MODE_CBC,ivector).decrypt(edclist[9].decode('base64'))
|
||||||
if plaintext[-16:] != 16 * chr(16):
|
if plaintext[-16:] != 16 * chr(16):
|
||||||
raise ADEPTError('Offlinekey cannot be decrypted, aborting ...')
|
raise ADEPTError('Offlinekey cannot be decrypted, aborting (hint: redownload pdf) ...')
|
||||||
pdrlpol = AES.new(plaintext[16:32],AES.MODE_CBC,edclist[2].decode('base64')).decrypt(pdrlpol)
|
pdrlpol = AES.new(plaintext[16:32],AES.MODE_CBC,edclist[2].decode('base64')).decrypt(pdrlpol)
|
||||||
if ord(pdrlpol[-1]) < 1 or ord(pdrlpol[-1]) > 16:
|
if ord(pdrlpol[-1]) < 1 or ord(pdrlpol[-1]) > 16:
|
||||||
raise ADEPTError('Could not decrypt PDRLPol, aborting ...')
|
raise ADEPTError('Could not decrypt PDRLPol, aborting ...')
|
||||||
|
@ -1633,8 +1713,8 @@ class PDFDocument(object):
|
||||||
self.fo_sethwids = self.fo_linux_sethwids
|
self.fo_sethwids = self.fo_linux_sethwids
|
||||||
else:
|
else:
|
||||||
adeptout = ''
|
adeptout = ''
|
||||||
adeptout = adeptout + 'Due to various privacy violations from Apple\n'
|
adeptout = adeptout + 'Mac OS X is not supported, yet.'
|
||||||
adeptout = adeptout + 'Mac OS X support is disabled by default.'
|
adeptout = adeptout + 'Read the blogs FAQs for more information'
|
||||||
raise ADEPTError(adeptout)
|
raise ADEPTError(adeptout)
|
||||||
# add static arguments for http/https request
|
# add static arguments for http/https request
|
||||||
self.fo_setattributes()
|
self.fo_setattributes()
|
||||||
|
@ -1720,8 +1800,10 @@ class PDFDocument(object):
|
||||||
self.fileopen['RequestSchema'] = self.surlresult['RequestSchema']
|
self.fileopen['RequestSchema'] = self.surlresult['RequestSchema']
|
||||||
if 'ServerSessionData' in self.surlresult:
|
if 'ServerSessionData' in self.surlresult:
|
||||||
self.fileopen['ServerSessionData'] = self.surlresult['ServerSessionData']
|
self.fileopen['ServerSessionData'] = self.surlresult['ServerSessionData']
|
||||||
|
if 'SetScope' in self.surlresult:
|
||||||
|
self.fileopen['RequestSchema'] = self.surlresult['SetScope']
|
||||||
#print self.surlresult
|
#print self.surlresult
|
||||||
if 'RetVal' in self.surlresult and (('Reason' in self.surlresult and \
|
if 'RetVal' in self.surlresult and 'SEMO' not in self.fileopen and(('Reason' in self.surlresult and \
|
||||||
self.surlresult['Reason'] == 'AskUnp') or ('SetTarget' in self.surlresult and\
|
self.surlresult['Reason'] == 'AskUnp') or ('SetTarget' in self.surlresult and\
|
||||||
self.surlresult['SetTarget'] == 'UnpDlg')):
|
self.surlresult['SetTarget'] == 'UnpDlg')):
|
||||||
# get user and password dialog
|
# get user and password dialog
|
||||||
|
@ -2173,7 +2255,8 @@ class PDFDocument(object):
|
||||||
## self.fileopen['Uuid'] = self.genkey_cryptmach(userkey,1)[4:]
|
## self.fileopen['Uuid'] = self.genkey_cryptmach(userkey,1)[4:]
|
||||||
## else:
|
## else:
|
||||||
except:
|
except:
|
||||||
raise ADEPTError('Cannot find FowP3Uuid file')
|
raise ADEPTError('Cannot find FowP3Uuid file - reason might be Adobe (Reader) X.'\
|
||||||
|
'Read the FAQs for more information how to solve the problem.')
|
||||||
else:
|
else:
|
||||||
self.fileopen['Uuid'] = str(uuid.uuid1())
|
self.fileopen['Uuid'] = str(uuid.uuid1())
|
||||||
# get time stamp
|
# get time stamp
|
||||||
|
@ -3063,7 +3146,7 @@ def gui_main():
|
||||||
"This script requires PyCrypto, which must be installed "
|
"This script requires PyCrypto, which must be installed "
|
||||||
"separately. Read the top-of-script comment for details.")
|
"separately. Read the top-of-script comment for details.")
|
||||||
return 1
|
return 1
|
||||||
root.title('INEPT PDF Decrypter 8.4.48 (FileOpen/APS-Support)')
|
root.title('INEPT PDF Decrypter 8.4.51 (FileOpen/APS-Support)')
|
||||||
root.resizable(True, False)
|
root.resizable(True, False)
|
||||||
root.minsize(370, 0)
|
root.minsize(370, 0)
|
||||||
DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
|
DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)
|
||||||
|
|
Loading…
Reference in New Issue