-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCrypt.php
444 lines (340 loc) · 12.7 KB
/
Crypt.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
<?php
declare(strict_types=1);
/*
* This file is part of the QuidPHP package <https://quidphp.com>
* Author: Pierre-Philippe Emond <emondpph@gmail.com>
* License: https://github.com/quidphp/base/blob/master/LICENSE
*/
namespace Quid\Base;
// crypt
// class which contains methods to deal with the most common PHP cryptography functions
final class Crypt extends Root
{
// config
protected static array $config = [
'passwordHash'=>[ // configuration pour password_hash et password_verify
'algo'=>PASSWORD_DEFAULT,
'options'=>['cost'=>11]],
'passwordNew'=>10, // longueur d'un nouveau mot de passe
'openssl'=>[ // configuration pour encrypt/decrypt openssl
'method'=>'AES-256-CBC',
'multiplier'=>7843,
'divider'=>747,
'sha'=>256],
'randomString'=>[
'alphanumeric'=>'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyWwZz0123456789', // caractère possible pour alphanumeric
'alpha'=>'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyWwZz', // caractère possible pour alpha
'alphaUpper'=>'ABCDEFGHIJKLMNOPQRSTUVXYWZ', // caractère possible pour alphaUpper
'alphaLower'=>'abcdefghijklmnopqrstuvxywz'] // caractère possible pour alphaLower
];
// passwordInfo
// retourne les informations sur la variable hash
final public static function passwordInfo(string $hash):array
{
return password_get_info($hash);
}
// passwordHash
// hash une string avec password_pash
// cette méthode cast les scalaires en string, pouvait crée des problèmes avec les données cast provenant de post
final public static function passwordHash(string $value,?array $option=null):?string
{
$return = null;
$option = Arr::plus(self::$config['passwordHash'],$option);
$hash = password_hash($value,$option['algo'],$option['options']);
if(is_string($hash))
$return = $hash;
return $return;
}
// passwordVerify
// verifie le mot de passe avec password_verify
final public static function passwordVerify(string $value,string $hash):bool
{
return password_verify($value,$hash);
}
// passwordNeedsRehash
// retourne vrai si le hash n'est pas compatible avec l'algorythme et les options
// de même, seul un password qui passe validate/isPassword est considéré
final public static function passwordNeedsRehash(string $value,?array $option=null):bool
{
$return = false;
$option = Arr::plus(self::$config['passwordHash'],$option);
$return = password_needs_rehash($value,$option['algo'],$option['options']);
return $return;
}
// passwordNew
// crée un nouveau mot de passe qui sera comptable avec la méthode validate/isPassword
// longueur minimum de 5, le password aura toujours au moins 2 chiffres
// utiliser lors du reset des mots de passe
final public static function passwordNew(?int $length=null):?string
{
$return = null;
$length ??= self::$config['passwordNew'] ?? null;
if(is_int($length) && $length > 4)
{
$return = self::randomString($length - 2,'alpha');
$return .= (string) self::randomInt(2);
}
return $return;
}
// passwordValidate
// retourne les messages négatifs en lien avec un changement de mot de passe
// newPasswordConfirm, oldPassword et oldPasswordHash sont facultatifs
// ceci est utilisé dans la classe user pour changer le mot de passe
final public static function passwordValidate(string $newPassword,?string $newPasswordConfirm=null,?string $oldPassword=null,?string $oldPasswordHash=null,?string $security=null,?array $option=null):?string
{
$return = null;
if(empty($newPassword))
$return = 'invalidValues';
elseif(!Validate::isPassword($newPassword,$security))
$return = 'invalidPassword';
elseif(is_string($newPasswordConfirm) && $newPassword !== $newPasswordConfirm)
$return = 'newPasswordMismatch';
elseif(is_string($oldPasswordHash) && !empty($oldPasswordHash) && !self::passwordNeedsRehash($oldPasswordHash,$option) && self::passwordVerify($newPassword,$oldPasswordHash,$option))
$return = 'noChange';
elseif(is_string($oldPassword))
{
if(!Validate::isPassword($oldPassword,$security))
$return = 'invalidOldPassword';
elseif($newPassword === $oldPassword)
$return = 'noChange';
elseif(is_string($oldPasswordHash) && !empty($oldPasswordHash) && !self::passwordVerify($oldPassword,$oldPasswordHash))
$return = 'oldPasswordMismatch';
}
return $return;
}
// passwordActivate
// retourne une string sha1, tel qu'utilisé pour générer la hash d'activation d'un password
final public static function passwordActivate(string $value):string
{
return self::sha($value,1);
}
// passwordAlgos
// retourne la liste des algorythmes de hash pour mot de passe
final public static function passwordAlgos():array
{
return password_algos();
}
// md5
// retourne un hash md5
final public static function md5(string $value,bool $binary=false):string
{
return md5($value,$binary);
}
// hash
// retourne un hash
final public static function hash(string $algo,string $value,bool $binary=false):string
{
return hash($algo,$value,$binary);
}
// sha
// retourne un hash sha
final public static function sha(string $value,int $type=256,bool $binary=false):string
{
return self::hash('sha'.$type,$value,$binary);
}
// hashHmac
// retourne un hash avec une clé
final public static function hashHmac(string $algo,string $value,string $key,bool $binary=false):string
{
return hash_hmac($algo,$value,$key,$binary);
}
// randomBytes
// à partir d'une fonction CSPRNG
final public static function randomBytes(int $length=11):string
{
return random_bytes($length);
}
// randomBool
// à partir d'une fonction CSPRNG
final public static function randomBool(int $min=0,int $max=1):bool
{
$random = random_int($min,$max);
return $random === $min;
}
// randomInt
// à partir d'une fonction CSPRNG
final public static function randomInt(?int $length=null,int $min=0,int $max=PHP_INT_MAX):int
{
$return = random_int($min,$max);
if(is_int($length))
$return = Num::sub(0,$length,$return);
return $return;
}
// randomString
// génère une string random à partir d'une chaîne de caracètre possible
// random généré à partir d'une fonction CSPRNG
final public static function randomString(int $length=40,?string $random=null,?bool $mb=null):string
{
$return = '';
$random = self::getRandomString($random);
if($length > 0 && is_string($random) && !empty($random))
{
$counter = 0;
$split = Str::split(1,$random,$mb);
$count = count($split);
if($count > 0)
{
$max = $count - 1;
while ($counter < $length)
{
$key = random_int(0,$max);
if(array_key_exists($key,$split))
{
$return .= $split[$key];
$counter++;
}
else
break;
}
}
}
return $return;
}
// getRandomString
// retourne les chars pour la méthode randomString
final public static function getRandomString(?string $value=null):?string
{
$return = null;
if(is_string($value))
{
if(array_key_exists($value,self::$config['randomString']))
$return = self::$config['randomString'][$value];
else
$return = $value;
}
elseif($value === null)
$return = current(self::$config['randomString']);
return $return;
}
// randomArray
// retourne une ou plusieurs slices d'un array de façon random
// random généré à partir d'une fonction CSPRNG
final public static function randomArray(array $array,int $length=1):array
{
$return = [];
for ($i=0; $i < $length; $i++)
{
$keys = array_keys($array);
$values = array_values($array);
$count = count($keys);
if($count > 0)
{
$max = $count - 1;
$index = random_int(0,$max);
$key = $keys[$index];
$value = $values[$index];
$return[$key] = $value;
unset($array[$key]);
}
else
break;
}
return $return;
}
// microtime
// retourne une string unique à partir de uniqid qui se base sur microtime
// 13 caractères si moreEntropy est false, 23 si true
final public static function microtime($value=null,bool $moreEntropy=false):?string
{
$return = null;
$prefix = '';
if(is_numeric($value) && $value > 0)
$prefix = self::randomString($value);
elseif(is_string($value))
$prefix = $value;
if(is_string($prefix))
$return = uniqid($prefix,$moreEntropy);
return $return;
}
// base64
// encode une chaîne en base64
final public static function base64(string $value):string
{
return base64_encode($value);
}
// base64Decode
// décode une chaîne présentement en base64
final public static function base64Decode(string $value,bool $strict=false):string
{
return base64_decode($value,$strict);
}
// openssl
// encrypte une chaîne à partir de openssl
// possible de décrypter la chaîne
final public static function openssl(string $value,string $key,string $iv=''):?string
{
$return = null;
if(!empty($value) && !empty($key))
{
$key .= self::openSslKey($key);
$method = self::$config['openssl']['method'];
$key = self::sha($key,self::$config['openssl']['sha']);
$iv = self::sha($iv,self::$config['openssl']['sha']);
$iv = substr($iv,0,16);
$ssl = openssl_encrypt($value,$method,$key,0,$iv);
$encode = self::base64($ssl);
if(is_string($encode))
$return = $encode;
}
return $return;
}
// opensslDecrypt
// décrypte une chaîne à partir de openssl
final public static function opensslDecrypt(string $value,string $key,string $iv=''):?string
{
$return = null;
if(!empty($value) && !empty($key))
{
$key .= self::openSslKey($key);
$method = self::$config['openssl']['method'];
$key = self::sha($key,self::$config['openssl']['sha']);
$iv = self::sha($iv,self::$config['openssl']['sha']);
$iv = substr($iv,0,16);
$decode = self::base64Decode($value);
$ssl = openssl_decrypt($decode,$method,$key,0,$iv);
if(is_string($ssl))
$return = $ssl;
}
return $return;
}
// openSslKey
// génère la clé ssl secrète pour openssl et opensslDecrypt
protected static function openSslKey(string $return):string
{
$return .= (strlen($return) * static::$config['openssl']['multiplier']);
$return .= (strlen($return) / static::$config['openssl']['divider']);
return $return;
}
// serialize
// serialize une variable, retourne une string
final public static function serialize($value):string
{
return serialize($value);
}
// unserialize
// unserialize une string, retourne la variable
// allowed classes permet de spécifier les classes de retour acceptés si la valeur contient des objets
final public static function unserialize(string $value,$allowedClasses=true)
{
$return = null;
$option = ['allowed_classes'=>($allowedClasses === false)? $allowedClasses:true];
if(is_object($allowedClasses))
$allowedClasses = $allowedClasses::class;
if(is_string($allowedClasses))
$allowedClasses = [$allowedClasses];
if(is_array($allowedClasses))
{
$allowed = [];
foreach ($allowedClasses as $v)
{
$v = Fqcn::str($v);
if(!empty($v))
$allowed[] = $v;
}
$option['allowed_classes'] = $allowed;
}
$return = unserialize($value,$option);
return $return;
}
}
?>