source-class-Com.Tecnick.Pdf.Encrypt.Encrypt

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
  1: <?php
  2: /**
  3:  * Encrypt.php
  4:  *
  5:  * @since       2008-01-02
  6:  * @category    Library
  7:  * @package     PdfEncrypt
  8:  * @author      Nicola Asuni <info@tecnick.com>
  9:  * @copyright   2011-2015 Nicola Asuni - Tecnick.com LTD
 10:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 11:  * @link        https://github.com/tecnickcom/tc-lib-pdf-encrypt
 12:  *
 13:  * This file is part of tc-lib-pdf-encrypt software library.
 14:  */
 15: 
 16: namespace Com\Tecnick\Pdf\Encrypt;
 17: 
 18: use \Com\Tecnick\Pdf\Encrypt\Exception as EncException;
 19: 
 20: /**
 21:  * Com\Tecnick\Pdf\Encrypt\Encrypt
 22:  *
 23:  * PHP class for encrypting data for PDF documents
 24:  *
 25:  * @since       2008-01-02
 26:  * @category    Library
 27:  * @package     PdfEncrypt
 28:  * @author      Nicola Asuni <info@tecnick.com>
 29:  * @copyright   2011-2015 Nicola Asuni - Tecnick.com LTD
 30:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 31:  * @link        https://github.com/tecnickcom/tc-lib-pdf-encrypt
 32:  */
 33: class Encrypt extends \Com\Tecnick\Pdf\Encrypt\Compute
 34: {
 35:     /**
 36:      * Encryption data
 37:      *
 38:      * @var array
 39:      */
 40:     protected $encryptdata = array('encrypted' => false, 'mode' => false);
 41: 
 42:     /**
 43:      * Set PDF document protection (permission settings)
 44:      *
 45:      * NOTES: The protection against modification is for people who have the full Acrobat product.
 46:      *        If you don't set any password, the document will open as usual.
 47:      *        If you set a user password, the PDF viewer will ask for it before displaying the document.
 48:      *        The master password, if different from the user one, can be used to get full access.
 49:      *        Protecting a document requires to encrypt it, which requires long processign time and may cause timeouts.
 50:      *
 51:      * @param bool   $enabled     False if the encryption is disabled (i.e. the document is in PDF/A mode)
 52:      * @param string $file_id     File ID
 53:      * @param int    $mode        Encryption strength: 0 = RC4 40; 1 = RC4 128; 2 = AES 128; 3 = AES 256
 54:      * @param array  $permissions The set of permissions (specify the ones you want to block):
 55:      *                      'owner' // When set permits change of encryption and enables all other permissions.
 56:      *                              // (inverted logic: cleared by default).
 57:      *                      'print' // Print the document.
 58:      *                     'modify' // Modify the contents of the document by operations other than those controlled
 59:      *                              // by 'fill-forms', 'extract' and 'assemble'.
 60:      *                       'copy' // Copy or otherwise extract text and graphics from the document.
 61:      *                'annot-forms' // Add or modify text annotations, fill in interactive form fields, and,
 62:      *                              // if 'modify' is also set, create or modify interactive form fields
 63:      *                              // (including signature fields).
 64:      *                 'fill-forms' // Fill in existing interactive form fields (including signature fields),
 65:      *                              // even if 'annot-forms' is not specified.
 66:      *                    'extract' // Extract text and graphics (in support of accessibility to users with
 67:      *                              // disabilities or for other purposes).
 68:      *                   'assemble' // Assemble the document (insert, rotate, or delete pages and create bookmarks
 69:      *                              // or thumbnail images), even if 'modify' is not set.
 70:      *                 'print-high' // Print the document to a representation from which a faithful digital copy of the
 71:      *                              // PDF content could be generated. When this is not set, printing is limited to a
 72:      *                              // low-level representation of the appearance, possibly of degraded quality.
 73:      *
 74:      * @param string $user_pass   User password. Empty by default.
 75:      * @param string $owner_pass  Owner password. If not specified, a random value is used.
 76:      * @param string $pubkeys     Array of recipients containing public-key certificates ('c') and permissions ('p').
 77:      *                            For example:
 78:      *                            array(array('c' => 'file://../examples/data/cert/test.crt', 'p' => array('print')))
 79:      *                            To create self-signed certificate:
 80:      *                            openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout key.pem -out cert.pem
 81:      *                            To export crt to p12: openssl pkcs12 -export -in cert.pem -out cert.p12
 82:      *                            To convert pfx certificate to pem: openssl pkcs12 -in cert.pfx -out cert.pem -nodes
 83:      */
 84:     public function __construct(
 85:         $enabled = false,
 86:         $file_id = '',
 87:         $mode = 0,
 88:         $permissions = array(
 89:             'print',
 90:             'modify',
 91:             'copy',
 92:             'annot-forms',
 93:             'fill-forms',
 94:             'extract',
 95:             'assemble',
 96:             'print-high'
 97:         ),
 98:         $user_pass = '',
 99:         $owner_pass = null,
100:         $pubkeys = null
101:     ) {
102:         if (!$enabled) {
103:             return;
104:         }
105:         $this->encryptdata['protection'] = $this->getUserPermissionCode($permissions, $mode);
106: 
107:         if (is_array($pubkeys)) {
108:             // public-key mode
109:             $this->encryptdata['pubkeys'] = $pubkeys;
110:             if ($mode == 0) {
111:                 // public-Key Security requires at least 128 bit
112:                 $mode = 1;
113:             }
114:             // Set Public-Key filter (available are: Entrust.PPKEF, Adobe.PPKLite, Adobe.PubSec)
115:             $this->encryptdata['pubkey'] = true;
116:             $this->encryptdata['Filter'] = 'Adobe.PubSec';
117:             $this->encryptdata['StmF']   = 'DefaultCryptFilter';
118:             $this->encryptdata['StrF']   = 'DefaultCryptFilter';
119:         } else {
120:             // standard mode (password mode)
121:             $this->encryptdata['pubkey'] = false;
122:             $this->encryptdata['Filter'] = 'Standard';
123:             $this->encryptdata['StmF']   = 'StdCF';
124:             $this->encryptdata['StrF']   = 'StdCF';
125:         }
126: 
127:         if ($owner_pass === null) {
128:             $owner_pass = md5($this->encrypt('seed'));
129:         }
130: 
131:         $this->encryptdata['user_password']  = $user_pass;
132:         $this->encryptdata['owner_password'] = $owner_pass;
133: 
134:         if (($mode < 0) || ($mode > 3)) {
135:             throw new EncException('unknown encryption mode: '.$this->encryptdata['mode']);
136:         }
137:         $this->encryptdata['mode'] = $mode;
138: 
139:         $this->encryptdata = array_merge($this->encryptdata, self::$encrypt_settings[$mode]);
140:         if (!$this->encryptdata['pubkey']) {
141:             unset($this->encryptdata['SubFilter'], $this->encryptdata['Recipients']);
142:         }
143:         $this->encryptdata['encrypted'] = true;
144:         $this->encryptdata['fileid'] = $this->convertHexStringToString($file_id);
145:         $this->generateEncryptionKey();
146:     }
147: 
148:     /**
149:      * Get the encryption data array.
150:      *
151:      * @return array
152:      */
153:     public function getEncryptionData()
154:     {
155:         return $this->encryptdata;
156:     }
157: 
158:     /**
159:      * Encrypt data using the specified encrypt type.
160:      *
161:      * @param string $type   Encrypt type.
162:      * @param string $data   Data string to encrypt.
163:      * @param string $key    Encryption key.
164:      * @param int    $objnum Object number.
165:      *
166:      * @return string Encrypted data string.
167:      */
168:     public function encrypt($type, $data = '', $key = null, $objnum = null)
169:     {
170:         if (empty($this->encryptdata['encrypted']) || ($type === false)) {
171:             return $data;
172:         }
173: 
174:         if (!isset(self::$encmap[$type])) {
175:             throw new EncException('unknown encryption type: '.$type);
176:         }
177: 
178:         if (($key === null) && ($type == $this->encryptdata['mode'])) {
179:             $key = '';
180:             if ($this->encryptdata['mode'] < 3) {
181:                 $key = $this->getObjectKey($objnum);
182:             } elseif ($this->encryptdata['mode'] == 3) {
183:                 $key = $this->encryptdata['key'];
184:             }
185:         }
186: 
187:         $class = '\\Com\\Tecnick\\Pdf\\Encrypt\\Type\\'.self::$encmap[$type];
188:         $obj = new $class;
189:         return $obj->encrypt($data, $key);
190:     }
191: 
192:     /**
193:      * Compute encryption key depending on object number where the encrypted data is stored.
194:      * This is used for all strings and streams without crypt filter specifier.
195:      *
196:      * @param int $objnum Object number.
197:      *
198:      * @return int
199:      */
200:     public function getObjectKey($objnum)
201:     {
202:         $objkey = $this->encryptdata['key'].pack('VXxx', $objnum);
203:         if ($this->encryptdata['mode'] == 2) {
204:             // AES-128 padding
205:             $objkey .= "\x73\x41\x6C\x54"; // sAlT
206:         }
207:         $objkey = substr($this->encrypt('MD5-16', $objkey, 'H*'), 0, (($this->encryptdata['Length'] / 8) + 5));
208:         $objkey = substr($objkey, 0, 16);
209:         return $objkey;
210:     }
211: 
212:     /**
213:      * Convert encryption P value to a string of bytes, low-order byte first.
214:      *
215:      * @param string $protection 32bit encryption permission value (P value).
216:      *
217:      * @return string
218:      */
219:     public function getEncPermissionsString($protection)
220:     {
221:         $binprot = sprintf('%032b', $protection);
222:         return chr(bindec(substr($binprot, 24, 8)))
223:             .chr(bindec(substr($binprot, 16, 8)))
224:             .chr(bindec(substr($binprot, 8, 8)))
225:             .chr(bindec(substr($binprot, 0, 8)));
226:     }
227: 
228:     /**
229:      * Return the permission code used on encryption (P value).
230:      *
231:      * @param array $permissions The set of permissions (specify the ones you want to block).
232:      * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit.
233:      *
234:      * @return int
235:      */
236:     public function getUserPermissionCode($permissions, $mode = 0)
237:     {
238:         $protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100)
239:         foreach ($permissions as $permission) {
240:             if (isset(self::$permbits[$permission])) {
241:                 if (($mode > 0) || (self::$permbits[$permission] <= 32)) {
242:                     // set only valid permissions
243:                     if (self::$permbits[$permission] == 2) {
244:                         // the logic for bit 2 is inverted (cleared by default)
245:                         $protection += self::$permbits[$permission];
246:                     } else {
247:                         $protection -= self::$permbits[$permission];
248:                     }
249:                 }
250:             }
251:         }
252:         return $protection;
253:     }
254: 
255:     /**
256:      * Convert hexadecimal string to string.
257:      *
258:      * @param string $bstr Byte-string to convert.
259:      *
260:      * @return String
261:      */
262:     public function convertHexStringToString($bstr)
263:     {
264:         $str = ''; // string to be returned
265:         $bslength = strlen($bstr);
266:         if (($bslength % 2) != 0) {
267:             // padding
268:             $bstr .= '0';
269:             ++$bslength;
270:         }
271:         for ($idx = 0; $idx < $bslength; $idx += 2) {
272:             $str .= chr(hexdec($bstr[$idx].$bstr[($idx + 1)]));
273:         }
274:         return $str;
275:     }
276: 
277:     /**
278:      * Convert string to hexadecimal string (byte string).
279:      *
280:      * @param string $str String to convert.
281:      *
282:      * @return string
283:      */
284:     public function convertStringToHexString($str)
285:     {
286:         $bstr = '';
287:         $chars = preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY);
288:         foreach ($chars as $chr) {
289:             $bstr .= sprintf('%02s', dechex(ord($chr)));
290:         }
291:         return $bstr;
292:     }
293: 
294:     /**
295:      * Encode a name object.
296:      *
297:      * @param string $name Name object to encode.
298:      *
299:      * @return string Encoded name object.
300:      */
301:     public function encodeNameObject($name)
302:     {
303:         $escname = '';
304:         $length = strlen($name);
305:         for ($idx = 0; $idx < $length; ++$idx) {
306:             $chr = $name[$idx];
307:             if (preg_match('/[0-9a-zA-Z#_=-]/', $chr) == 1) {
308:                 $escname .= $chr;
309:             } else {
310:                 $escname .= sprintf('#%02X', ord($chr));
311:             }
312:         }
313:         return $escname;
314:     }
315: 
316:     /**
317:      * Escape a string: add "\" before "\", "(" and ")".
318:      *
319:      * @param string $str String to escape.
320:      *
321:      * @return string
322:      */
323:     public function escapeString($str)
324:     {
325:         return strtr($str, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
326:     }
327: 
328:     /**
329:      * Encrypt a string.
330:      *
331:      * @param string $str    String to encrypt.
332:      * @param int    $objnum Object ID.
333:      *
334:      * @return string
335:      */
336:     public function encryptString($str, $objnum = null)
337:     {
338:         return $this->encrypt($this->encryptdata['mode'], $str, null, $objnum);
339:     }
340: 
341:     /**
342:      * Format a data string for meta information.
343:      *
344:      * @param string $str    Data string to escape.
345:      * @param int    $objnum Object ID.
346:      *
347:      * @return string
348:      */
349:     public function escapeDataString($str, $objnum = null)
350:     {
351:         return '('.$this->escapeString($this->encryptString($str, $objnum)).')';
352:     }
353: 
354:     /**
355:      * Returns a formatted date-time.
356:      *
357:      * @param int $time   UTC time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
358:      * @param int $objnum Object ID.
359:      *
360:      * @return string escaped date string.
361:      */
362:     public function getFormattedDate($time = null, $objnum = null)
363:     {
364:         if ($time === null) {
365:             $time = time(); // get current UTC time
366:         }
367:         return $this->escapeDataString('D:'.substr_replace(date('YmdHisO', intval($time)), '\'', -2, 0).'\'', $objnum);
368:     }
369: }
370: 
 

© 2004-2017 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy