PasswordUtil   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 44
c 1
b 0
f 0
dl 0
loc 104
rs 10
wmc 15

3 Methods

Rating   Name   Duplication   Size   Complexity  
A generateRandomBytes() 0 3 1
C randomPassword() 0 54 12
A checkStrength() 0 13 2
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2019, Rubén Domínguez nuxsmin@$syspass.org
8
 *
9
 * This file is part of sysPass.
10
 *
11
 * sysPass is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * sysPass is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 *  along with sysPass.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace SP\Util;
26
27
28
use Defuse\Crypto\Core;
29
use Defuse\Crypto\Encoding;
30
use Defuse\Crypto\Exception\EnvironmentIsBrokenException;
31
32
/**
33
 * Class PasswordUtil
34
 *
35
 * @package SP\Util
36
 */
37
final class PasswordUtil
38
{
39
    const CHARS = 'abcdefghijklmnopqrstuwxyz';
40
    const CHARS_SPECIAL = '@$%&/()!_:.;{}^-';
41
    const CHARS_NUMBER = '0123456789';
42
    const FLAG_PASSWORD_NUMBER = 2;
43
    const FLAG_PASSWORD_SPECIAL = 4;
44
    const FLAG_PASSWORD_STRENGTH = 8;
45
46
    /**
47
     * Generate a ramdom password
48
     *
49
     * @param int $length Password length
50
     * @param int $flags  Password chars included and checking strength flags
51
     *
52
     * @return string
53
     */
54
    public static function randomPassword($length = 16, int $flags = null)
55
    {
56
        if ($flags === null) {
57
            $flags = self::FLAG_PASSWORD_SPECIAL | self::FLAG_PASSWORD_NUMBER | self::FLAG_PASSWORD_STRENGTH;
58
        }
59
60
        $useSpecial = ($flags & self::FLAG_PASSWORD_SPECIAL) > 0;
61
        $useNumbers = ($flags & self::FLAG_PASSWORD_NUMBER) > 0;
62
63
        $alphabet = self::CHARS . strtoupper(self::CHARS);
64
65
        if ($useSpecial) {
66
            $alphabet .= self::CHARS_SPECIAL;
67
        }
68
69
        if ($useNumbers) {
70
            $alphabet .= self::CHARS_NUMBER;
71
        }
72
73
        /**
74
         * @return array
75
         */
76
        $passGen = function () use ($alphabet, $length) {
77
            $pass = [];
78
            $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
79
80
            for ($i = 0; $i < $length; $i++) {
81
                $n = mt_rand(0, $alphaLength);
82
                $pass[] = $alphabet[$n];
83
            }
84
85
            return $pass;
86
        };
87
88
        if ($flags & self::FLAG_PASSWORD_STRENGTH) {
89
            do {
90
                $pass = $passGen();
91
                $strength = self::checkStrength($pass);
92
93
                $res = $strength['lower'] > 0 && $strength['upper'] > 0;
94
95
                if ($useSpecial === true) {
96
                    $res = $res && $strength['special'] > 0;
97
                }
98
99
                if ($useNumbers === true) {
100
                    $res = $res && $strength['number'] > 0;
101
                }
102
            } while ($res === false);
103
104
            return implode('', $pass);
105
        }
106
107
        return implode($passGen());
108
    }
109
110
    /**
111
     * @param array $pass
112
     *
113
     * @return array
114
     */
115
    public static function checkStrength(array $pass)
116
    {
117
        $charsUpper = strtoupper(self::CHARS);
118
        $strength = ['lower' => 0, 'upper' => 0, 'special' => 0, 'number' => 0];
119
120
        foreach ($pass as $char) {
121
            $strength['lower'] += substr_count(self::CHARS, $char);
122
            $strength['upper'] += substr_count($charsUpper, $char);
123
            $strength['special'] += substr_count(self::CHARS_SPECIAL, $char);
124
            $strength['number'] += substr_count(self::CHARS_NUMBER, $char);
125
        }
126
127
        return $strength;
128
    }
129
130
    /**
131
     * Generar una cadena aleatoria usuando criptografía.
132
     *
133
     * @param int $length opcional, con la longitud de la cadena
134
     *
135
     * @return string
136
     * @throws EnvironmentIsBrokenException
137
     */
138
    public static function generateRandomBytes($length = 30)
139
    {
140
        return Encoding::binToHex(Core::secureRandom($length));
141
    }
142
}