diff --git a/Other_Tools/Adobe_PDF_Tools/ineptpdf8.pyw b/Other_Tools/Adobe_PDF_Tools/ineptpdf8.pyw
index 9ad2c54..433f5cb 100644
--- a/Other_Tools/Adobe_PDF_Tools/ineptpdf8.pyw
+++ b/Other_Tools/Adobe_PDF_Tools/ineptpdf8.pyw
@@ -1,7 +1,7 @@
#! /usr/bin/python
-# ineptpdf8.4.48.pyw
-# ineptpdf, version 8.4.48
+# ineptpdf8.4.51.pyw
+# ineptpdf, version 8.4.51
# To run this program install Python 2.7 from http://www.python.org/download/
#
@@ -16,7 +16,7 @@
# Windows system).
#
# 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:
# 1 - Initial release
@@ -103,6 +103,10 @@
# 8.4.46 - script cleanup and optimizations (Tetrachroma)
# 8.4.47 - script identification change to Adobe Reader (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.
@@ -139,6 +143,7 @@ import traceback
import inspect
import tempfile
import sqlite3
+import httplib
try:
from Crypto.Cipher import ARC4
# needed for newer pdfs
@@ -162,7 +167,7 @@ INPUTFILEPATH = ''
KEYFILEPATH = ''
PASSWORD = ''
DEBUG_MODE = False
-IVERSION = '8.4.48'
+IVERSION = '8.4.51'
# Do we generate cross reference streams on output?
# 0 = never
@@ -1333,11 +1338,74 @@ class PDFDocument(object):
self.decipher = self.decrypt_aes
self.ready = True
return
+
+ def getPrincipalKey(self, k=None, url=None, referer=None):
+ if url == None:
+ url="ssl://edc.bibliothek-digital.de/edcws/services/urn:EDCLicenseService"
+ data1='<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>7de-de'+\
+ '10'+\
+ 'licenseSeqNum>10<'+\
+ 'watermarkTemplateSeqNum>0'+\
+ 'impl:synchronize>'
+ 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"((?!).)*]*>(((?!).)*)', re.I).search(responsedata).group(2)
+
+ except :
+ key=None
+ return key
def genkey_adobe_ps(self, param):
# nice little offline principal keys dictionary
- # global static principal key for German Onleihe / Bibliothek Digital
- principalkeys = { 'bibliothek-digital.de': 'rRwGv2tbpKov1krvv7PO0ws9S436/lArPlfipz5Pqhw='.decode('base64')}
+ principalkeys = { 'bibliothek-digital.de': 'Dzqx8McQUNd2CDzBVmtnweUxVWlqJTMqyYtiDIc4dZI='.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
## print 'keyvalue'
## print len(keyvalue)
@@ -1350,27 +1418,39 @@ class PDFDocument(object):
edclist = []
for pair in edcdata.split('\n'):
edclist.append(pair)
- #print edclist
- #print 'edcdata decrypted'
- #print edclist[0].decode('base64').encode('hex')
- #print edclist[1].decode('base64').encode('hex')
- #print edclist[2].decode('base64').encode('hex')
- #print edclist[3].decode('base64').encode('hex')
- #print 'offlinekey'
- #print len(edclist[9].decode('base64'))
- #print pdrllic
+## print edclist
+## print 'edcdata decrypted'
+## print edclist[0].decode('base64').encode('hex')
+## print edclist[1].decode('base64').encode('hex')
+## print edclist[2].decode('base64').encode('hex')
+## print edclist[3].decode('base64').encode('hex')
+## print 'offlinekey'
+## print len(edclist[9].decode('base64'))
+## print pdrllic
# principal key request
for key in principalkeys:
if key in pdrllic:
principalkey = principalkeys[key]
else:
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)
#print shakey
plaintext = AES.new(shakey,AES.MODE_CBC,ivector).decrypt(edclist[9].decode('base64'))
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)
if ord(pdrlpol[-1]) < 1 or ord(pdrlpol[-1]) > 16:
raise ADEPTError('Could not decrypt PDRLPol, aborting ...')
@@ -1633,8 +1713,8 @@ class PDFDocument(object):
self.fo_sethwids = self.fo_linux_sethwids
else:
adeptout = ''
- adeptout = adeptout + 'Due to various privacy violations from Apple\n'
- adeptout = adeptout + 'Mac OS X support is disabled by default.'
+ adeptout = adeptout + 'Mac OS X is not supported, yet.'
+ adeptout = adeptout + 'Read the blogs FAQs for more information'
raise ADEPTError(adeptout)
# add static arguments for http/https request
self.fo_setattributes()
@@ -1720,8 +1800,10 @@ class PDFDocument(object):
self.fileopen['RequestSchema'] = self.surlresult['RequestSchema']
if 'ServerSessionData' in self.surlresult:
self.fileopen['ServerSessionData'] = self.surlresult['ServerSessionData']
+ if 'SetScope' in self.surlresult:
+ self.fileopen['RequestSchema'] = self.surlresult['SetScope']
#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['SetTarget'] == 'UnpDlg')):
# get user and password dialog
@@ -2173,7 +2255,8 @@ class PDFDocument(object):
## self.fileopen['Uuid'] = self.genkey_cryptmach(userkey,1)[4:]
## else:
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:
self.fileopen['Uuid'] = str(uuid.uuid1())
# get time stamp
@@ -3063,7 +3146,7 @@ def gui_main():
"This script requires PyCrypto, which must be installed "
"separately. Read the top-of-script comment for details.")
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.minsize(370, 0)
DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1)