-
Notifications
You must be signed in to change notification settings - Fork 0
/
totp.class.php
57 lines (51 loc) · 1.72 KB
/
totp.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
class TOTP
{
private static array $BASE32_CHARS = array(
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7'
);
public function base32_decode($base32)
{
$bits = "";
for ($i = 0; $i < strlen($base32); $i++) {
$char = strtoupper($base32[$i]);
$idx = array_search($char, self::$BASE32_CHARS);
$bits .= sprintf('%05b', $idx);
}
$bytes = array();
for ($i = 0; $i < strlen($bits); $i += 8) {
$bytes[] = bindec(substr($bits, $i, 8));
}
return $bytes;
}
public function hmac_sha1($key, $data)
{
$key = pack('C*', ...$key);
return hash_hmac("sha1", $data, $key, true);
}
public function hotp($secret, $counter, $length = 6)
{
$secret = $this->base32_decode($secret);
$counter = pack("N*", 0) . pack("N*", $counter);
$hash = $this->hmac_sha1($secret, $counter);
$offset = ord(substr($hash, -1));
$truncated_hash = substr($hash, $offset & 0x0F, 4);
$value = unpack("N", $truncated_hash)[1];
$value = $value & 0x7FFFFFFF;
$modulo = pow(10, $length);
return str_pad($value % $modulo, $length, "0", STR_PAD_LEFT);
}
public function totp($secret, $time_step = 30, $start_time = 0, $length = 6)
{
$counter = intdiv((time() - $start_time), $time_step);
return $this->hotp($secret, $counter, $length);
}
public function timeLeft($time_step = 30)
{
$next_interval = ceil(time() / $time_step) * $time_step;
return $next_interval - time();
}
}