src/reportlab/lib/pdfencrypt.py
author robin
Thu, 24 Oct 2019 16:07:15 +0100
changeset 4551 d357e2acc856
parent 4536 ea5704e5ff9b
permissions -rw-r--r--
improve usage of eval/exec; version --> 3.5.32
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4252
fe660f227cac changes for release 3.3.0
robin
parents: 4116
diff changeset
     1
#copyright ReportLab Europe Limited. 2000-2016
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
     2
#see license.txt for license details
4252
fe660f227cac changes for release 3.3.0
robin
parents: 4116
diff changeset
     3
__version__='3.3.0'
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
     4
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
     5
"""helpers for pdf encryption/decryption"""
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
     6
import sys, os, tempfile
4551
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
     7
from binascii import hexlify, unhexlify
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
     8
from reportlab.lib.utils import getBytesIO, md5, asBytes, int2Byte, char2int, rawUnicode, rawBytes, isPy3, asNative
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
     9
from reportlab.pdfgen.canvas import Canvas
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    10
from reportlab.pdfbase import pdfutils
4000
1718042b25c0 pdfdoc.py, pdfform.py & pdfencrypt.py: switch to using PDFObject inheritance(not __PDFObject__=True) to identify our instances
robin
parents: 3972
diff changeset
    11
from reportlab.pdfbase.pdfdoc import PDFObject
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    12
from reportlab.platypus.flowables import Flowable
4367
9960d82643bf remove ascii, cmp & xrange builtins abuse; version-->3.4.15
robin <robin@reportlab.com>
parents: 4252
diff changeset
    13
from reportlab import rl_config, ascii
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    14
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    15
try:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    16
    import pyaes
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    17
    from hashlib import sha256
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    18
except ImportError:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    19
    pyaes = None
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    20
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    21
if isPy3:
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    22
    def xorKey(num,key):
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    23
        "xor's each byte of the key with the number, which is <256"
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    24
        if num==0: return key
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    25
        return bytes(num^k for k in key)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    26
    bytes3 = bytes
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    27
else:
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    28
    def xorKey(num,key):
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    29
        "xor's each bytes of the key with the number, which is <256"
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    30
        if num==0: return key
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    31
        return ''.join(chr(num^ord(k)) for k in key)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    32
    def bytes3(x):
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    33
        if isinstance(x,basestring):
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    34
            return asBytes(x)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    35
        else:
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    36
            return b''.join([chr(k) for k in x])
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    37
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    38
#AR debug hooks - leaving in for now
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    39
CLOBBERID = 0  # set a constant Doc ID to allow comparison with other software like iText
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    40
CLOBBERPERMISSIONS = 0
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
    41
DEBUG = rl_config.debug # print stuff to trace calculations
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    42
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    43
# permission bits
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    44
reserved1 = 1               # bit 1 must be 0
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    45
reserved2 = 1<<1            # bit 2 must be 0
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    46
printable = 1<<2
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    47
modifiable = 1<<3
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    48
copypastable = 1<<4
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    49
annotatable = 1<<5
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    50
# others [7..32] are reserved, must be 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    51
higherbits = 0
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    52
for i in range(6,31):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    53
    higherbits = higherbits | (1<<i)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    54
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    55
if rl_config.invariant:
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    56
    _os_random_x=0
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    57
    _os_random_b = b'\xbd\x8f\xdc\xabovp\xe8\x15\xec\\C\x9d\x92B~\xb8\xf4\xdeEg8\xb2f\x80Sj\'y\xcfG\xcaY\xb9\xdc-\xc4Q\x17\x88\xaf\xd1\xf7\x7f\xa1L>\x99\x89i\xf7\xc4\xb4\'\xe9k\xc9\xfa\xa6p\x80\xcd\xaa\xaf|\x97\xf7\xcc \xc1\xef\xc7\x97\xd2;\xaf\xe1\xfc\x16,\xd3\x0b\x19\xa1\x02\xe6\x01\xcb\x1c\xd8\xe6\\H}\r\xdc\x85\xe1\xbc\xc4\x02>|\xc5\x97\xb5T\xad\x0cT\x95\xb1\xdc!\xb6+E#\xa1\xa4O\xf3j\x98"\xc2\x1a\xcb\x8cHB\xd8B~\xa7\x7f7\xd2\xe8\x131.\xd7\xa9\x0b\r\xdd2\x0b}\xc0\xffm\x9e3\xe2/\xea\x84W\x82\xbd\xc8K\xc2;?\xbe#\x84`W\xf3\xe0\xec\x9e\x85\x9c\xcb\xc7\xc9#\x19\xff\xde\x17\xea\xb2\xd4\x0e\x9a\xbd\xbaz\xbd\x87O\xd4\xf4\xac\xb3(z\x92\xfc\xbc\x85i\x8d\x1f\xfb!\t|w,\x8bI\xc9_D`A\xbc}\x0e+r\x1b-%F(@\xc8\\cL\x172(\x9c\x95BM\xa1\x89UG\x9d\xfd\xed\xce\xd8\x1f\xb1'
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    58
    def os_urandom(n):
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    59
        global _os_random_x
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    60
        b = [_os_random_b[(i+_os_random_x)%256] for i in range(n)]
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    61
        b = bytes(b) if isPy3 else b''.join(b)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    62
        _os_random_x = (_os_random_x + n) % 256
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    63
        return b
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    64
else:
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    65
    os_urandom = os.urandom
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
    66
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    67
# no encryption
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    68
class StandardEncryption:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    69
    prepared = 0
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    70
    def __init__(self, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=None):
3053
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    71
        '''
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    72
        This class defines the encryption properties to be used while creating a pdf document.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    73
        Once initiated, a StandardEncryption object can be applied to a Canvas or a BaseDocTemplate.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    74
        The userPassword parameter sets the user password on the encrypted pdf.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    75
        The ownerPassword parameter sets the owner password on the encrypted pdf.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    76
        The boolean flags canPrint, canModify, canCopy, canAnnotate determine wether a user can
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    77
        perform the corresponding actions on the pdf when only a user password has been supplied.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    78
        If the user supplies the owner password while opening the pdf, all actions can be performed regardless
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    79
        of the flags.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    80
        Note that the security provided by these encryption settings (and even more so for the flags) is very weak.
e238a5851dd0 Added docstring to the reportlab.lib.pdfencrypt.StandardEncryption constructor.
jonas
parents: 3035
diff changeset
    81
        '''
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    82
        self.userPassword = userPassword
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    83
        if ownerPassword:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    84
            self.ownerPassword = ownerPassword    
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    85
        else:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    86
            self.ownerPassword = userPassword
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    87
        if strength is None:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    88
            strength = rl_config.encryptionStrength
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    89
        if strength == 40:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    90
            self.revision = 2
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    91
        elif strength == 128:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    92
            self.revision = 3
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    93
        elif strength == 256:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    94
            if not pyaes:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    95
                raise ValueError('strength==256 is not supported as package pyaes is not importable')
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    96
            self.revision = 5
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    97
        else:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
    98
            raise ValueError('Unknown encryption strength=%s' % repr(strength))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
    99
        self.canPrint = canPrint
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   100
        self.canModify = canModify
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   101
        self.canCopy = canCopy
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   102
        self.canAnnotate = canAnnotate
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   103
        self.O = self.U = self.P = self.key = self.OE = self.UE = self.Perms =  None
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   104
    def setAllPermissions(self, value):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   105
        self.canPrint = \
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   106
        self.canModify = \
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   107
        self.canCopy = \
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   108
        self.canAnnotate = value
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   109
    def permissionBits(self):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   110
        p = 0
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   111
        if self.canPrint: p = p | printable
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   112
        if self.canModify: p = p | modifiable
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   113
        if self.canCopy: p = p | copypastable
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   114
        if self.canAnnotate: p = p | annotatable
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   115
        p = p | higherbits
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   116
        return p
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   117
    def encode(self, t):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   118
        "encode a string, stream, text"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   119
        if not self.prepared:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   120
            raise ValueError("encryption not prepared!")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   121
        if self.objnum is None:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   122
            raise ValueError("not registered in PDF object")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   123
        return encodePDF(self.key, self.objnum, self.version, t, revision=self.revision)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   124
    def prepare(self, document, overrideID=None):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   125
        # get ready to do encryption
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   126
        if DEBUG: print('StandardEncryption.prepare(...) - revision %d' % self.revision)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   127
        if self.prepared:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   128
            raise ValueError("encryption already prepared!")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   129
        # get the unescaped string value of the document id (first array element).
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   130
        # we allow one to be passed in instead to permit reproducible tests
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   131
        # of our algorithm, but in real life overrideID will always be None
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   132
        if overrideID:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   133
            internalID = overrideID
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   134
        else:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   135
            externalID = document.ID() # initialize it...
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   136
            internalID = document.signature.digest()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   137
            #AR debugging
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   138
            if CLOBBERID:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   139
                internalID = "xxxxxxxxxxxxxxxx"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   140
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   141
        if DEBUG:
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   142
            print('userPassword    = %r' % self.userPassword)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   143
            print('ownerPassword   = %r' % self.ownerPassword)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   144
            print('internalID      = %r' % internalID)
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   145
        self.P = int(self.permissionBits() - 2**31)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   146
        if CLOBBERPERMISSIONS: self.P = -44 # AR hack
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   147
        if DEBUG:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   148
            print("self.P          = %s" % repr(self.P))
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   149
        if self.revision == 5:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   150
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   151
            # Init vectro for AES cipher (should be 16 bytes null array)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   152
            iv  = b'\x00' * 16
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   153
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   154
            # Random User salts
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   155
            uvs = os_urandom(8)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   156
            uks = os_urandom(8)
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   157
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   158
            # the main encryption key
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   159
            self.key = asBytes(os_urandom(32))
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   160
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   161
            if DEBUG:
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   162
                print("uvs      (hex)  = %s" % hexText(uvs))
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   163
                print("uks      (hex)  = %s" % hexText(uks))
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   164
                print("self.key (hex)  = %s" % hexText(self.key))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   165
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   166
            # Calculate the sha-256 hash of the User password (U)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   167
            md = sha256(asBytes(self.userPassword[:127]) + uvs)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   168
            self.U = md.digest() + uvs + uks
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   169
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   170
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   171
                print("self.U (hex)  = %s" % hexText(self.U))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   172
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   173
            # Calculate the User encryption key (UE)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   174
            md = sha256(asBytes(self.userPassword[:127]) + uks)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   175
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   176
            encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(md.digest(), iv=iv))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   177
            self.UE = encrypter.feed(self.key)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   178
            self.UE += encrypter.feed()
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   179
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   180
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   181
                print("self.UE (hex)  = %s" % hexText(self.UE))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   182
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   183
            # Random Owner salts
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   184
            ovs = os_urandom(8)
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   185
            oks = os_urandom(8)
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   186
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   187
            # Calculate the hash of the Owner password (U)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   188
            md = sha256(asBytes(self.ownerPassword[:127]) + ovs + self.U )
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   189
            self.O = md.digest() + ovs + oks
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   190
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   191
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   192
                print("self.O (hex)  = %s" % hexText(self.O))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   193
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   194
            # Calculate the User encryption key (OE)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   195
            md = sha256(asBytes(self.ownerPassword[:127]) + oks + self.U)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   196
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   197
            encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(md.digest(), iv=iv))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   198
            self.OE = encrypter.feed(self.key)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   199
            self.OE += encrypter.feed()
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   200
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   201
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   202
                print("self.OE (hex)  = %s" % hexText(self.OE))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   203
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   204
            # Compute permissions array 
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   205
            permsarr = [
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   206
                self.P       & 0xFF, # store the permission value in the first 32-bits
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   207
                self.P >> 8  & 0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   208
                self.P >> 16 & 0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   209
                self.P >> 24 & 0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   210
                0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   211
                0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   212
                0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   213
                0xFF,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   214
                ord('T'),             # 'T' if EncryptMetaData is True (default), 'F' otherwise
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   215
                ord('a'),             # a, d, b are magic values 
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   216
                ord('d'),
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   217
                ord('b'),
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   218
                0x01,                   # trailing zeros will be ignored
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   219
                0x01,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   220
                0x01,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   221
                0x01
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   222
            ]
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   223
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   224
            # the permission array should be enrypted in the Perms field
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   225
            encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(self.key, iv=iv))
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   226
            self.Perms = encrypter.feed(bytes3(permsarr))
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   227
            self.Perms += encrypter.feed()
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   228
                        
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   229
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   230
                print("self.Perms (hex)  = %s" % hexText(self.Perms))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   231
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   232
        elif self.revision in (2, 3):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   233
            self.O = computeO(self.userPassword, self.ownerPassword, self.revision)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   234
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   235
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   236
                print("self.O (as hex) = %s" % hexText(self.O))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   237
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   238
            #print "\nself.O", self.O, repr(self.O)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   239
            self.key = encryptionkey(self.userPassword, self.O, self.P, internalID, revision=self.revision)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   240
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   241
                print("self.key (hex)  = %s" % hexText(self.key))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   242
            self.U = computeU(self.key, revision=self.revision, documentId=internalID)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   243
            if DEBUG:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   244
                print("self.U (as hex) = %s" % hexText(self.U))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   245
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   246
        self.objnum = self.version = None
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   247
        self.prepared = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   248
    def register(self, objnum, version):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   249
        # enter a new direct object
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   250
        if not self.prepared:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   251
            raise ValueError("encryption not prepared!")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   252
        self.objnum = objnum
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   253
        self.version = version
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   254
    def info(self):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   255
        # the representation of self in file if any (should be None or PDFDict)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   256
        if not self.prepared:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   257
            raise ValueError("encryption not prepared!")
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   258
        return StandardEncryptionDictionary(O=self.O, OE=self.OE, U=self.U, UE=self.UE, P=self.P, Perms=self.Perms, revision=self.revision)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   259
4000
1718042b25c0 pdfdoc.py, pdfform.py & pdfencrypt.py: switch to using PDFObject inheritance(not __PDFObject__=True) to identify our instances
robin
parents: 3972
diff changeset
   260
class StandardEncryptionDictionary(PDFObject):
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   261
    __RefOnly__ = 1
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   262
    def __init__(self, O, OE, U, UE,  P, Perms, revision):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   263
        self.O,  self.OE, self.U, self.UE, self.P, self.Perms = O, OE, U, UE, P, Perms
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   264
        self.revision = revision
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   265
    def format(self, document):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   266
        # use a dummy document to bypass encryption
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   267
        from reportlab.pdfbase.pdfdoc import DummyDoc, PDFDictionary, PDFString, PDFName
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   268
        dummy = DummyDoc()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   269
        dict = {"Filter": PDFName("Standard"),
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   270
                "O": hexText(self.O),
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   271
                "U": hexText(self.U),
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   272
                "P": self.P}
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   273
        if self.revision == 5:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   274
            dict['Length'] = 256
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   275
            dict['R'] = 5
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   276
            dict['V'] = 5
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   277
            dict['O'] = hexText(self.O)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   278
            dict['U'] = hexText(self.U)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   279
            dict['OE'] = hexText(self.OE)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   280
            dict['UE'] = hexText(self.UE)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   281
            dict['Perms'] = hexText(self.Perms)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   282
            dict['StrF'] = PDFName("StdCF")
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   283
            dict['StmF'] = PDFName("StdCF")
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   284
            stdcf = {
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   285
                "Length": 32,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   286
                "AuthEvent": PDFName("DocOpen"),
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   287
                "CFM": PDFName("AESV3")
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   288
            }
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   289
            cf = {
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   290
                "StdCF": PDFDictionary(stdcf)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   291
            }
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   292
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   293
            dict['CF'] = PDFDictionary(cf)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   294
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   295
        elif self.revision == 3:
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   296
            dict['Length'] = 128
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   297
            dict['R'] = 3
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   298
            dict['V'] = 2
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   299
        else:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   300
            dict['R'] = 2
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   301
            dict['V'] = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   302
        pdfdict = PDFDictionary(dict)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   303
        return pdfdict.format(dummy)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   304
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   305
# from pdf spec
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   306
padding = """
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   307
28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   308
2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   309
"""
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   310
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   311
def hexText(text):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   312
    "a legitimate way to show strings in PDF"
4551
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
   313
    return '<%s>' % asNative(hexlify(rawBytes(text))).upper()
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   314
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   315
def unHexText(hexText):
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   316
    equalityCheck(hexText[0], '<', 'bad hex text')
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   317
    equalityCheck(hexText[-1], '>', 'bad hex text')
4551
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
   318
    return unhexlify(hexText[1:-1])
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   319
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   320
PadString = rawBytes(''.join(chr(int(c, 16)) for c in padding.strip().split()))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   321
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   322
def checkRevision(revision):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   323
    if revision is None:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   324
        strength = rl_config.encryptionStrength
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   325
        if strength == 40:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   326
            revision = 2
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   327
        elif strength == 128:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   328
            revision = 3
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   329
        elif strength == 256:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   330
            if not pyaes:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   331
                raise ValueError('strength==256 is not supported as package pyaes is not importable')
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   332
            revision = 5
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   333
        else:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   334
            raise ValueError('Unknown encryption strength=%s' % repr(strength))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   335
    return revision
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   336
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   337
def encryptionkey(password, OwnerKey, Permissions, FileId1, revision=None):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   338
    revision = checkRevision(revision)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   339
    # FileId1 is first string of the fileid array
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   340
    # add padding string
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   341
    #AR force same as iText example
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   342
    #Permissions =  -1836   #int(Permissions - 2**31)
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   343
    password = asBytes(password) + PadString
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   344
    # truncate to 32 bytes
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   345
    password = password[:32]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   346
    # translate permissions to string, low order byte first
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   347
    p = Permissions# + 2**32L
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   348
    permissionsString = b""
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   349
    for i in range(4):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   350
        byte = (p & 0xff)    # seems to match what iText does
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   351
        p = p>>8
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   352
        permissionsString += int2Byte(byte % 256)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   353
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   354
    hash = md5(asBytes(password))
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   355
    hash.update(asBytes(OwnerKey))
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   356
    hash.update(asBytes(permissionsString))
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   357
    hash.update(asBytes(FileId1))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   358
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   359
    md5output = hash.digest()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   360
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   361
    if revision==2:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   362
        key = md5output[:5]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   363
    elif revision==3:  #revision 3 algorithm - loop 50 times
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   364
        for x in range(50):
3098
318ba6cb2cb1 reportlab: fix md5 usage in pdfencrypt.py & fontfinder.py
rgbecker
parents: 3073
diff changeset
   365
            md5output = md5(md5output).digest()
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   366
        key = md5output[:16]
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   367
    if DEBUG: print('encryptionkey(%s,%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (password, OwnerKey, Permissions, FileId1, revision, key)]))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   368
    return key
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   369
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   370
def computeO(userPassword, ownerPassword, revision):
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   371
    from reportlab.lib.arciv import ArcIV
3098
318ba6cb2cb1 reportlab: fix md5 usage in pdfencrypt.py & fontfinder.py
rgbecker
parents: 3073
diff changeset
   372
    #print 'digest of hello is %s' % md5('hello').digest()
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   373
    assert revision in (2,3), 'Unknown algorithm revision %s' % revision
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   374
    if not ownerPassword:
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   375
        ownerPassword = userPassword
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   376
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   377
    ownerPad = asBytes(ownerPassword) + PadString
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   378
    ownerPad = ownerPad[0:32]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   379
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   380
    password = asBytes(userPassword) + PadString
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   381
    userPad = password[:32]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   382
3098
318ba6cb2cb1 reportlab: fix md5 usage in pdfencrypt.py & fontfinder.py
rgbecker
parents: 3073
diff changeset
   383
    digest = md5(ownerPad).digest()
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   384
    if DEBUG: print('PadString=%s\nownerPad=%s\npassword=%s\nuserPad=%s\ndigest=%s\nrevision=%s' % (ascii(PadString),ascii(ownerPad),ascii(password),ascii(userPad),ascii(digest),revision))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   385
    if revision == 2:
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   386
        O = ArcIV(digest[:5]).encode(userPad)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   387
    elif revision == 3:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   388
        for i in range(50):
3098
318ba6cb2cb1 reportlab: fix md5 usage in pdfencrypt.py & fontfinder.py
rgbecker
parents: 3073
diff changeset
   389
            digest = md5(digest).digest()
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   390
        digest = digest[:16]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   391
        O = userPad
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   392
        for i in range(20):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   393
            thisKey = xorKey(i, digest)
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   394
            O = ArcIV(thisKey).encode(O)
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   395
    if DEBUG: print('computeO(%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (userPassword, ownerPassword, revision,O)]))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   396
    return O
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   397
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   398
def computeU(encryptionkey, encodestring=PadString,revision=None,documentId=None):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   399
    revision = checkRevision(revision)
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   400
    from reportlab.lib.arciv import ArcIV
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   401
    if revision == 2:
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   402
        result = ArcIV(encryptionkey).encode(encodestring)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   403
    elif revision == 3:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   404
        assert documentId is not None, "Revision 3 algorithm needs the document ID!"
3098
318ba6cb2cb1 reportlab: fix md5 usage in pdfencrypt.py & fontfinder.py
rgbecker
parents: 3073
diff changeset
   405
        h = md5(PadString)
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   406
        h.update(rawBytes(documentId))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   407
        tmp = h.digest()
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   408
        tmp = ArcIV(encryptionkey).encode(tmp)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   409
        for n in range(1,20):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   410
            thisKey = xorKey(n, encryptionkey)
3071
ff411e85ba36 make pdfencrypt.py use ArcIV
rgbecker
parents: 3053
diff changeset
   411
            tmp = ArcIV(thisKey).encode(tmp)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   412
        while len(tmp) < 32:
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   413
            tmp += b'\0'
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   414
        result = tmp
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   415
    if DEBUG: print('computeU(%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (encryptionkey, encodestring,revision,documentId,result)]))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   416
    return result
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   417
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   418
def checkU(encryptionkey, U):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   419
    decoded = computeU(encryptionkey, U)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   420
    #print len(decoded), len(U), len(PadString)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   421
    if decoded!=PadString:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   422
        if len(decoded)!=len(PadString):
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   423
            raise ValueError("lengths don't match! (password failed)")
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   424
        raise ValueError("decode of U doesn't match fixed padstring (password failed)")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   425
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   426
def encodePDF(key, objectNumber, generationNumber, string, revision=None):
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   427
    "Encodes a string or stream"
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   428
    revision = checkRevision(revision)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   429
    #print 'encodePDF (%s, %d, %d, %s)' % (hexText(key), objectNumber, generationNumber, string)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   430
    # extend 3 bytes of the object Number, low byte first
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   431
    if revision in (2,3):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   432
        newkey = key
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   433
        n = objectNumber
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   434
        for i in range(3):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   435
            newkey += int2Byte(n & 0xff)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   436
            n = n>>8
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   437
        # extend 2 bytes of the generationNumber
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   438
        n = generationNumber
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   439
        for i in range(2):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   440
            newkey += int2Byte(n & 0xff)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   441
            n = n>>8
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   442
        md5output = md5(newkey).digest()
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   443
        if revision == 2:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   444
            key = md5output[:10]
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   445
        elif revision == 3:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   446
            key = md5output #all 16 bytes
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   447
        from reportlab.lib.arciv import ArcIV
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   448
        encrypted = ArcIV(key).encode(string)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   449
        #print 'encrypted=', hexText(encrypted)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   450
    elif revision == 5:
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   451
        iv = os_urandom(16)
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   452
        encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv=iv))
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   453
       
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   454
        # pkcs7 style padding so that the size of the encrypted block is multiple of 16 
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   455
        string_len = len(string)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   456
        padding = ""
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   457
        padding_len = (16 - (string_len % 16)) if string_len > 16 else (16 - string_len)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   458
        if padding_len > 0:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   459
            padding = chr(padding_len) * padding_len
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   460
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   461
        if isinstance(string, str):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   462
            string = (string + padding).encode("utf-8")    
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   463
        else:
4536
ea5704e5ff9b improve support for aes; version --> 3.5.28
robin
parents: 4535
diff changeset
   464
            string += asBytes(padding)
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   465
            
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   466
        encrypted = iv + encrypter.feed(string)
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   467
        encrypted += encrypter.feed()
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   468
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   469
    if DEBUG: print('encodePDF(%s,%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (key, objectNumber, generationNumber, string, revision,encrypted)]))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   470
    return encrypted
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   471
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   472
def equalityCheck(observed,expected,label):
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   473
    assert observed==expected,'%s\n expected=%s\n observed=%s' % (label,expected,observed)
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   474
######################################################################
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   475
#
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   476
#  quick tests of algorithm, should be moved elsewhere
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   477
#
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   478
######################################################################
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   479
def test():
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   480
    # do a 40 bit example known to work in Acrobat Reader 4.0
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   481
    enc = StandardEncryption('User','Owner', strength=40)
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   482
    enc.prepare(None, overrideID='xxxxxxxxxxxxxxxx')
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   483
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   484
    expectedO = '<FA7F558FACF8205D25A7F1ABFA02629F707AE7B0211A2BB26F5DF4C30F684301>'
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   485
    expectedU = '<09F26CF46190AF8F93B304AD50C16B615DC43C228C9B2D2EA34951A80617B2B1>'
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   486
    expectedKey = '<BB2C00EB3D>'    # 5 byte key = 40 bits
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   487
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   488
    equalityCheck(hexText(enc.O),expectedO, '40 bit O value')
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   489
    equalityCheck(hexText(enc.U),expectedU, '40 bit U value')
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   490
    equalityCheck(hexText(enc.key),expectedKey, '40 bit key value')
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   491
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   492
    # now for 128 bit example
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   493
    enc = StandardEncryption('userpass','ownerpass', strength=128)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   494
    enc.prepare(None, overrideID = 'xxxxxxxxxxxxxxxx')
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   495
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   496
    expectedO = '<68E5704AC779A5F0CD89704406587A52F25BF61CADC56A0F8DB6C4DB0052534D>'
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   497
    expectedU = '<A9AE45CDE827FE0B7D6536267948836A00000000000000000000000000000000>'
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   498
    expectedKey = '<13DDE7585D9BE366C976DDD56AF541D1>'  # 16 byte key = 128 bits
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   499
3861
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   500
    equalityCheck(hexText(enc.O), expectedO, '128 bit O value')
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   501
    equalityCheck(hexText(enc.U), expectedU, '128 bit U value')
2c6bef69fa95 pdfencrypt.py: encryption works
robin
parents: 3747
diff changeset
   502
    equalityCheck(hexText(enc.key), expectedKey, '128 key value')
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   503
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   504
    ######################################################################
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   505
    #
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   506
    #  These represent the higher level API functions
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   507
    #
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   508
    ######################################################################
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   509
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   510
def encryptCanvas(canvas,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   511
                  userPassword, ownerPassword=None,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   512
                  canPrint=1, canModify=1, canCopy=1, canAnnotate=1,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   513
                  strength=40):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   514
    "Applies encryption to the document being generated"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   515
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   516
    enc = StandardEncryption(userPassword, ownerPassword,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   517
                             canPrint, canModify, canCopy, canAnnotate,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   518
                             strength=strength)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   519
    canvas._doc.encrypt = enc
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   520
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   521
# Platypus stuff needs work, sadly.  I wanted to do it without affecting
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   522
# needing changes to latest release.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   523
class EncryptionFlowable(StandardEncryption, Flowable):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   524
    """Drop this in your Platypus story and it will set up the encryption options.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   525
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   526
    If you do it multiple times, the last one before saving will win."""
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   527
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   528
    def wrap(self, availWidth, availHeight):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   529
        return (0,0)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   530
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   531
    def draw(self):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   532
        encryptCanvas(self.canv,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   533
                      self.userPassword,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   534
                      self.ownerPassword,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   535
                      self.canPrint,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   536
                      self.canModify,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   537
                      self.canCopy,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   538
                      self.canAnnotate)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   539
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   540
##  I am thinking about this one.  Needs a change to reportlab to
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   541
##  work.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   542
def encryptDocTemplate(dt,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   543
                  userPassword, ownerPassword=None,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   544
                  canPrint=1, canModify=1, canCopy=1, canAnnotate=1,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   545
                       strength=40):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   546
    "For use in Platypus.  Call before build()."
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   547
    raise Exception("Not implemented yet")
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   548
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   549
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   550
def encryptPdfInMemory(inputPDF,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   551
                  userPassword, ownerPassword=None,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   552
                  canPrint=1, canModify=1, canCopy=1, canAnnotate=1,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   553
                       strength=40):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   554
    """accepts a PDF file 'as a byte array in memory'; return encrypted one.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   555
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   556
    This is a high level convenience and does not touch the hard disk in any way.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   557
    If you are encrypting the same file over and over again, it's better to use
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   558
    pageCatcher and cache the results."""
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   559
3073
6554a30b7450 Stop pdfencrypt from expecting rlextra to be present.
jonas
parents: 3071
diff changeset
   560
    try:
6554a30b7450 Stop pdfencrypt from expecting rlextra to be present.
jonas
parents: 3071
diff changeset
   561
        from rlextra.pageCatcher.pageCatcher import storeFormsInMemory, restoreFormsInMemory
6554a30b7450 Stop pdfencrypt from expecting rlextra to be present.
jonas
parents: 3071
diff changeset
   562
    except ImportError:
6554a30b7450 Stop pdfencrypt from expecting rlextra to be present.
jonas
parents: 3071
diff changeset
   563
        raise ImportError('''reportlab.lib.pdfencrypt.encryptPdfInMemory failed because rlextra cannot be imported.
4109
3c6b4cc83623 pdfencrypt.py: use page sizes in encryptPdfInMemory, bump to 3.1.17
robin
parents: 4067
diff changeset
   564
See https://www.reportlab.com/downloads''')
3073
6554a30b7450 Stop pdfencrypt from expecting rlextra to be present.
jonas
parents: 3071
diff changeset
   565
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   566
    (bboxInfo, pickledForms) = storeFormsInMemory(inputPDF, all=1, BBoxes=1)
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   567
    names = list(bboxInfo.keys())
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   568
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   569
    firstPageSize = bboxInfo['PageForms0'][2:]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   570
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   571
    #now make a new PDF document
3723
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   572
    buf = getBytesIO()
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   573
    canv = Canvas(buf, pagesize=firstPageSize)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   574
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   575
    # set a standard ID while debugging
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   576
    if CLOBBERID:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   577
        canv._doc._ID = "[(xxxxxxxxxxxxxxxx)(xxxxxxxxxxxxxxxx)]"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   578
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   579
    formNames = restoreFormsInMemory(pickledForms, canv)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   580
    for formName in formNames:
4109
3c6b4cc83623 pdfencrypt.py: use page sizes in encryptPdfInMemory, bump to 3.1.17
robin
parents: 4067
diff changeset
   581
        canv.setPageSize(bboxInfo[formName][2:])
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   582
        canv.doForm(formName)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   583
        canv.showPage()
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   584
    encryptCanvas(canv,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   585
                  userPassword, ownerPassword,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   586
                  canPrint, canModify, canCopy, canAnnotate,
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   587
                  strength=strength)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   588
    canv.save()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   589
    return buf.getvalue()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   590
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   591
def encryptPdfOnDisk(inputFileName, outputFileName,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   592
                  userPassword, ownerPassword=None,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   593
                  canPrint=1, canModify=1, canCopy=1, canAnnotate=1,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   594
                     strength=40):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   595
    "Creates encrypted file OUTPUTFILENAME.  Returns size in bytes."
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   596
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   597
    inputPDF = open(inputFileName, 'rb').read()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   598
    outputPDF = encryptPdfInMemory(inputPDF,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   599
                  userPassword, ownerPassword,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   600
                  canPrint, canModify, canCopy, canAnnotate,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   601
                                   strength=strength)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   602
    open(outputFileName, 'wb').write(outputPDF)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   603
    return len(outputPDF)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   604
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   605
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   606
def scriptInterp():
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   607
    sys_argv = sys.argv[:] # copy
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   608
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   609
    usage = """PDFENCRYPT USAGE:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   610
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   611
PdfEncrypt encrypts your PDF files.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   612
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   613
Line mode usage:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   614
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   615
% pdfencrypt.exe pdffile [-o ownerpassword] | [owner ownerpassword],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   616
\t[-u userpassword] | [user userpassword],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   617
\t[-p 1|0] | [printable 1|0],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   618
\t[-m 1|0] | [modifiable 1|0],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   619
\t[-c 1|0] | [copypastable 1|0],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   620
\t[-a 1|0] | [annotatable 1|0],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   621
\t[-s savefilename] | [savefile savefilename],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   622
\t[-v 1|0] | [verbose 1|0],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   623
\t[-e128], [encrypt128],
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   624
\t[-h] | [help]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   625
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   626
-o or owner set the owner password.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   627
-u or user set the user password.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   628
-p or printable set the printable attribute (must be 1 or 0).
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   629
-m or modifiable sets the modifiable attribute (must be 1 or 0).
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   630
-c or copypastable sets the copypastable attribute (must be 1 or 0).
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   631
-a or annotatable sets the annotatable attribute (must be 1 or 0).
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   632
-s or savefile sets the name for the output PDF file
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   633
-v or verbose prints useful output to the screen.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   634
      (this defaults to 'pdffile_encrypted.pdf').
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   635
'-e128' or 'encrypt128' allows you to use 128 bit encryption (in beta).
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   636
'-e256' or 'encrypt256' allows you to use 256 bit encryption (in beta AES).
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   637
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   638
-h or help prints this message.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   639
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   640
See PdfEncryptIntro.pdf for more information.
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   641
"""
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   642
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   643
    known_modes = ['-o', 'owner',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   644
                   '-u', 'user',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   645
                   '-p', 'printable',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   646
                   '-m', 'modifiable',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   647
                   '-c', 'copypastable',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   648
                   '-a', 'annotatable',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   649
                   '-s', 'savefile',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   650
                   '-v', 'verbose',
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   651
                   '-h', 'help',
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   652
                   '-e128', 'encrypt128',
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   653
                   '-e256', 'encryptAES',
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   654
                   ]
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   655
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   656
    OWNER        = ''
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   657
    USER         = ''
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   658
    PRINTABLE    = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   659
    MODIFIABLE   = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   660
    COPYPASTABLE = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   661
    ANNOTATABLE  = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   662
    SAVEFILE     = 'encrypted.pdf'
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   663
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   664
    #try:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   665
    caller = sys_argv[0] # may be required later - eg if called by security.py
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   666
    argv = list(sys_argv)[1:]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   667
    if len(argv)>0:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   668
        if argv[0] == '-h' or argv[0] == 'help':
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   669
            print(usage)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   670
            return
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   671
        if len(argv)<2:
3328
4d7f836cd947 reportlab: fix 2to3 warnings
rgbecker
parents: 3326
diff changeset
   672
            raise ValueError("Must include a filename and one or more arguments!")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   673
        if argv[0] not in known_modes:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   674
            infile = argv[0]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   675
            argv = argv[1:]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   676
            if not os.path.isfile(infile):
3328
4d7f836cd947 reportlab: fix 2to3 warnings
rgbecker
parents: 3326
diff changeset
   677
                raise ValueError("Can't open input file '%s'!" % infile)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   678
        else:
3328
4d7f836cd947 reportlab: fix 2to3 warnings
rgbecker
parents: 3326
diff changeset
   679
            raise ValueError("First argument must be name of the PDF input file!")
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   680
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   681
        # meaningful name at this stage
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   682
        STRENGTH = 40
4535
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   683
        for (s,_a) in ((128,('-e128','encrypt128')),(256,('-e256','encrypt256'))):
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   684
            for a in _a:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   685
                if a in argv:
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   686
                    STRENGTH = s
6f649f4056b5 fix BalancedColumn width calculation; version --> 3.5.27
robin
parents: 4367
diff changeset
   687
                    argv.remove(a)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   688
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   689
        if ('-v' in argv) or ('verbose' in argv):
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   690
            if '-v' in argv:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   691
                pos = argv.index('-v')
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   692
                arg = "-v"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   693
            elif 'verbose' in argv:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   694
                pos = argv.index('verbose')
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   695
                arg = "verbose"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   696
            try:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   697
                verbose = int(argv[pos+1])
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   698
            except:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   699
                verbose = 1
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   700
            argv.remove(argv[pos+1])
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   701
            argv.remove(arg)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   702
        else:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   703
            from reportlab.rl_config import verbose
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   704
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   705
        #argument, valid license variable, invalid license variable, text for print
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   706
        arglist = (('-o', 'OWNER', OWNER, 'Owner password'),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   707
                   ('owner', 'OWNER', OWNER, 'Owner password'),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   708
                   ('-u', 'USER', USER, 'User password'),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   709
                   ('user', 'USER', USER, 'User password'),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   710
                   ('-p', 'PRINTABLE', PRINTABLE, "'Printable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   711
                   ('printable', 'PRINTABLE', PRINTABLE, "'Printable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   712
                   ('-m', 'MODIFIABLE', MODIFIABLE, "'Modifiable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   713
                   ('modifiable', 'MODIFIABLE',  MODIFIABLE, "'Modifiable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   714
                   ('-c', 'COPYPASTABLE', COPYPASTABLE, "'Copypastable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   715
                   ('copypastable', 'COPYPASTABLE', COPYPASTABLE, "'Copypastable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   716
                   ('-a', 'ANNOTATABLE', ANNOTATABLE, "'Annotatable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   717
                   ('annotatable', 'ANNOTATABLE', ANNOTATABLE, "'Annotatable'"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   718
                   ('-s', 'SAVEFILE', SAVEFILE, "Output file"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   719
                   ('savefile', 'SAVEFILE', SAVEFILE, "Output file"),
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   720
                   )
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   721
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   722
        binaryrequired = ('-p', 'printable', '-m', 'modifiable', 'copypastable', '-c', 'annotatable', '-a')
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   723
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   724
        for thisarg in arglist:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   725
            if thisarg[0] in argv:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   726
                pos = argv.index(thisarg[0])
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   727
                if thisarg[0] in binaryrequired:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   728
                    if argv[pos+1] not in ('1', '0'):
3972
b5870c0f3eb4 patches from Matthias Klose
robin
parents: 3903
diff changeset
   729
                        raise ValueError("%s value must be either '1' or '0'!" % thisarg[1])
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   730
                try:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   731
                    if argv[pos+1] not in known_modes:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   732
                        if thisarg[0] in binaryrequired:
4551
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
   733
                            exec(thisarg[1] +' = int(argv[pos+1])',vars())
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   734
                        else:
4551
d357e2acc856 improve usage of eval/exec; version --> 3.5.32
robin
parents: 4536
diff changeset
   735
                            exec(thisarg[1] +' = argv[pos+1]',vars())
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   736
                        if verbose:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   737
                            print("%s set to: '%s'." % (thisarg[3], argv[pos+1]))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   738
                        argv.remove(argv[pos+1])
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   739
                        argv.remove(thisarg[0])
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   740
                except:
3747
7155d7117e67 Backed out changeset d30e432b8a2f
robin
parents: 3746
diff changeset
   741
                    raise "Unable to set %s." % thisarg[3]
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   742
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   743
        if verbose>4:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   744
            #useful if feeling paranoid and need to double check things at this point...
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   745
            print("\ninfile:", infile)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   746
            print("STRENGTH:", STRENGTH)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   747
            print("SAVEFILE:", SAVEFILE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   748
            print("USER:", USER)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   749
            print("OWNER:", OWNER)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   750
            print("PRINTABLE:", PRINTABLE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   751
            print("MODIFIABLE:", MODIFIABLE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   752
            print("COPYPASTABLE:", COPYPASTABLE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   753
            print("ANNOTATABLE:", ANNOTATABLE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   754
            print("SAVEFILE:", SAVEFILE)
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   755
            print("VERBOSE:", verbose)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   756
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   757
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   758
        if SAVEFILE == 'encrypted.pdf':
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   759
            if infile[-4:] == '.pdf' or infile[-4:] == '.PDF':
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   760
                tinfile = infile[:-4]
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   761
            else:
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   762
                tinfile = infile
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   763
            SAVEFILE = tinfile+"_encrypted.pdf"
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   764
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   765
        filesize = encryptPdfOnDisk(infile, SAVEFILE, USER, OWNER,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   766
                  PRINTABLE, MODIFIABLE, COPYPASTABLE, ANNOTATABLE,
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   767
                                    strength=STRENGTH)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   768
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   769
        if verbose:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   770
            print("wrote output file '%s'(%s bytes)\n  owner password is '%s'\n  user password is '%s'" % (SAVEFILE, filesize, OWNER, USER))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   771
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   772
        if len(argv)>0:
4116
cf49463fc067 Fix a bunch of undefined names. Mostly typos or missing imports.
Matthew Duggan <mgithub@guarana.org>
parents: 4109
diff changeset
   773
            raise ValueError("\nUnrecognised arguments : %s\nknown arguments are:\n%s" % (str(argv)[1:-1], known_modes))
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   774
    else:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   775
        print(usage)
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   776
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   777
def main():
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   778
    from reportlab.rl_config import verbose
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   779
    scriptInterp()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   780
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   781
if __name__=="__main__": #NO RUNTESTS
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   782
    a = [x for x in sys.argv if x[:7]=='--debug']
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   783
    if a:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   784
        sys.argv = [x for x in sys.argv if x[:7]!='--debug']
3035
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   785
        DEBUG = len(a)
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   786
    if '--test' in sys.argv: test()
41408333df89 Add pdfencrypt to reportlab.lib.
jonas
parents:
diff changeset
   787
    else: main()