PluginProbe
The WP Remote WordPress Plugin / 6.47
The WP Remote WordPress Plugin v6.47
6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 5.73 All 53 releases
wpremote / wp_2fa / authenticator.php

authenticator.php in The WP Remote WordPress Plugin 6.47, at wp_2fa/authenticator.php

114 lines 3.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit;
3 if (!class_exists('WPRWP2FAAuthenticator')) :
4
5 class WPRWP2FAAuthenticator
6 {
7 private static $code_length = 6;
8
9 const BASE32_LOOKUP_TABLE = array(
10 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
11 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
12 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
13 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
14 '=', // padding char
15 );
16
17 private static function getCode($secret, $time_slice = null) {
18 if ($time_slice === null) {
19 $time_slice = floor(time() / 30);
20 }
21
22 $secret_key = self::_base32Decode($secret);
23 $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $time_slice);
24
25 $hm = hash_hmac('SHA1', $time, $secret_key, true);
26
27 $offset = ord(substr($hm, -1)) & 0x0F;
28 $hashpart = substr($hm, $offset, 4);
29
30 $value = unpack('N', $hashpart);
31 $value = $value[1];
32 $value = $value & 0x7FFFFFFF;
33
34 $modulo = pow(10, self::$code_length);
35
36 return str_pad($value % $modulo, self::$code_length, '0', STR_PAD_LEFT);
37 }
38
39 public static function verifyCode($secret, $code, $discrepancy = 1, $current_time_slice = null) {
40 if ($current_time_slice === null) {
41 $current_time_slice = floor(time() / 30);
42 }
43
44 if (strlen($code) != 6) {
45 return false;
46 }
47
48 for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
49 $calculated_code = self::getCode($secret, $current_time_slice + $i);
50 if (self::timingSafeEquals($calculated_code, $code)) {
51 return true;
52 }
53 }
54
55 return false;
56 }
57
58 private static function _base32Decode($secret) {
59 $base32_chars = WPRWP2FAAuthenticator::BASE32_LOOKUP_TABLE;
60 $base32_chars_flipped = array_flip($base32_chars);
61
62 $padding_char_count = substr_count($secret, $base32_chars[32]);
63 $allowed_values = array(6, 4, 3, 1, 0);
64 if (!in_array($padding_char_count, $allowed_values)) {
65 return false;
66 }
67 for ($i = 0; $i < 4; ++$i) {
68 if ($padding_char_count == $allowed_values[$i] &&
69 substr($secret, -($allowed_values[$i])) != str_repeat($base32_chars[32], $allowed_values[$i])) {
70 return false;
71 }
72 }
73 $secret = str_replace('=', '', $secret);
74
75 $secret = str_split($secret);
76 $binary_string = '';
77 for ($i = 0; $i < count($secret); $i = $i + 8) {
78 $x = '';
79 if (!in_array($secret[$i], $base32_chars)) {
80 return false;
81 }
82 for ($j = 0; $j < 8; ++$j) {
83 $x .= str_pad(base_convert(@$base32_chars_flipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
84 }
85 $eight_bits = str_split($x, 8);
86 for ($z = 0; $z < count($eight_bits); ++$z) {
87 $binary_string .= (($y = chr(base_convert($eight_bits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
88 }
89 }
90
91 return $binary_string;
92 }
93
94 private static function timingSafeEquals($safe_string, $user_string) {
95 if (function_exists('hash_equals')) {
96 return hash_equals($safe_string, $user_string);
97 }
98 $safe_len = strlen($safe_string);
99 $user_len = strlen($user_string);
100
101 if ($user_len != $safe_len) {
102 return false;
103 }
104
105 $result = 0;
106
107 for ($i = 0; $i < $user_len; ++$i) {
108 $result |= (ord($safe_string[$i]) ^ ord($user_string[$i]));
109 }
110
111 return $result === 0;
112 }
113 }
114 endif;