PKCryptContext   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 401
Duplicated Lines 0 %

Test Coverage

Coverage 97.62%

Importance

Changes 0
Metric Value
eloc 294
dl 0
loc 401
ccs 41
cts 42
cp 0.9762
rs 10
c 0
b 0
f 0
wmc 14

8 Methods

Rating   Name   Duplication   Size   Complexity  
A encryptByte() 0 6 1
A crc32() 0 3 1
A updateKeys() 0 6 1
A encryptString() 0 9 2
A decryptString() 0 11 2
A decryptByte() 0 5 1
A __construct() 0 14 3
A checkHeader() 0 11 3
1
<?php
2
3
namespace PhpZip\IO\Filter\Cipher\Pkware;
4
5
use PhpZip\Exception\RuntimeException;
6
use PhpZip\Exception\ZipAuthenticationException;
7
use PhpZip\Util\PackUtil;
8
9
/**
10
 * Traditional PKWARE Encryption Engine.
11
 *
12
 * @see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT .ZIP File Format Specification
13
 *
14
 * @author Ne-Lexa [email protected]
15
 * @license MIT
16
 */
17
class PKCryptContext
18
{
19
    /** Encryption header size */
20
    const STD_DEC_HDR_SIZE = 12;
21
22
    /**
23
     * Crc table.
24
     *
25
     * @var int[]|array
26
     */
27
    private static $CRC_TABLE = [
28
        0x00000000,
29
        0x77073096,
30
        0xee0e612c,
31
        0x990951ba,
32
        0x076dc419,
33
        0x706af48f,
34
        0xe963a535,
35
        0x9e6495a3,
36
        0x0edb8832,
37
        0x79dcb8a4,
38
        0xe0d5e91e,
39
        0x97d2d988,
40
        0x09b64c2b,
41
        0x7eb17cbd,
42
        0xe7b82d07,
43
        0x90bf1d91,
44
        0x1db71064,
45
        0x6ab020f2,
46
        0xf3b97148,
47
        0x84be41de,
48
        0x1adad47d,
49
        0x6ddde4eb,
50
        0xf4d4b551,
51
        0x83d385c7,
52
        0x136c9856,
53
        0x646ba8c0,
54
        0xfd62f97a,
55
        0x8a65c9ec,
56
        0x14015c4f,
57
        0x63066cd9,
58
        0xfa0f3d63,
59
        0x8d080df5,
60
        0x3b6e20c8,
61
        0x4c69105e,
62
        0xd56041e4,
63
        0xa2677172,
64
        0x3c03e4d1,
65
        0x4b04d447,
66
        0xd20d85fd,
67
        0xa50ab56b,
68
        0x35b5a8fa,
69
        0x42b2986c,
70
        0xdbbbc9d6,
71
        0xacbcf940,
72
        0x32d86ce3,
73
        0x45df5c75,
74
        0xdcd60dcf,
75
        0xabd13d59,
76
        0x26d930ac,
77
        0x51de003a,
78
        0xc8d75180,
79
        0xbfd06116,
80
        0x21b4f4b5,
81
        0x56b3c423,
82
        0xcfba9599,
83
        0xb8bda50f,
84
        0x2802b89e,
85
        0x5f058808,
86
        0xc60cd9b2,
87
        0xb10be924,
88
        0x2f6f7c87,
89
        0x58684c11,
90
        0xc1611dab,
91
        0xb6662d3d,
92
        0x76dc4190,
93
        0x01db7106,
94
        0x98d220bc,
95
        0xefd5102a,
96
        0x71b18589,
97
        0x06b6b51f,
98
        0x9fbfe4a5,
99
        0xe8b8d433,
100
        0x7807c9a2,
101
        0x0f00f934,
102
        0x9609a88e,
103
        0xe10e9818,
104
        0x7f6a0dbb,
105
        0x086d3d2d,
106
        0x91646c97,
107
        0xe6635c01,
108
        0x6b6b51f4,
109
        0x1c6c6162,
110
        0x856530d8,
111
        0xf262004e,
112
        0x6c0695ed,
113
        0x1b01a57b,
114
        0x8208f4c1,
115
        0xf50fc457,
116
        0x65b0d9c6,
117
        0x12b7e950,
118
        0x8bbeb8ea,
119
        0xfcb9887c,
120
        0x62dd1ddf,
121
        0x15da2d49,
122
        0x8cd37cf3,
123
        0xfbd44c65,
124
        0x4db26158,
125
        0x3ab551ce,
126
        0xa3bc0074,
127
        0xd4bb30e2,
128
        0x4adfa541,
129
        0x3dd895d7,
130
        0xa4d1c46d,
131
        0xd3d6f4fb,
132
        0x4369e96a,
133
        0x346ed9fc,
134
        0xad678846,
135
        0xda60b8d0,
136
        0x44042d73,
137
        0x33031de5,
138
        0xaa0a4c5f,
139
        0xdd0d7cc9,
140
        0x5005713c,
141
        0x270241aa,
142
        0xbe0b1010,
143
        0xc90c2086,
144
        0x5768b525,
145
        0x206f85b3,
146
        0xb966d409,
147
        0xce61e49f,
148
        0x5edef90e,
149
        0x29d9c998,
150
        0xb0d09822,
151
        0xc7d7a8b4,
152
        0x59b33d17,
153
        0x2eb40d81,
154
        0xb7bd5c3b,
155
        0xc0ba6cad,
156
        0xedb88320,
157
        0x9abfb3b6,
158
        0x03b6e20c,
159
        0x74b1d29a,
160
        0xead54739,
161
        0x9dd277af,
162
        0x04db2615,
163
        0x73dc1683,
164
        0xe3630b12,
165
        0x94643b84,
166
        0x0d6d6a3e,
167
        0x7a6a5aa8,
168
        0xe40ecf0b,
169
        0x9309ff9d,
170
        0x0a00ae27,
171
        0x7d079eb1,
172
        0xf00f9344,
173
        0x8708a3d2,
174
        0x1e01f268,
175
        0x6906c2fe,
176
        0xf762575d,
177
        0x806567cb,
178
        0x196c3671,
179
        0x6e6b06e7,
180
        0xfed41b76,
181
        0x89d32be0,
182
        0x10da7a5a,
183
        0x67dd4acc,
184
        0xf9b9df6f,
185
        0x8ebeeff9,
186
        0x17b7be43,
187
        0x60b08ed5,
188
        0xd6d6a3e8,
189
        0xa1d1937e,
190
        0x38d8c2c4,
191
        0x4fdff252,
192
        0xd1bb67f1,
193
        0xa6bc5767,
194
        0x3fb506dd,
195
        0x48b2364b,
196
        0xd80d2bda,
197
        0xaf0a1b4c,
198
        0x36034af6,
199
        0x41047a60,
200
        0xdf60efc3,
201
        0xa867df55,
202
        0x316e8eef,
203
        0x4669be79,
204
        0xcb61b38c,
205
        0xbc66831a,
206
        0x256fd2a0,
207
        0x5268e236,
208
        0xcc0c7795,
209
        0xbb0b4703,
210
        0x220216b9,
211
        0x5505262f,
212
        0xc5ba3bbe,
213
        0xb2bd0b28,
214
        0x2bb45a92,
215
        0x5cb36a04,
216
        0xc2d7ffa7,
217
        0xb5d0cf31,
218
        0x2cd99e8b,
219
        0x5bdeae1d,
220
        0x9b64c2b0,
221
        0xec63f226,
222
        0x756aa39c,
223
        0x026d930a,
224
        0x9c0906a9,
225
        0xeb0e363f,
226
        0x72076785,
227
        0x05005713,
228
        0x95bf4a82,
229
        0xe2b87a14,
230
        0x7bb12bae,
231
        0x0cb61b38,
232
        0x92d28e9b,
233
        0xe5d5be0d,
234
        0x7cdcefb7,
235
        0x0bdbdf21,
236
        0x86d3d2d4,
237
        0xf1d4e242,
238
        0x68ddb3f8,
239
        0x1fda836e,
240
        0x81be16cd,
241
        0xf6b9265b,
242
        0x6fb077e1,
243
        0x18b74777,
244
        0x88085ae6,
245
        0xff0f6a70,
246
        0x66063bca,
247
        0x11010b5c,
248
        0x8f659eff,
249
        0xf862ae69,
250
        0x616bffd3,
251
        0x166ccf45,
252
        0xa00ae278,
253
        0xd70dd2ee,
254
        0x4e048354,
255
        0x3903b3c2,
256
        0xa7672661,
257
        0xd06016f7,
258
        0x4969474d,
259
        0x3e6e77db,
260
        0xaed16a4a,
261
        0xd9d65adc,
262
        0x40df0b66,
263
        0x37d83bf0,
264
        0xa9bcae53,
265
        0xdebb9ec5,
266
        0x47b2cf7f,
267
        0x30b5ffe9,
268
        0xbdbdf21c,
269
        0xcabac28a,
270
        0x53b39330,
271
        0x24b4a3a6,
272
        0xbad03605,
273
        0xcdd70693,
274
        0x54de5729,
275
        0x23d967bf,
276
        0xb3667a2e,
277
        0xc4614ab8,
278
        0x5d681b02,
279
        0x2a6f2b94,
280
        0xb40bbe37,
281
        0xc30c8ea1,
282
        0x5a05df1b,
283
        0x2d02ef8d,
284
    ];
285
286
    /**
287
     * Encryption keys.
288
     *
289
     * @var array
290
     */
291
    private $keys;
292
293
    /**
294
     * PKCryptContext constructor.
295
     *
296
     * @param string $password
297
     */
298 5
    public function __construct($password)
299
    {
300 5
        if (\PHP_INT_SIZE === 4) {
301
            throw new RuntimeException('Traditional PKWARE Encryption is not supported in 32-bit PHP.');
302
        }
303
304 5
        $this->keys = [
305
            305419896,
306
            591751049,
307
            878082192,
308
        ];
309
310 5
        foreach (unpack('C*', $password) as $b) {
311 5
            $this->updateKeys($b);
312
        }
313 5
    }
314
315
    /**
316
     * @param string $header
317
     * @param int    $checkByte
318
     *
319
     * @throws ZipAuthenticationException
320
     */
321 5
    public function checkHeader($header, $checkByte)
322
    {
323 5
        $byte = 0;
324
325 5
        foreach (unpack('C*', $header) as $byte) {
326 5
            $byte = ($byte ^ $this->decryptByte()) & 0xff;
327 5
            $this->updateKeys($byte);
328
        }
329
330 5
        if ($byte !== $checkByte) {
331 2
            throw new ZipAuthenticationException(sprintf('Invalid password'));
332
        }
333 4
    }
334
335
    /**
336
     * @param string $content
337
     *
338
     * @return string
339
     */
340 4
    public function decryptString($content)
341
    {
342 4
        $decryptContent = '';
343
344 4
        foreach (unpack('C*', $content) as $byte) {
345 4
            $byte = ($byte ^ $this->decryptByte()) & 0xff;
346 4
            $this->updateKeys($byte);
347 4
            $decryptContent .= \chr($byte);
348
        }
349
350 4
        return $decryptContent;
351
    }
352
353
    /**
354
     * Decrypt byte.
355
     *
356
     * @return int
357
     */
358 5
    private function decryptByte()
359
    {
360 5
        $temp = $this->keys[2] | 2;
361
362 5
        return (($temp * ($temp ^ 1)) >> 8) & 0xffffff;
363
    }
364
365
    /**
366
     * Update keys.
367
     *
368
     * @param int $charAt
369
     */
370 5
    private function updateKeys($charAt)
371
    {
372 5
        $this->keys[0] = $this->crc32($this->keys[0], $charAt);
373 5
        $this->keys[1] += ($this->keys[0] & 0xff);
374 5
        $this->keys[1] = PackUtil::toSignedInt32($this->keys[1] * 134775813 + 1);
375 5
        $this->keys[2] = PackUtil::toSignedInt32($this->crc32($this->keys[2], ($this->keys[1] >> 24) & 0xff));
376 5
    }
377
378
    /**
379
     * Update crc.
380
     *
381
     * @param int $oldCrc
382
     * @param int $charAt
383
     *
384
     * @return int
385
     */
386 5
    private function crc32($oldCrc, $charAt)
387
    {
388 5
        return (($oldCrc >> 8) & 0xffffff) ^ self::$CRC_TABLE[($oldCrc ^ $charAt) & 0xff];
389
    }
390
391
    /**
392
     * @param string $content
393
     *
394
     * @return string
395
     */
396 4
    public function encryptString($content)
397
    {
398 4
        $encryptContent = '';
399
400 4
        foreach (unpack('C*', $content) as $val) {
401 4
            $encryptContent .= pack('c', $this->encryptByte($val));
402
        }
403
404 4
        return $encryptContent;
405
    }
406
407
    /**
408
     * @param int $byte
409
     *
410
     * @return int
411
     */
412 4
    private function encryptByte($byte)
413
    {
414 4
        $tempVal = $byte ^ $this->decryptByte() & 0xff;
415 4
        $this->updateKeys($byte);
416
417 4
        return $tempVal;
418
    }
419
}
420