PluginProbe
Patchstack – WordPress & Plugins Security / 2.3.0
Patchstack – WordPress & Plugins Security v2.3.0
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
patchstack / includes / 2fa / rfc6238.php

rfc6238.php in Patchstack – WordPress & Plugins Security 2.3.0, at includes/2fa/rfc6238.php

120 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Do not allow the file to be called directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 require_once dirname( __FILE__ ) . '/base32.php';
9
10 class TokenAuth6238 {
11
12 /**
13 * Verify the code & token.
14 *
15 * @param string $secretkey Secret clue (base 32).
16 * @return bool True if success, false if failure
17 */
18 public static function verify( $secretkey, $code, $rangein30s = 3 ) {
19 $key = Base32Static::decode( $secretkey );
20 $unixtimestamp = time() / 30;
21
22 for ( $i = -( $rangein30s ); $i <= $rangein30s; $i++ ) {
23 $checktime = (int) ( $unixtimestamp + $i );
24 $thiskey = self::oath_hotp( $key, $checktime );
25
26 if ( self::stringEquals( (string) self::oath_truncate( $thiskey, 6 ), (string) $code ) ) {
27 return true;
28 }
29 }
30
31 return false;
32 }
33
34 /**
35 * Generate the random clue/key.
36 *
37 * @param integer $length
38 * @return string
39 */
40 public static function generateRandomClue( $length = 16 ) {
41 if ( function_exists( 'random_bytes' ) ) {
42 return Base32Static::encode( random_bytes( 10 ) );
43 }
44
45 require_once dirname( __FILE__ ) . '/polyfill/lib/random.php';
46 return Base32Static::encode( random_bytes( 10 ) );
47 }
48
49 /**
50 *
51 * @param string $key
52 * @param integer $counter
53 * @return string
54 */
55 private static function oath_hotp( $key, $counter ) {
56 $cur_counter = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
57
58 for ( $i = 7; $i >= 0; $i-- ) { // C for unsigned char, * for repeating to the end of the input data
59 $cur_counter[ $i ] = pack( 'C*', $counter );
60 $counter = $counter >> 8;
61 }
62
63 $binary = implode( $cur_counter );
64
65 // Pad to 8 characters
66 str_pad( $binary, 8, chr( 0 ), STR_PAD_LEFT );
67 return hash_hmac( 'sha1', $binary, $key );
68 }
69
70 /**
71 * Truncate
72 *
73 * @param string $hash
74 * @param integer $length
75 * @return boolean
76 */
77 private static function oath_truncate( $hash, $length = 6 ) {
78 $hashcharacters = str_split( $hash, 2 );
79
80 for ( $j = 0; $j < count( $hashcharacters ); $j++ ) {
81 $hmac_result[] = hexdec( $hashcharacters[ $j ] );
82 }
83
84 $offset = $hmac_result[19] & 0xf;
85 return (
86 ( ( $hmac_result[ $offset + 0 ] & 0x7f ) << 24 ) |
87 ( ( $hmac_result[ $offset + 1 ] & 0xff ) << 16 ) |
88 ( ( $hmac_result[ $offset + 2 ] & 0xff ) << 8 ) |
89 ( $hmac_result[ $offset + 3 ] & 0xff )
90 ) % pow( 10, $length );
91 }
92
93 /**
94 * Compare 2 strings with each other.
95 *
96 * @param string $own
97 * @param string $user
98 * @return boolean
99 */
100 private static function stringEquals( $own, $user ) {
101 if ( function_exists( 'hash_equals' ) ) {
102 return hash_equals( $own, $user );
103 }
104
105 $safeLen = strlen( $own );
106 $userLen = strlen( $user );
107
108 if ( $userLen != $safeLen ) {
109 return false;
110 }
111
112 $result = 0;
113 for ( $i = 0; $i < $userLen; $i++ ) {
114 $result |= ( ord( $own[$i] ) ^ ord( $user[$i] ) );
115 }
116
117 return $result === 0;
118 }
119 }
120