Passed
Push — devel-3.0 ( 40e719...463a23 )
by Rubén
03:27
created

PasswordUtil::checkStrength()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2018, 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
31
/**
32
 * Class PasswordUtil
33
 *
34
 * @package SP\Util
35
 */
36
final class PasswordUtil
37
{
38
    const CHARS = 'abcdefghijklmnopqrstuwxyz';
39
    const CHARS_SPECIAL = '@$%&/()!_:.;{}^-';
40
    const CHARS_NUMBER = '0123456789';
41
    const FLAG_PASSWORD_NUMBER = 2;
42
    const FLAG_PASSWORD_SPECIAL = 4;
43
    const FLAG_PASSWORD_STRENGTH = 8;
44
45
    /**
46
     * Generate a ramdom password
47
     *
48
     * @param int $length Password length
49
     * @param int $flags  Password chars included and checking strength flags
50
     *
51
     * @return string
52
     */
53
    public static function randomPassword($length = 16, int $flags = null)
54
    {
55
        if ($flags === null) {
56
            $flags = self::FLAG_PASSWORD_SPECIAL | self::FLAG_PASSWORD_NUMBER | self::FLAG_PASSWORD_STRENGTH;
57
        }
58
59
        $useSpecial = ($flags & self::FLAG_PASSWORD_SPECIAL) > 0;
60
        $useNumbers = ($flags & self::FLAG_PASSWORD_NUMBER) > 0;
61
62
        $alphabet = self::CHARS . strtoupper(self::CHARS);
63
64
        if ($useSpecial) {
65
            $alphabet .= self::CHARS_SPECIAL;
66
        }
67
68
        if ($useNumbers) {
69
            $alphabet .= self::CHARS_NUMBER;
70
        }
71
72
        /**
73
         * @return array
74
         */
75
        $passGen = function () use ($alphabet, $length) {
76
            $pass = [];
77
            $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
78
79
            for ($i = 0; $i < $length; $i++) {
80
                $n = mt_rand(0, $alphaLength);
81
                $pass[] = $alphabet[$n];
82
            }
83
84
            return $pass;
85
        };
86
87
        if ($flags & self::FLAG_PASSWORD_STRENGTH) {
88
            do {
89
                $pass = $passGen();
90
                $strength = self::checkStrength($pass);
91
92
                $res = $strength['lower'] > 0 && $strength['upper'] > 0;
93
94
                if ($useSpecial === true) {
95
                    $res = $res && $strength['special'] > 0;
96
                }
97
98
                if ($useNumbers === true) {
99
                    $res = $res && $strength['number'] > 0;
100
                }
101
            } while ($res === false);
102
103
            return implode('', $pass);
104
        }
105
106
        return implode($passGen());
107
    }
108
109
    /**
110
     * @param array $pass
111
     *
112
     * @return array
113
     */
114
    public static function checkStrength(array $pass)
115
    {
116
        $charsUpper = strtoupper(self::CHARS);
117
        $strength = ['lower' => 0, 'upper' => 0, 'special' => 0, 'number' => 0];
118
119
        foreach ($pass as $char) {
120
            $strength['lower'] += substr_count(self::CHARS, $char);
121
            $strength['upper'] += substr_count($charsUpper, $char);
122
            $strength['special'] += substr_count(self::CHARS_SPECIAL, $char);
123
            $strength['number'] += substr_count(self::CHARS_NUMBER, $char);
124
        }
125
126
        return $strength;
127
    }
128
129
    /**
130
     * Generar una cadena aleatoria usuando criptografía.
131
     *
132
     * @param int $length opcional, con la longitud de la cadena
133
     *
134
     * @return string
135
     * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
136
     */
137
    public static function generateRandomBytes($length = 30)
138
    {
139
        return Encoding::binToHex(Core::secureRandom($length));
140
    }
141
}