dolibarr 24.0.0-beta
securitycore.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2024 Laurent Destailleur <eldy@users.sourceforge.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 * or see https://www.gnu.org/
17 */
18
27define('MAIN_SECURITY_REVERSIBLE_ALGO', 'AES-256-CTR');
28
29
38function isHTTPS()
39{
40 $isSecure = false;
41 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
42 $isSecure = true;
43 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
44 $isSecure = true;
45 }
46 return $isSecure;
47}
48
63function dolEncrypt($chain, $key = '', $ciphering = '', $forceseed = '', $obfuscationmode = 'dolcrypt')
64{
65 global $conf;
66 global $dolibarr_disable_dolcrypt_for_debug;
67
68 if ($chain === '' || is_null($chain)) {
69 return '';
70 }
71
72 $reg = array();
73 if (preg_match('/^(dolobfuscationv1[^:]+|dolcrypt):([^:]+):(.+)$/', $chain, $reg)) {
74 // The $chain is already an encrypted string
75 return $chain;
76 }
77
78 if (empty($key)) { // This may happen only with $obfuscationmode = 'dolcrypt'
79 if (!empty($conf->file->dolcrypt_key)) { // This code was to prepare a renaming of option but has been abandoned. Note: this param was never been set for the moment.
80 $key = $conf->file->dolcrypt_key;
81 } else {
82 // We fall back on the instance_unique_id (coming from $dolibarr_main_instance_unique_id, for backward compatibility).
83 $key = $conf->file->instance_unique_id;
84 }
85 }
86 if (empty($ciphering)) {
87 $ciphering = constant('MAIN_SECURITY_REVERSIBLE_ALGO');
88 }
89
90 $newchain = $chain;
91
92 if (function_exists('openssl_encrypt') && empty($dolibarr_disable_dolcrypt_for_debug)) {
93 if (empty($key)) {
94 return $chain;
95 }
96
97 $ivlen = 16;
98 if (function_exists('openssl_cipher_iv_length')) {
99 $ivlen = openssl_cipher_iv_length($ciphering);
100 }
101 if ($ivlen === false || $ivlen < 1 || $ivlen > 32) {
102 $ivlen = 16;
103 }
104 if (empty($forceseed)) {
105 $ivseed = dolGetRandomBytes($ivlen);
106 } else { // This case has been abandoned
107 $ivseed = dol_substr(md5($forceseed), 0, $ivlen, 'ascii', 1);
108 }
109
110 // If $key is a string with several keys, we keep only the first one (the other are alternative to use to decode)
111 $key = preg_replace('/,.*$/', '', $key); // Remove content after the ",".
112
113 $newchain = openssl_encrypt($chain, $ciphering, $key, 0, $ivseed);
114
115 return $obfuscationmode.':'.$ciphering.':'.$ivseed.':'.$newchain;
116 } else {
117 return $chain;
118 }
119}
120
132function dolDecrypt($chain, $key = '', $patterntotest = '')
133{
134 global $conf;
135
136 if ($chain === '' || is_null($chain)) {
137 return '';
138 }
139
140 $savkey = $key;
141
142 if (empty($key)) {
143 if (!empty($conf->file->dolcrypt_key)) {
144 // If dolcrypt_key is defined, we used it in priority. Note: this param has never been set for the moment.
145 $key = $conf->file->dolcrypt_key;
146 } else {
147 // We fall back on the instance_unique_id (coming from $dolibarr_main_instance_unique_id, for backward compatibility).
148 $key = !empty($conf->file->instance_unique_id) ? $conf->file->instance_unique_id : "";
149 }
150 }
151
152 $reg = array();
153
154 // Old method (no more used, kept for compatibility)
155 if (preg_match('/^crypted:(.+)$/', $chain, $reg)) {
156 return dol_decode($reg[1]);
157 }
158
159 // New method
160 if (preg_match('/^dol[^:]+:([^:]+):(.+)$/', $chain, $reg)) {
161 // Do not enable this log, except during debug
162 //dol_syslog("We try to decrypt the chain: ".$chain, LOG_DEBUG);
163
164 $ciphering = $reg[1];
165 if (function_exists('openssl_decrypt')) {
166 if (empty($key)) {
167 dol_syslog("Error dolDecrypt decrypt key is empty", LOG_WARNING);
168 return $chain;
169 }
170 $tmpexplode = explode(':', $reg[2]);
171 if (!empty($tmpexplode[1])) {
172 $data = $tmpexplode[1];
173 $iv = $tmpexplode[0];
174 } else {
175 $data = (string) $tmpexplode[0];
176 $iv = '';
177 }
178
179 $keys = explode(',', $key);
180
181 // Loop on each possible keys (usually one, but can be more in future if we have a list of keys)
182 foreach ($keys as $tmpkey) {
183 $newchain = openssl_decrypt($data, $ciphering, $tmpkey, 0, $iv);
184 if (!empty($patterntotest) && preg_match('/^'.preg_quote($patterntotest, '/').'/', $newchain)) {
185 break; // decoding is ok, we stop the loop.
186 }
187 if (ascii_check($newchain)) {
188 break; // decoding seems ok, we stop the loop (1rst key is main key, the other one are alternative we can use if we have a pattern to test the decoding).
189 }
190 }
191
192 // Test validity of decryption
193 if (!ascii_check($newchain)) {
194 if (empty($savkey)) {
195 dol_syslog("Error dolDecrypt failed: The key dolibarr_main_dolcrypt or dolibarr_main_instance_unique_id, found in conf.php file, is the the one used to encrypt this encrypted string", LOG_ERR);
196 } else {
197 dol_syslog("Error dolDecrypt failed: The string decoded with the key return a non valid value (not ascii)", LOG_ERR);
198 }
199 return $chain;
200 }
201 } else {
202 dol_syslog("Error dolDecrypt openssl_decrypt is not available", LOG_ERR);
203 return $chain;
204 }
205
206 return $newchain;
207 } else {
208 return $chain;
209 }
210}
211
232function dol_hash($chain, $type = '0', $nosalt = 0, $mode = 0)
233{
234 // No need to add salt for password_hash
235 if (($type == '0' || $type == 'auto') && getDolGlobalString('MAIN_SECURITY_HASH_ALGO') == 'password_hash' && function_exists('password_hash')) {
236 // if string contains a null character that can't be encoded. Return an error instead of fatal error.
237 if (strpos($chain, "\0") !== false) {
238 if ($mode == 1) {
239 return array('pass_encrypted' => 'Invalid string to encrypt. Contains a null character', 'pass_encoding' => '');
240 } else {
241 return 'Invalid string to encrypt. Contains a null character.';
242 }
243 }
244
245 // Build a password hash with default algorithm
246 if ($mode == 1) {
247 return array('pass_encrypted' => password_hash($chain, PASSWORD_DEFAULT), 'pass_encoding' => 'password_hash');
248 } else {
249 return password_hash($chain, PASSWORD_DEFAULT);
250 }
251 }
252
253 // Salt value
254 if (getDolGlobalString('MAIN_SECURITY_SALT') && $type != '4' && $type !== 'openldap' && empty($nosalt)) {
255 $chain = getDolGlobalString('MAIN_SECURITY_SALT') . $chain;
256 }
257
258 if ($type == '1' || $type == 'sha1') {
259 if ($mode == 1) {
260 return array('pass_encrypted' => sha1($chain), 'pass_encoding' => 'sha1');
261 } else {
262 return sha1($chain);
263 }
264 } elseif ($type == '2' || $type == 'sha1md5') {
265 if ($mode == 1) {
266 return array('pass_encrypted' => sha1(md5($chain)), 'pass_encoding' => 'sha1md5');
267 } else {
268 return sha1(md5($chain));
269 }
270 } elseif ($type == '3' || $type == 'md5') { // For hashing with no need of security
271 if ($mode == 1) {
272 return array('pass_encrypted' => md5($chain), 'pass_encoding' => 'md5');
273 } else {
274 return md5($chain);
275 }
276 } elseif ($type == '4' || $type == 'openldap') {
277 if ($mode == 1) {
278 return array('pass_encrypted' => dolGetLdapPasswordHash($chain, getDolGlobalString('LDAP_PASSWORD_HASH_TYPE', 'md5')), 'pass_encoding' => 'ldappasswordhash'.getDolGlobalString('LDAP_PASSWORD_HASH_TYPE', 'md5'));
279 } else {
280 return dolGetLdapPasswordHash($chain, getDolGlobalString('LDAP_PASSWORD_HASH_TYPE', 'md5'));
281 }
282 } elseif ($type == '5' || $type == 'sha256') {
283 if ($mode == 1) {
284 return array('pass_encrypted' => hash('sha256', $chain), 'pass_encoding' => 'sha256');
285 } else {
286 return hash('sha256', $chain);
287 }
288 } elseif ($type == '6' || $type == 'password_hash') {
289 if ($mode == 1) {
290 return array('pass_encrypted' => password_hash($chain, PASSWORD_DEFAULT), 'pass_encoding' => 'password_hash');
291 } else {
292 return password_hash($chain, PASSWORD_DEFAULT);
293 }
294 } elseif (getDolGlobalString('MAIN_SECURITY_HASH_ALGO') == 'sha1') {
295 if ($mode == 1) {
296 return array('pass_encrypted' => sha1($chain), 'pass_encoding' => 'sha1');
297 } else {
298 return sha1($chain);
299 }
300 } elseif (getDolGlobalString('MAIN_SECURITY_HASH_ALGO') == 'sha1md5') {
301 if ($mode == 1) {
302 return array('pass_encrypted' => sha1(md5($chain)), 'pass_encoding' => 'sha1md5');
303 } else {
304 return sha1(md5($chain));
305 }
306 }
307
308 // No particular encoding defined, use default
309 if ($mode == 1) {
310 return array('pass_encrypted' => md5($chain), 'pass_encoding' => 'md5');
311 } else {
312 return md5($chain);
313 }
314}
315
328function dol_verifyHash($chain, $hash, $type = '0')
329{
330 if ($type == '0' && getDolGlobalString('MAIN_SECURITY_HASH_ALGO') == 'password_hash' && function_exists('password_verify')) {
331 // Try to autodetect which algo we used
332 if (! empty($hash[0]) && $hash[0] == '$') {
333 return password_verify($chain, $hash);
334 } elseif (dol_strlen($hash) == 32) {
335 return dol_verifyHash($chain, $hash, '3'); // md5
336 } elseif (dol_strlen($hash) == 40) {
337 return dol_verifyHash($chain, $hash, '2'); // sha1md5
338 }
339
340 return false;
341 }
342
343 return dol_hash($chain, $type) == $hash;
344}
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length for cryptographic purposes.
dol_decode($chain, $key='1')
Decode a base 64 encoded + specific delta change.
dolGetLdapPasswordHash($password, $type='md5')
Returns a specific ldap hash of a password.
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
dolDecrypt($chain, $key='', $patterntotest='')
Decode a string with a symmetric encryption.
isHTTPS()
Return if we are using a HTTPS connection Check HTTPS (no way to be modified by user but may be empty...
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...
dolEncrypt($chain, $key='', $ciphering='', $forceseed='', $obfuscationmode='dolcrypt')
Encode a string with a symmetric encryption.