Test Failed
Pull Request — master (#667)
by
unknown
02:48
created

Stream::make()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
nc 4
nop 2
dl 0
loc 17
rs 9.8666
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is based on code of tecnickcom/TCPDF PDF library.
5
 *
6
 * Original author Nicola Asuni ([email protected]) and
7
 * contributors (https://github.com/tecnickcom/TCPDF/graphs/contributors).
8
 *
9
 * @see https://github.com/tecnickcom/TCPDF
10
 *
11
 * Original code was licensed on the terms of the LGPL v3.
12
 *
13
 * ------------------------------------------------------------------------------
14
 *
15
 * @file This file is part of the PdfParser library.
16
 *
17
 * @author  Alastair Irvine <[email protected]>
18
 *
19
 * @date    2024-01-12
20
 *
21
 * @license LGPLv3
22
 *
23
 * @url     <https://github.com/smalot/pdfparser>
24
 *
25
 *  PdfParser is a pdf library written in PHP, extraction oriented.
26
 *  Copyright (C) 2017 - Sébastien MALOT <[email protected]>
27
 *
28
 *  This program is free software: you can redistribute it and/or modify
29
 *  it under the terms of the GNU Lesser General Public License as published by
30
 *  the Free Software Foundation, either version 3 of the License, or
31
 *  (at your option) any later version.
32
 *
33
 *  This program is distributed in the hope that it will be useful,
34
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
35
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36
 *  GNU Lesser General Public License for more details.
37
 *
38
 *  You should have received a copy of the GNU Lesser General Public License
39
 *  along with this program.
40
 *  If not, see <http://www.pdfparser.org/sites/default/LICENSE.txt>.
41
 */
42
43
namespace Smalot\PdfParser\Encryption;
44
45
/**
46
 * Handles data decoding, decryption & ciphers, extra parsing, etc.
47
 */
48
abstract class Stream
49
{
50
    function __construct($key)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
51
    {
52
        $this->key = $key;
0 ignored issues
show
Bug Best Practice introduced by
The property key does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
53
    }
54
55
56
    /**
57
     * Carve the IV and the cyphertext apart.  Only used by some algorithms.
58
     *
59
     * @return array of two strings
60
     */
61
    public static function splitBlock(string $block, int $ivLength)
62
    {
63
        $iv = \substr($block, 0, $ivLength);
64
        $cyphertext = \substr($block, $ivLength);
65
        return [ $iv, $cyphertext ];
66
    }
67
68
69
    /**
70
     * Object factory that instantiates the relevant subclass.
71
     *
72
     * @param string $algorithm
73
     * @param        $key file key consisting of byte string of the relevant number of characters
74
     *
75
     * @return Stream subclass
76
     *
77
     * @throws InvalidAlgorithm if $algorithm is invalid
78
     */
79
    public static function make(string $algorithm, string $key)
80
    {
81
        switch ($algorithm) {
82
            case 'RC4':
83
                return new RC4Stream($key);
84
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
85
86
            case 'AES':
87
                return new AES128Stream($key);
88
                break;
89
90
            case 'AES256':
91
                return new AES256Stream($key);
92
                break;
93
94
            default:
95
                throw new InvalidAlgorithm("Unsupported encryption algorithm");
0 ignored issues
show
Bug introduced by
The type Smalot\PdfParser\Encryption\InvalidAlgorithm was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
96
        }
97
    }
98
}
99
100
101
class RC4Stream extends Stream
102
{
103
    public function decrypt(string $cyphertext, int $num, int $gen)
104
    {
105
        // 32 bytes minus 5 bytes of salting
106
        if (strlen($this->key) <= 27) {
107
            $key = $this->makeObjectKey($num, $gen);
108
        } else {
109
            $key = $this->key;
110
        }
111
        //# printf("%d_%d\n", $num, $gen);
112
        return \openssl_decrypt($cyphertext, "RC4-40", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
113
    }
114
115
116
    /**
117
     * Make a tweaked key that is based on info about the object.
118
     */
119
    public function makeObjectKey(int $num, int $gen)
120
    {
121
        $objectSalt = [
122
            ($num >> 0) & 0xff,
123
            ($num >> 8) & 0xff,
124
            ($num >> 16) & 0xff,
125
            ($gen >> 0) & 0xff,
126
            ($gen >> 8) & 0xff
127
        ];
128
        $blob = $this->key.\implode(\array_map("chr", $objectSalt));
129
        $hash = \md5($blob, true);
130
        return $hash;
131
    }
132
}
133
134
135
class AES128Stream extends Stream
136
{
137
    public function decrypt(string $block, int $num, int $gen)
138
    {
139
        // 32 bytes minus 9 bytes of salting
140
        if (strlen($key) <= 23) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key seems to be never defined.
Loading history...
141
            $key = $this->makeObjectKey($num, $gen);
142
        } else {
143
            $key = $this->key;
144
        }
145
146
        list($iv, $cyphertext) = self::splitBlock($block, 16);
147
        return \openssl_decrypt($cyphertext, "aes-128-cbc", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
148
    }
149
150
151
    /**
152
     * Make a tweaked key that is based on info about the object.
153
     */
154
    public function makeObjectKey(int $num, int $gen)
155
    {
156
        $objectSalt = [
157
            ($num >> 0) & 0xff,
158
            ($num >> 8) & 0xff,
159
            ($num >> 16) & 0xff,
160
            ($gen >> 0) & 0xff,
161
            ($gen >> 8) & 0xff
162
        ];
163
        $blob = $this->key.\implode(\array_map("chr", $objectSalt))."sAlT";
164
        $hash = \md5($blob, true);
165
        return $hash;
166
    }
167
}
168
169
170
class AES256Stream extends Stream
171
{
172
    /**
173
     * 
174
     */
175
    public function decrypt(string $block, int $num, int $gen)
176
    {
177
        $key = $this->makeObjectKey($num, $gen);
178
        list($iv, $cyphertext) = self::splitBlock($block, 16);
179
        return \openssl_decrypt($cyphertext, "aes-256-cbc", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
180
    }
181
182
183
    public function makeObjectKey(int $num, int $gen)
0 ignored issues
show
Unused Code introduced by
The parameter $gen is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

183
    public function makeObjectKey(int $num, /** @scrutinizer ignore-unused */ int $gen)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $num is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

183
    public function makeObjectKey(/** @scrutinizer ignore-unused */ int $num, int $gen)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
184
    {
185
        return $this->key;
186
    }
187
}
188