This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * PHP Class for handling Google Authenticator 2-factor authentication |
||
4 | * |
||
5 | * @author Michael Kliewe |
||
6 | * @copyright 2012 Michael Kliewe |
||
7 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License |
||
8 | * @link http://www.phpgangsta.de/ |
||
9 | */ |
||
10 | |||
11 | class PHPGangsta_GoogleAuthenticator |
||
0 ignored issues
–
show
This class is not in CamelCase format.
Classes in PHP are usually named in CamelCase. In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well. Thus the name database provider becomes ![]() |
|||
12 | { |
||
13 | protected $_codeLength = 6; |
||
14 | |||
15 | /** |
||
16 | * Create new secret. |
||
17 | * 16 characters, randomly chosen from the allowed base32 characters. |
||
18 | * |
||
19 | * @param int $secretLength |
||
20 | * @return string |
||
21 | */ |
||
22 | public function createSecret($secretLength = 16) |
||
23 | { |
||
24 | $validChars = $this->_getBase32LookupTable(); |
||
25 | unset($validChars[32]); |
||
26 | |||
27 | $secret = ''; |
||
28 | for ($i = 0; $i < $secretLength; $i++) { |
||
29 | $secret .= $validChars[array_rand($validChars)]; |
||
30 | } |
||
31 | return $secret; |
||
32 | } |
||
33 | |||
34 | /** |
||
35 | * Calculate the code, with given secret and point in time |
||
36 | * |
||
37 | * @param string $secret |
||
38 | * @param int|null $timeSlice |
||
39 | * @return string |
||
40 | */ |
||
41 | public function getCode($secret, $timeSlice = null) |
||
42 | { |
||
43 | if ($timeSlice === null) { |
||
44 | $timeSlice = floor(time() / 30); |
||
45 | } |
||
46 | |||
47 | $secretkey = $this->_base32Decode($secret); |
||
48 | |||
49 | // Pack time into binary string |
||
50 | $time = chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', $timeSlice); |
||
51 | // Hash it with users secret key |
||
52 | $hm = hash_hmac('SHA1', $time, $secretkey, true); |
||
0 ignored issues
–
show
|
|||
53 | // Use last nipple of result as index/offset |
||
54 | $offset = ord(substr($hm, -1)) & 0x0F; |
||
55 | // grab 4 bytes of the result |
||
56 | $hashpart = substr($hm, $offset, 4); |
||
57 | |||
58 | // Unpak binary value |
||
59 | $value = unpack('N', $hashpart); |
||
60 | $value = $value[1]; |
||
61 | // Only 32 bits |
||
62 | $value = $value & 0x7FFFFFFF; |
||
63 | |||
64 | $modulo = pow(10, $this->_codeLength); |
||
65 | return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT); |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Get QR-Code URL for image, from google charts |
||
70 | * |
||
71 | * @param string $name |
||
72 | * @param string $secret |
||
73 | * @return string |
||
74 | */ |
||
75 | public function getQRCodeGoogleUrl($name, $secret) { |
||
76 | $urlencoded = urlencode('otpauth://totp/' . $name . '?secret=' . $secret . ''); |
||
77 | return 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=' . $urlencoded . ''; |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now |
||
82 | * |
||
83 | * @param string $secret |
||
84 | * @param string $code |
||
85 | * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after) |
||
86 | * @return bool |
||
87 | */ |
||
88 | public function verifyCode($secret, $code, $discrepancy = 2) |
||
89 | { |
||
90 | $currentTimeSlice = floor(time() / 30) - 46800; |
||
91 | for ($hour = 0; $hour <= 24; $hour++) { |
||
92 | $currentTimeSlice = $currentTimeSlice + 3600; |
||
93 | for ($i = -$discrepancy; $i <= $discrepancy; $i++) { |
||
94 | $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i); |
||
95 | if ($calculatedCode == $code) { |
||
96 | return true; |
||
97 | } |
||
98 | } |
||
99 | } |
||
100 | |||
101 | return false; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * Set the code length, should be >=6 |
||
106 | * |
||
107 | * @param int $length |
||
108 | * @return PHPGangsta_GoogleAuthenticator |
||
109 | */ |
||
110 | public function setCodeLength($length) |
||
111 | { |
||
112 | $this->_codeLength = $length; |
||
113 | return $this; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Helper class to decode base32 |
||
118 | * |
||
119 | * @param $secret |
||
120 | * @return bool|string |
||
121 | */ |
||
122 | protected function _base32Decode($secret) |
||
123 | { |
||
124 | if (empty($secret)) { |
||
125 | return ''; |
||
126 | } |
||
127 | |||
128 | $base32chars = $this->_getBase32LookupTable(); |
||
129 | $base32charsFlipped = array_flip($base32chars); |
||
130 | |||
131 | $paddingCharCount = substr_count($secret, $base32chars[32]); |
||
132 | $allowedValues = array(6, 4, 3, 1, 0); |
||
133 | if (!in_array($paddingCharCount, $allowedValues)) { |
||
134 | return false; |
||
135 | } |
||
136 | for ($i = 0; $i < 4; $i++) { |
||
137 | if ($paddingCharCount == $allowedValues[$i] && |
||
138 | substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) { |
||
139 | return false; |
||
140 | } |
||
141 | } |
||
142 | $secret = str_replace('=', '', $secret); |
||
143 | $secret = str_split($secret); |
||
144 | $binaryString = ""; |
||
145 | $num = count($secret); |
||
146 | for ($i = 0; $i < $num; $i = $i + 8) { |
||
147 | $x = ""; |
||
0 ignored issues
–
show
|
|||
148 | if (!in_array($secret[$i], $base32chars)) { |
||
149 | return false; |
||
150 | } |
||
151 | for ($j = 0; $j < 8; $j++) { |
||
152 | $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT); |
||
153 | } |
||
154 | $eightBits = str_split($x, 8); |
||
155 | $bits = count($eightBits); |
||
156 | for ($z = 0; $z < $bits; $z++) { |
||
157 | $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : ""; |
||
0 ignored issues
–
show
|
|||
158 | } |
||
159 | } |
||
160 | return $binaryString; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Helper class to encode base32 |
||
165 | * |
||
166 | * @param string $secret |
||
167 | * @param bool $padding |
||
168 | * @return string |
||
169 | */ |
||
170 | protected function _base32Encode($secret, $padding = true) |
||
171 | { |
||
172 | if (empty($secret)) { |
||
173 | return ''; |
||
174 | } |
||
175 | |||
176 | $base32chars = $this->_getBase32LookupTable(); |
||
177 | |||
178 | $secret = str_split($secret); |
||
179 | $binaryString = ""; |
||
180 | $num = count($secret); |
||
181 | for ($i = 0; $i < $num; $i++) { |
||
182 | $binaryString .= str_pad(base_convert(ord($secret[$i]), 10, 2), 8, '0', STR_PAD_LEFT); |
||
183 | } |
||
184 | $fiveBitBinaryArray = str_split($binaryString, 5); |
||
185 | $base32 = ""; |
||
186 | $i = 0; |
||
187 | $num = count($fiveBitBinaryArray); |
||
188 | while ($i < $num) { |
||
189 | $base32 .= $base32chars[base_convert(str_pad($fiveBitBinaryArray[$i], 5, '0'), 2, 10)]; |
||
190 | $i++; |
||
191 | } |
||
192 | if ($padding && ($x = strlen($binaryString) % 40) != 0) { |
||
0 ignored issues
–
show
|
|||
193 | if ($x == 8) { |
||
194 | $base32 .= str_repeat($base32chars[32], 6); |
||
195 | } elseif ($x == 16) { |
||
196 | $base32 .= str_repeat($base32chars[32], 4); |
||
197 | } elseif ($x == 24) { |
||
198 | $base32 .= str_repeat($base32chars[32], 3); |
||
199 | } elseif ($x == 32) { |
||
200 | $base32 .= $base32chars[32]; |
||
201 | } |
||
202 | } |
||
203 | return $base32; |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Get array with all 32 characters for decoding from/encoding to base32 |
||
208 | * |
||
209 | * @return array |
||
210 | */ |
||
211 | protected function _getBase32LookupTable() |
||
212 | { |
||
213 | return array( |
||
214 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7 |
||
215 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15 |
||
216 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23 |
||
217 | 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31 |
||
218 | '=' // padding char |
||
219 | ); |
||
220 | } |
||
221 | } |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.