]>
Commit | Line | Data |
---|---|---|
fb70f26e AD |
1 | <?php |
2 | /* | |
310c18e6 | 3 | * Copyright (c) 2011 Le Lag |
fb70f26e AD |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | * of this software and associated documentation files (the "Software"), to deal | |
6 | * in the Software without restriction, including without limitation the rights | |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | * copies of the Software, and to permit persons to whom the Software is | |
9 | * furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 | * THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | namespace OTPHP { | |
24 | /** | |
310c18e6 AD |
25 | * One Time Password Generator |
26 | * | |
fb70f26e AD |
27 | * The OTP class allow the generation of one-time |
28 | * password that is described in rfc 4xxx. | |
310c18e6 AD |
29 | * |
30 | * This is class is meant to be compatible with | |
fb70f26e AD |
31 | * Google Authenticator. |
32 | * | |
33 | * This class was originally ported from the rotp | |
34 | * ruby library available at https://github.com/mdp/rotp | |
35 | */ | |
36 | class OTP { | |
37 | /** | |
38 | * The base32 encoded secret key | |
39 | * @var string | |
40 | */ | |
41 | public $secret; | |
42 | ||
43 | /** | |
44 | * The algorithm used for the hmac hash function | |
45 | * @var string | |
46 | */ | |
47 | public $digest; | |
48 | ||
49 | /** | |
50 | * The number of digits in the one-time password | |
51 | * @var integer | |
310c18e6 | 52 | */ |
fb70f26e AD |
53 | public $digits; |
54 | ||
55 | /** | |
56 | * Constructor for the OTP class | |
57 | * @param string $secret the secret key | |
58 | * @param array $opt options array can contain the | |
59 | * following keys : | |
60 | * @param integer digits : the number of digits in the one time password | |
61 | * Currently Google Authenticator only support 6. Defaults to 6. | |
62 | * @param string digest : the algorithm used for the hmac hash function | |
63 | * Google Authenticator only support sha1. Defaults to sha1 | |
64 | * | |
65 | * @return new OTP class. | |
66 | */ | |
67 | public function __construct($secret, $opt = Array()) { | |
68 | $this->digits = isset($opt['digits']) ? $opt['digits'] : 6; | |
69 | $this->digest = isset($opt['digest']) ? $opt['digest'] : 'sha1'; | |
70 | $this->secret = $secret; | |
71 | } | |
72 | ||
73 | /** | |
74 | * Generate a one-time password | |
75 | * | |
76 | * @param integer $input : number used to seed the hmac hash function. | |
77 | * This number is usually a counter (HOTP) or calculated based on the current | |
78 | * timestamp (see TOTP class). | |
310c18e6 | 79 | * @return integer the one-time password |
fb70f26e AD |
80 | */ |
81 | public function generateOTP($input) { | |
82 | $hash = hash_hmac($this->digest, $this->intToBytestring($input), $this->byteSecret()); | |
83 | foreach(str_split($hash, 2) as $hex) { // stupid PHP has bin2hex but no hex2bin WTF | |
84 | $hmac[] = hexdec($hex); | |
85 | } | |
86 | $offset = $hmac[19] & 0xf; | |
87 | $code = ($hmac[$offset+0] & 0x7F) << 24 | | |
88 | ($hmac[$offset + 1] & 0xFF) << 16 | | |
89 | ($hmac[$offset + 2] & 0xFF) << 8 | | |
90 | ($hmac[$offset + 3] & 0xFF); | |
91 | return $code % pow(10, $this->digits); | |
92 | } | |
93 | ||
94 | /** | |
95 | * Returns the binary value of the base32 encoded secret | |
96 | * @access private | |
97 | * This method should be private but was left public for | |
98 | * phpunit tests to work. | |
99 | * @return binary secret key | |
100 | */ | |
101 | public function byteSecret() { | |
310c18e6 | 102 | return Base32::decode($this->secret); |
fb70f26e AD |
103 | } |
104 | ||
105 | /** | |
106 | * Turns an integer in a OATH bytestring | |
107 | * @param integer $int | |
108 | * @access private | |
109 | * @return string bytestring | |
110 | */ | |
111 | public function intToBytestring($int) { | |
112 | $result = Array(); | |
113 | while($int != 0) { | |
114 | $result[] = chr($int & 0xFF); | |
115 | $int >>= 8; | |
116 | } | |
117 | return str_pad(join(array_reverse($result)), 8, "\000", STR_PAD_LEFT); | |
118 | } | |
119 | } | |
120 | } |