Changeset 766

Show
Ignore:
Timestamp:
12/12/06 22:01:32 (2 years ago)
Author:
mfenniak
Message:

update CHANGELOG. Begin work on adding encryption support for PDF files. It is incomplete and incorrect at this point.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pypdf/trunk/CHANGELOG

    r760 r766  
     1Version 1.8, YYYY-MM-DD 
     2----------------------- 
     3 
     4 - Add new pythondoc documentation. 
     5 
     6 - Fix bug in ASCII85 decode that occurs when whitespace exists inside the 
     7   two terminating characters of the stream. 
     8 
    19Version 1.7, 2006-12-10 
    210----------------------- 
  • pypdf/trunk/pyPdf/pdf.py

    r765 r766  
    4444 
    4545import filters 
     46import utils 
    4647from generic import * 
    4748from utils import readNonWhitespace, readUntilWhitespace, ConvertFunctionsToVirtualList 
     
    306307            pageObj.update(pages) 
    307308            self.flattenedPages.append(pageObj) 
     309 
     310    def safeGetObject(self, obj): 
     311        if isinstance(obj, IndirectObject): 
     312            return self.safeGetObject(self.getObject(obj)) 
     313        return obj 
    308314 
    309315    def getObject(self, indirectReference): 
     
    504510        return line 
    505511 
     512    # ref: pdf1.8 spec section 3.5.2 algorithm 3.2 
     513    _encryption_padding = '\x28\xbf\x4e\x5e\x4e\x75\x8a\x41\x64\x00\x4e\x56' + \ 
     514            '\xff\xfa\x01\x08\x2e\x2e\x00\xb6\xd0\x68\x3e\x80\x2f\x0c' + \ 
     515            '\xa9\xfe\x64\x53\x69\x7a' 
     516 
     517    def _alg32(self, password, rev, keylen): 
     518        import md5, struct 
     519        m = md5.new() 
     520        password = (password + self._encryption_padding)[:32] 
     521        m.update(password) 
     522        encrypt = self.safeGetObject(self.trailer['/Encrypt']) 
     523        owner_entry = self.safeGetObject(encrypt['/O']) 
     524        m.update(owner_entry) 
     525        p_entry = self.safeGetObject(encrypt['/P']) 
     526        p_entry = struct.pack('<i', p_entry) 
     527        m.update(p_entry) 
     528        id_entry = self.safeGetObject(self.trailer['/ID']) 
     529        id1_entry = self.safeGetObject(id_entry[0]) 
     530        m.update(id1_entry) 
     531        #if rev >= 3: 
     532        #    if document metadata is not being encrypted, pass \xff\xff\xff\xff into hash 
     533        md5_hash = m.digest() 
     534        if rev >= 3: 
     535            for i in range(50): 
     536                m = md5.new() 
     537                m.update(md5_hash[:keylen]) 
     538                md5_hash = m.digest() 
     539        return md5_hash[:keylen] 
     540 
     541    def _alg34(self, password): 
     542        rev = self.safeGetObject(self.safeGetObject(self.trailer['/Encrypt'])['/R']) 
     543        if rev == 2: 
     544            keylen = 5 
     545        key = self._alg32(password, rev, keylen) 
     546        U = utils.RC4_encrypt(key, self._encryption_padding) 
     547        return U 
     548 
     549    ## 
     550    # Decrypt file. 
     551    def decrypt(self, password): 
     552        U = self._alg34(password) 
     553        print "calc U: %r" % U 
     554        print "file U: %r" % self.safeGetObject(self.trailer['/Encrypt'])['/U'] 
    506555 
    507556def getRectangle(self, name, defaults): 
  • pypdf/trunk/pyPdf/utils.py

    r745 r766  
    7171        return self.getFunction(index) 
    7272 
     73def RC4_encrypt(key, plaintext): 
     74    S = [i for i in range(256)] 
     75    j = 0 
     76    for i in range(256): 
     77        j = (j + S[i] + ord(key[i % len(key)])) % 256 
     78        S[i], S[j] = S[j], S[i] 
     79    i, j = 0, 0 
     80    retval = "" 
     81    for x in range(len(plaintext)): 
     82        i = (i + 1) % 256 
     83        j = (j + S[i]) % 256 
     84        S[i], S[j] = S[j], S[i] 
     85        t = S[(S[i] + S[j]) % 256] 
     86        retval += chr(ord(plaintext[x]) ^ t) 
     87    return retval 
    7388 
     89if __name__ == "__main__": 
     90    # test RC4 
     91    out = RC4_encrypt("Key", "Plaintext") 
     92    print repr(out) 
     93    pt = RC4_encrypt("Key", out) 
     94    print repr(pt)