Subversion Repositories php_utils

Rev

Rev 31 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 daniel-mar 1
<?php
2
 
3
/*
4
 * OpenSSL php functions implemented using phpseclib
5
 * Copyright 2022 Daniel Marschall, ViaThinkSoft
6
 * Version 2022-04-09
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
 
21
// How to use this supplement:
22
// 1. Include phpseclib using composer and include the autoloader
23
// 2. Then, include this file. The openssl functions are now available.
24
 
25
// ATTENTION: This supplement/polyfill does only implement a few openssl_*() functions,
26
// and only a few algorithms: AES and RSA! Feel free to extend this library!
27
// The sign/verify and encrypt/decrypt functions should be binary compatible with
28
// the actual openssl functions.
29
 
30
if (!function_exists('openssl_pkey_new') && class_exists('\\phpseclib3\\Crypt\\RSA')) {
31
 
32
        define('OPENSSL_SUPPLEMENT', 1);
33
 
34
        $openssl_supplement_last_error = '';
35
 
36
        if (!defined('OPENSSL_KEYTYPE_RSA')) define('OPENSSL_KEYTYPE_RSA', 0);
37
 
38
        if (!defined('OPENSSL_RAW_DATA')) define('OPENSSL_RAW_DATA', 1);
39
        if (!defined('OPENSSL_ZERO_PADDING')) define('OPENSSL_ZERO_PADDING', 2);
40
 
41
        if (!defined('OPENSSL_ALGO_SHA1')) define('OPENSSL_ALGO_SHA1', 1);
42
        if (!defined('OPENSSL_ALGO_SHA224')) define('OPENSSL_ALGO_SHA224', 6);
43
        if (!defined('OPENSSL_ALGO_SHA256')) define('OPENSSL_ALGO_SHA256', 7);
44
        if (!defined('OPENSSL_ALGO_SHA384')) define('OPENSSL_ALGO_SHA384', 8);
45
        if (!defined('OPENSSL_ALGO_SHA512')) define('OPENSSL_ALGO_SHA512', 9);
46
        if (!defined('OPENSSL_ALGO_RMD160')) define('OPENSSL_ALGO_RMD160', 10);
47
        if (!defined('OPENSSL_ALGO_MD5')) define('OPENSSL_ALGO_MD5', 2);
48
        if (!defined('OPENSSL_ALGO_MD4')) define('OPENSSL_ALGO_MD4', 3);
49
 
50
        function openssl_pkey_new($pkey_config=null) {
51
                try {
52
                        $algo = $pkey_config && isset($pkey_config["private_key_type"]) ? $pkey_config["private_key_type"] : OPENSSL_KEYTYPE_RSA;
53
                        $bits = $pkey_config && isset($pkey_config["private_key_bits"]) ? $pkey_config["private_key_bits"] : 2048;
54
 
55
                        if ($algo == OPENSSL_KEYTYPE_RSA) {
56
                                $private = \phpseclib3\Crypt\RSA::createKey($bits);
57
                        } else {
58
                                throw new Exception("Algo not implemented");
59
                        }
60
 
61
                        $private = $private->withPadding(\phpseclib3\Crypt\RSA::ENCRYPTION_PKCS1 | \phpseclib3\Crypt\RSA::SIGNATURE_PKCS1);
62
 
63
                        $public = $private->getPublicKey()->withPadding(\phpseclib3\Crypt\RSA::ENCRYPTION_PKCS1 | \phpseclib3\Crypt\RSA::SIGNATURE_PKCS1);
64
 
65
                        return array($algo, $bits, $private, $public);
66
                } catch (Exception $e) {
67
                        global $openssl_supplement_last_error;
68
                        $openssl_supplement_last_error = $e->getMessage();
69
                        return false;
70
                }
71
        }
72
 
73
        function openssl_pkey_export($res, &$privKey, $passphrase = null, $options = null) {
74
                try {
75
                        if (!is_null($passphrase)) throw new Exception("passphrase not implemented");
76
                        //if (!is_null($options)) throw new Exception("options not implemented");
77
                        $privKey = $res[2]."";
78
                        return true;
79
                } catch (Exception $e) {
80
                        global $openssl_supplement_last_error;
81
                        $openssl_supplement_last_error = $e->getMessage();
82
                        return false;
83
                }
84
        }
85
 
86
        function openssl_pkey_get_details($res) {
87
                return array(
88
                        "bits" => $res[1],
89
                        "key" => $res[3]."",
90
                        "type" => $res[0]
91
                );
92
        }
93
 
94
        function openssl_public_encrypt($data, &$encrypted, $pubKey) {
95
                try {
96
                        if (is_string($pubKey)) $pubKey = openssl_pkey_get_public($pubKey);
97
                        $encrypted = $pubKey->encrypt($data);
98
                        return true;
99
                } catch (Exception $e) {
100
                        global $openssl_supplement_last_error;
101
                        $openssl_supplement_last_error = $e->getMessage();
102
                        return false;
103
                }
104
        }
105
 
106
        function openssl_private_decrypt($encrypted, &$decrypted, $privKey) {
107
                try {
108
                        if (is_string($privKey)) $privKey = openssl_pkey_get_private($privKey);
109
                        $decrypted = $privKey->decrypt($encrypted);
110
                        return true;
111
                } catch (Exception $e) {
112
                        global $openssl_supplement_last_error;
113
                        $openssl_supplement_last_error = $e->getMessage();
114
                        return false;
115
                }
116
        }
117
 
118
        function openssl_verify($msg, $signature, $public, $algorithm=OPENSSL_ALGO_SHA1) {
119
                try {
120
                        if ($algorithm == OPENSSL_ALGO_SHA1) $algorithm = 'SHA1';
121
                        if ($algorithm == OPENSSL_ALGO_SHA224) $algorithm = 'SHA224';
122
                        if ($algorithm == OPENSSL_ALGO_SHA256) $algorithm = 'SHA256)';
123
                        if ($algorithm == OPENSSL_ALGO_SHA384) $algorithm = 'SHA384';
124
                        if ($algorithm == OPENSSL_ALGO_SHA512) $algorithm = 'SHA512';
125
                        if ($algorithm == OPENSSL_ALGO_RMD160) $algorithm = 'RMD160';
126
                        if ($algorithm == OPENSSL_ALGO_MD5) $algorithm = 'MD5';
127
                        if ($algorithm == OPENSSL_ALGO_MD4) $algorithm = 'MD4';
128
                        if (is_string($public)) $public = openssl_pkey_get_public($public);
129
                        return $public->withHash($algorithm)->verify($msg, $signature) ? 1 : 0;
130
                } catch (Exception $e) {
131
                        global $openssl_supplement_last_error;
132
                        $openssl_supplement_last_error = $e->getMessage();
133
                        return false;
134
                }
135
        }
136
 
137
        function openssl_sign($msg, &$signature, $private, $algorithm=OPENSSL_ALGO_SHA1) {
138
                try {
139
                        if ($algorithm == OPENSSL_ALGO_SHA1) $algorithm = 'SHA1';
140
                        if ($algorithm == OPENSSL_ALGO_SHA224) $algorithm = 'SHA224';
141
                        if ($algorithm == OPENSSL_ALGO_SHA256) $algorithm = 'SHA256)';
142
                        if ($algorithm == OPENSSL_ALGO_SHA384) $algorithm = 'SHA384';
143
                        if ($algorithm == OPENSSL_ALGO_SHA512) $algorithm = 'SHA512';
144
                        if ($algorithm == OPENSSL_ALGO_RMD160) $algorithm = 'RMD160';
145
                        if ($algorithm == OPENSSL_ALGO_MD5) $algorithm = 'MD5';
146
                        if ($algorithm == OPENSSL_ALGO_MD4) $algorithm = 'MD4';
147
                        if (is_string($private)) $private = openssl_pkey_get_private($private);
148
                        $signature = $private->withHash($algorithm)->sign($msg);
149
                        return true;
150
                } catch (Exception $e) {
151
                        global $openssl_supplement_last_error;
152
                        $openssl_supplement_last_error = $e->getMessage();
153
                        return false;
154
                }
155
        }
156
 
157
        function openssl_error_string() {
158
                global $openssl_supplement_last_error;
159
                return $openssl_supplement_last_error;
160
        }
161
 
162
        function openssl_random_pseudo_bytes($len) {
163
                /*
164
                if (function_exists('openssl_random_pseudo_bytes')) {
165
                        $a = openssl_random_pseudo_bytes($len);
166
                        if ($a) return $a;
167
                }
168
                */
169
 
170
                if (function_exists('mcrypt_create_iv')) {
171
                        $a = bin2hex(mcrypt_create_iv($len, MCRYPT_DEV_URANDOM));
172
                        if ($a) return $a;
173
                }
174
 
175
                if (function_exists('random_bytes')) {
176
                        $a = random_bytes($len);
177
                        if ($a) return $a;
178
                }
179
 
180
                // Fallback to non-secure RNG
181
                $a = '';
182
                while (strlen($a) < $len*2) {
183
                        $a .= sha1(uniqid((string)mt_rand(), true));
184
                }
185
                $a = substr($a, 0, $len*2);
186
                return hex2bin($a);
187
        }
188
 
189
        function openssl_encrypt($data, $cipher_algo, $passphrase, $options=0, $iv="", &$tag=null, $aad="", $tag_length=16) {
190
                try {
191
                        if (!is_null($tag)) throw new Exception("tag not implemented");
192
                        if ($aad != "") throw new Exception("aad not implemented");
193
                        if ($tag_length != 16) throw new Exception("tag_length not implemented");
194
                        if (!preg_match('@AES\\-(.+)\\-(.+)@i', $cipher_algo, $m)) throw new Exception("Algo not implemented");
195
                        if (($options & OPENSSL_ZERO_PADDING) != 0) throw new Exception("OPENSSL_ZERO_PADDING not implemented");
196
                        $aes = new \phpseclib3\Crypt\AES($m[2]);
197
                        $aes->setKeyLength($m[1]);
198
                        $passphrase = substr($passphrase, 0, $m[1]/8);
199
                        $passphrase = str_pad($passphrase, $m[1]/8, "\0", STR_PAD_RIGHT);
200
                        $aes->setKey($passphrase);
201
                        $aes->setIV($iv);
202
                        $res = $aes->encrypt($data);
203
                        if (($options & OPENSSL_RAW_DATA) == 0) $res = base64_encode($res);
204
                        return $res;
205
                } catch (Exception $e) {
206
                        global $openssl_supplement_last_error;
207
                        $openssl_supplement_last_error = $e->getMessage();
208
                        return false;
209
                }
210
        }
211
 
212
        function openssl_decrypt($data, $cipher_algo, $passphrase, $options=0, $iv="", $tag=null, $aad="") {
213
                try {
214
                        if (!is_null($tag)) throw new Exception("tag not implemented");
215
                        if ($aad != "") throw new Exception("aad not implemented");
216
                        if (!preg_match('@AES\\-(.+)\\-(.+)@i', $cipher_algo, $m)) throw new Exception("Algo not implemented");
217
                        if (($options & OPENSSL_ZERO_PADDING) != 0) throw new Exception("OPENSSL_ZERO_PADDING not implemented");
218
                        $aes = new \phpseclib3\Crypt\AES($m[2]);
219
                        $aes->setKeyLength($m[1]);
220
                        $passphrase = substr($passphrase, 0, $m[1]/8);
221
                        $passphrase = str_pad($passphrase, $m[1]/8, "\0", STR_PAD_RIGHT);
222
                        $aes->setKey($passphrase);
223
                        $aes->setIV($iv);
224
                        if (($options & OPENSSL_RAW_DATA) == 0) $data = base64_decode($data);
225
                        return $aes->decrypt($data);
226
                } catch (Exception $e) {
227
                        global $openssl_supplement_last_error;
228
                        $openssl_supplement_last_error = $e->getMessage();
229
                        return false;
230
                }
231
        }
232
 
233
        function openssl_free_key($key) {
234
                // does nothing
235
        }
236
 
237
        function openssl_pkey_get_private($key, $passphrase=null) {
238
                try {
239
                        if (substr($key,0,7) === 'file://') {
240
                                if (!file_exists($file = substr($key, 7))) throw new Exception("file not found");
241
                                $key = file_get_contents($file);
242
                        }
243
                        if (is_null($passphrase)) $passphrase = false;
244
                        $privKey = \phpseclib3\Crypt\RSA::load($key, $passphrase);
245
                        return $privKey->withPadding(\phpseclib3\Crypt\RSA::ENCRYPTION_PKCS1 | \phpseclib3\Crypt\RSA::SIGNATURE_PKCS1); /** @phpstan-ignore-line */ // Call to an undefined method phpseclib3\Crypt\Common\AsymmetricKey::withPadding().
246
                } catch (Exception $e) {
247
                        global $openssl_supplement_last_error;
248
                        $openssl_supplement_last_error = $e->getMessage();
249
                        return false;
250
                }
251
        }
252
 
253
        function openssl_pkey_get_public($public_key) {
254
                try {
255
                        if (substr($public_key,0,7) === 'file://') {
256
                                if (!file_exists($file = substr($public_key, 7))) throw new Exception("file not found");
257
                                $public_key = file_get_contents($file);
258
                        }
259
                        $pubKey = \phpseclib3\Crypt\RSA::load($public_key);
260
                        return $pubKey->withPadding(\phpseclib3\Crypt\RSA::ENCRYPTION_PKCS1 | \phpseclib3\Crypt\RSA::SIGNATURE_PKCS1); /** @phpstan-ignore-line */ // Call to an undefined method phpseclib3\Crypt\Common\AsymmetricKey::withPadding().
261
                } catch (Exception $e) {
262
                        global $openssl_supplement_last_error;
263
                        $openssl_supplement_last_error = $e->getMessage();
264
                        return false;
265
                }
266
        }
267
 
268
}