1
1
<?php
2
2
3
3
/**
4
- * PHP Class for handling Google Authenticator 2-factor authentication
4
+ * PHP Class for handling Google Authenticator 2-factor authentication.
5
5
*
6
6
* @author Michael Kliewe
7
7
* @copyright 2012 Michael Kliewe
8
8
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
9
+ *
9
10
* @link http://www.phpgangsta.de/
10
11
*/
11
-
12
12
class PHPGangsta_GoogleAuthenticator
13
13
{
14
14
protected $ _codeLength = 6 ;
@@ -18,6 +18,7 @@ class PHPGangsta_GoogleAuthenticator
18
18
* 16 characters, randomly chosen from the allowed base32 characters.
19
19
*
20
20
* @param int $secretLength
21
+ *
21
22
* @return string
22
23
*/
23
24
public function createSecret ($ secretLength = 16 )
@@ -41,20 +42,22 @@ public function createSecret($secretLength = 16)
41
42
}
42
43
}
43
44
if ($ rnd !== false ) {
44
- for ($ i = 0 ; $ i < $ secretLength ; $ i ++ ) {
45
+ for ($ i = 0 ; $ i < $ secretLength ; ++ $ i ) {
45
46
$ secret .= $ validChars [ord ($ rnd [$ i ]) & 31 ];
46
47
}
47
48
} else {
48
49
throw new Exception ('No source of secure random ' );
49
50
}
51
+
50
52
return $ secret ;
51
53
}
52
54
53
55
/**
54
- * Calculate the code, with given secret and point in time
56
+ * Calculate the code, with given secret and point in time.
55
57
*
56
- * @param string $secret
58
+ * @param string $secret
57
59
* @param int|null $timeSlice
60
+ *
58
61
* @return string
59
62
*/
60
63
public function getCode ($ secret , $ timeSlice = null )
@@ -81,37 +84,42 @@ public function getCode($secret, $timeSlice = null)
81
84
$ value = $ value & 0x7FFFFFFF ;
82
85
83
86
$ modulo = pow (10 , $ this ->_codeLength );
87
+
84
88
return str_pad ($ value % $ modulo , $ this ->_codeLength , '0 ' , STR_PAD_LEFT );
85
89
}
86
90
87
91
/**
88
- * Get QR-Code URL for image, from google charts
92
+ * Get QR-Code URL for image, from google charts.
89
93
*
90
94
* @param string $name
91
95
* @param string $secret
92
96
* @param string $title
93
- * @param array $params
97
+ * @param array $params
98
+ *
94
99
* @return string
95
100
*/
96
- public function getQRCodeGoogleUrl ($ name , $ secret , $ title = null , $ params = array ()) {
97
- $ width = !empty ($ params ['width ' ]) && (int )$ params ['width ' ] > 0 ? (int )$ params ['width ' ] : 200 ;
98
- $ height = !empty ($ params ['height ' ]) && (int )$ params ['height ' ] > 0 ? (int )$ params ['height ' ] : 200 ;
101
+ public function getQRCodeGoogleUrl ($ name , $ secret , $ title = null , $ params = array ())
102
+ {
103
+ $ width = !empty ($ params ['width ' ]) && (int ) $ params ['width ' ] > 0 ? (int ) $ params ['width ' ] : 200 ;
104
+ $ height = !empty ($ params ['height ' ]) && (int ) $ params ['height ' ] > 0 ? (int ) $ params ['height ' ] : 200 ;
99
105
$ level = !empty ($ params ['level ' ]) && array_search ($ params ['level ' ], array ('L ' , 'M ' , 'Q ' , 'H ' )) !== false ? $ params ['level ' ] : 'M ' ;
100
106
101
107
$ urlencoded = urlencode ('otpauth://totp/ ' .$ name .'?secret= ' .$ secret .'' );
102
- if (isset ($ title )) {
103
- $ urlencoded .= urlencode ('&issuer= ' .urlencode ($ title ));
108
+ if (isset ($ title )) {
109
+ $ urlencoded .= urlencode ('&issuer= ' .urlencode ($ title ));
104
110
}
111
+
105
112
return 'https://chart.googleapis.com/chart?chs= ' .$ width .'x ' .$ height .'&chld= ' .$ level .'|0&cht=qr&chl= ' .$ urlencoded .'' ;
106
113
}
107
114
108
115
/**
109
- * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now
116
+ * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
110
117
*
111
- * @param string $secret
112
- * @param string $code
113
- * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
118
+ * @param string $secret
119
+ * @param string $code
120
+ * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
114
121
* @param int|null $currentTimeSlice time slice if we want use other that time()
122
+ *
115
123
* @return bool
116
124
*/
117
125
public function verifyCode ($ secret , $ code , $ discrepancy = 1 , $ currentTimeSlice = null )
@@ -124,7 +132,7 @@ public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice =
124
132
return false ;
125
133
}
126
134
127
- for ($ i = -$ discrepancy ; $ i <= $ discrepancy ; $ i ++ ) {
135
+ for ($ i = -$ discrepancy ; $ i <= $ discrepancy ; ++ $ i ) {
128
136
$ calculatedCode = $ this ->getCode ($ secret , $ currentTimeSlice + $ i );
129
137
if ($ this ->timingSafeEquals ($ calculatedCode , $ code )) {
130
138
return true ;
@@ -135,56 +143,68 @@ public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice =
135
143
}
136
144
137
145
/**
138
- * Set the code length, should be >=6
146
+ * Set the code length, should be >=6.
139
147
*
140
148
* @param int $length
149
+ *
141
150
* @return PHPGangsta_GoogleAuthenticator
142
151
*/
143
152
public function setCodeLength ($ length )
144
153
{
145
154
$ this ->_codeLength = $ length ;
155
+
146
156
return $ this ;
147
157
}
148
158
149
159
/**
150
- * Helper class to decode base32
160
+ * Helper class to decode base32.
151
161
*
152
162
* @param $secret
163
+ *
153
164
* @return bool|string
154
165
*/
155
166
protected function _base32Decode ($ secret )
156
167
{
157
- if (empty ($ secret )) return '' ;
168
+ if (empty ($ secret )) {
169
+ return '' ;
170
+ }
158
171
159
172
$ base32chars = $ this ->_getBase32LookupTable ();
160
173
$ base32charsFlipped = array_flip ($ base32chars );
161
174
162
175
$ paddingCharCount = substr_count ($ secret , $ base32chars [32 ]);
163
176
$ allowedValues = array (6 , 4 , 3 , 1 , 0 );
164
- if (!in_array ($ paddingCharCount , $ allowedValues )) return false ;
165
- for ($ i = 0 ; $ i < 4 ; $ i ++){
177
+ if (!in_array ($ paddingCharCount , $ allowedValues )) {
178
+ return false ;
179
+ }
180
+ for ($ i = 0 ; $ i < 4 ; ++$ i ) {
166
181
if ($ paddingCharCount == $ allowedValues [$ i ] &&
167
- substr ($ secret , -($ allowedValues [$ i ])) != str_repeat ($ base32chars [32 ], $ allowedValues [$ i ])) return false ;
182
+ substr ($ secret , -($ allowedValues [$ i ])) != str_repeat ($ base32chars [32 ], $ allowedValues [$ i ])) {
183
+ return false ;
184
+ }
168
185
}
169
- $ secret = str_replace ('= ' ,'' , $ secret );
186
+ $ secret = str_replace ('= ' , '' , $ secret );
170
187
$ secret = str_split ($ secret );
171
- $ binaryString = "" ;
172
- for ($ i = 0 ; $ i < count ($ secret ); $ i = $ i +8 ) {
173
- $ x = "" ;
174
- if (!in_array ($ secret [$ i ], $ base32chars )) return false ;
175
- for ($ j = 0 ; $ j < 8 ; $ j ++) {
188
+ $ binaryString = '' ;
189
+ for ($ i = 0 ; $ i < count ($ secret ); $ i = $ i + 8 ) {
190
+ $ x = '' ;
191
+ if (!in_array ($ secret [$ i ], $ base32chars )) {
192
+ return false ;
193
+ }
194
+ for ($ j = 0 ; $ j < 8 ; ++$ j ) {
176
195
$ x .= str_pad (base_convert (@$ base32charsFlipped [@$ secret [$ i + $ j ]], 10 , 2 ), 5 , '0 ' , STR_PAD_LEFT );
177
196
}
178
197
$ eightBits = str_split ($ x , 8 );
179
- for ($ z = 0 ; $ z < count ($ eightBits ); $ z ++ ) {
180
- $ binaryString .= ( ($ y = chr (base_convert ($ eightBits [$ z ], 2 , 10 ))) || ord ($ y ) == 48 ) ? $ y: "" ;
198
+ for ($ z = 0 ; $ z < count ($ eightBits ); ++ $ z ) {
199
+ $ binaryString .= (($ y = chr (base_convert ($ eightBits [$ z ], 2 , 10 ))) || ord ($ y ) == 48 ) ? $ y : '' ;
181
200
}
182
201
}
202
+
183
203
return $ binaryString ;
184
204
}
185
205
186
206
/**
187
- * Get array with all 32 characters for decoding from/encoding to base32
207
+ * Get array with all 32 characters for decoding from/encoding to base32.
188
208
*
189
209
* @return array
190
210
*/
@@ -195,18 +215,18 @@ protected function _getBase32LookupTable()
195
215
'I ' , 'J ' , 'K ' , 'L ' , 'M ' , 'N ' , 'O ' , 'P ' , // 15
196
216
'Q ' , 'R ' , 'S ' , 'T ' , 'U ' , 'V ' , 'W ' , 'X ' , // 23
197
217
'Y ' , 'Z ' , '2 ' , '3 ' , '4 ' , '5 ' , '6 ' , '7 ' , // 31
198
- '= ' // padding char
218
+ '= ' , // padding char
199
219
);
200
220
}
201
221
202
222
/**
203
223
* A timing safe equals comparison
204
- * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html
224
+ * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
205
225
*
206
226
* @param string $safeString The internal (safe) value to be checked
207
227
* @param string $userString The user submitted (unsafe) value
208
228
*
209
- * @return boolean True if the two strings are identical.
229
+ * @return bool True if the two strings are identical
210
230
*/
211
231
private function timingSafeEquals ($ safeString , $ userString )
212
232
{
@@ -222,7 +242,7 @@ private function timingSafeEquals($safeString, $userString)
222
242
223
243
$ result = 0 ;
224
244
225
- for ($ i = 0 ; $ i < $ userLen ; $ i ++ ) {
245
+ for ($ i = 0 ; $ i < $ userLen ; ++ $ i ) {
226
246
$ result |= (ord ($ safeString [$ i ]) ^ ord ($ userString [$ i ]));
227
247
}
228
248
0 commit comments