Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)
This commit is contained in:
+225
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
//namespace Base32;
|
||||
|
||||
/**
|
||||
* Base32 encoder and decoder
|
||||
*
|
||||
* Last update: 2012-06-20
|
||||
*
|
||||
* RFC 4648 compliant
|
||||
* @link http://www.ietf.org/rfc/rfc4648.txt
|
||||
*
|
||||
* Some groundwork based on this class
|
||||
* https://github.com/NTICompass/PHP-Base32
|
||||
*
|
||||
* @author Christian Riesen <chris.riesen@gmail.com>
|
||||
* @link http://christianriesen.com
|
||||
* @license MIT License see LICENSE file
|
||||
*/
|
||||
class Base32
|
||||
{
|
||||
/**
|
||||
* Table for encoding base32
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $encode = array(
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
4 => 'E',
|
||||
5 => 'F',
|
||||
6 => 'G',
|
||||
7 => 'H',
|
||||
8 => 'I',
|
||||
9 => 'J',
|
||||
10 => 'K',
|
||||
11 => 'L',
|
||||
12 => 'M',
|
||||
13 => 'N',
|
||||
14 => 'O',
|
||||
15 => 'P',
|
||||
16 => 'Q',
|
||||
17 => 'R',
|
||||
18 => 'S',
|
||||
19 => 'T',
|
||||
20 => 'U',
|
||||
21 => 'V',
|
||||
22 => 'W',
|
||||
23 => 'X',
|
||||
24 => 'Y',
|
||||
25 => 'Z',
|
||||
26 => 2,
|
||||
27 => 3,
|
||||
28 => 4,
|
||||
29 => 5,
|
||||
30 => 6,
|
||||
31 => 7,
|
||||
32 => '=',
|
||||
);
|
||||
|
||||
/**
|
||||
* Table for decoding base32
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $decode = array(
|
||||
'A' => 0,
|
||||
'B' => 1,
|
||||
'C' => 2,
|
||||
'D' => 3,
|
||||
'E' => 4,
|
||||
'F' => 5,
|
||||
'G' => 6,
|
||||
'H' => 7,
|
||||
'I' => 8,
|
||||
'J' => 9,
|
||||
'K' => 10,
|
||||
'L' => 11,
|
||||
'M' => 12,
|
||||
'N' => 13,
|
||||
'O' => 14,
|
||||
'P' => 15,
|
||||
'Q' => 16,
|
||||
'R' => 17,
|
||||
'S' => 18,
|
||||
'T' => 19,
|
||||
'U' => 20,
|
||||
'V' => 21,
|
||||
'W' => 22,
|
||||
'X' => 23,
|
||||
'Y' => 24,
|
||||
'Z' => 25,
|
||||
2 => 26,
|
||||
3 => 27,
|
||||
4 => 28,
|
||||
5 => 29,
|
||||
6 => 30,
|
||||
7 => 31,
|
||||
'=' => 32,
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates an array from a binary string into a given chunk size
|
||||
*
|
||||
* @param string $binaryString String to chunk
|
||||
* @param integer $bits Number of bits per chunk
|
||||
* @return array
|
||||
*/
|
||||
private static function chunk($binaryString, $bits)
|
||||
{
|
||||
$binaryString = chunk_split($binaryString, $bits, ' ');
|
||||
|
||||
if (substr($binaryString, (strlen($binaryString)) - 1) == ' ') {
|
||||
$binaryString = substr($binaryString, 0, strlen($binaryString)-1);
|
||||
}
|
||||
|
||||
return explode(' ', $binaryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes into base32
|
||||
*
|
||||
* @param string $string Clear text string
|
||||
* @return string Base32 encoded string
|
||||
*/
|
||||
public static function encode($string)
|
||||
{
|
||||
if (strlen($string) == 0) {
|
||||
// Gives an empty string
|
||||
return '';
|
||||
}
|
||||
|
||||
// Convert string to binary
|
||||
$binaryString = '';
|
||||
|
||||
foreach (str_split($string) as $s) {
|
||||
// Return each character as an 8-bit binary string
|
||||
$s = decbin(ord($s));
|
||||
$binaryString .= str_pad($s, 8, 0, STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
// Break into 5-bit chunks, then break that into an array
|
||||
$binaryArray = self::chunk($binaryString, 5);
|
||||
|
||||
// Pad array to be divisible by 8
|
||||
while (count($binaryArray) % 8 !== 0) {
|
||||
$binaryArray[] = null;
|
||||
}
|
||||
|
||||
$base32String = '';
|
||||
|
||||
// Encode in base32
|
||||
foreach ($binaryArray as $bin) {
|
||||
$char = 32;
|
||||
|
||||
if (!is_null($bin)) {
|
||||
// Pad the binary strings
|
||||
$bin = str_pad($bin, 5, 0, STR_PAD_RIGHT);
|
||||
$char = bindec($bin);
|
||||
}
|
||||
|
||||
// Base32 character
|
||||
$base32String .= self::$encode[$char];
|
||||
}
|
||||
|
||||
return $base32String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes base32
|
||||
*
|
||||
* @param string $base32String Base32 encoded string
|
||||
* @return string Clear text string
|
||||
*/
|
||||
public static function decode($base32String)
|
||||
{
|
||||
if (strlen($base32String) == 0) {
|
||||
// Gives an empty string
|
||||
return '';
|
||||
}
|
||||
|
||||
// Only work in upper cases
|
||||
$base32String = strtoupper($base32String);
|
||||
|
||||
// Remove anything that is not base32 alphabet
|
||||
$pattern = '/[^A-Z2-7]/';
|
||||
$replacement = '';
|
||||
|
||||
$base32String = preg_replace($pattern, '', $base32String);
|
||||
|
||||
$base32Array = str_split($base32String);
|
||||
|
||||
$binaryArray = array();
|
||||
$string = '';
|
||||
|
||||
foreach ($base32Array as $str) {
|
||||
$char = self::$decode[$str];
|
||||
|
||||
// Ignore the padding character
|
||||
if ($char !== 32) {
|
||||
$char = decbin($char);
|
||||
$string .= str_pad($char, 5, 0, STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
while (strlen($string) %8 !== 0) {
|
||||
$string = substr($string, 0, strlen($string)-1);
|
||||
}
|
||||
|
||||
$binaryArray = self::chunk($string, 8);
|
||||
|
||||
$realString = '';
|
||||
|
||||
foreach ($binaryArray as $bin) {
|
||||
// Pad each value to 8 bits
|
||||
$bin = str_pad($bin, 8, 0, STR_PAD_RIGHT);
|
||||
// Convert binary strings to ascii
|
||||
$realString .= chr(bindec($bin));
|
||||
}
|
||||
|
||||
return $realString;
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2008, Jakob Heuser
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of HOTP-PHP nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Jakob Heuser ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
HOTP - PHP Based HMAC One Time Passwords
|
||||
========================================
|
||||
|
||||
**What is HOTP**:
|
||||
HOTP is a class that simplifies One Time Password systems for PHP Authentication. The HOTP/TOTP Algorithms have been around for a bit, so this is a straightforward class to meet the test vector requirements.
|
||||
|
||||
**What works with HOTP/TOTP**:
|
||||
It's been tested to the test vectors, and I've verified the time-sync hashes against the following:
|
||||
|
||||
* Android: Mobile-OTP
|
||||
* iPhone: OATH Token
|
||||
|
||||
**Why would I use this**:
|
||||
Who wouldn't love a simple drop-in class for HMAC Based One Time Passwords? It's a great extra layer of security (creating two-factor auth) and it's pretty darn zippy.
|
||||
|
||||
**Okay you sold me. Give me some docs**:
|
||||
|
||||
* $result = HOTP::generateByCounter($key, $counter); // event based
|
||||
* $result = HOTP::generateByTime($key, $window); // time based within a "window" of time
|
||||
* $result = HOTP::generateByTimeWindow($key, $window, $min, $max); // same as generateByTime, but for $min windows before and $max windows after
|
||||
|
||||
with $result, you can do all sorts of neat things...
|
||||
|
||||
* $result->toString();
|
||||
* $result->toHex();
|
||||
* $result->doDec();
|
||||
* $result->toHotp($length); // how many digits in your OTP?
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
HOTP Example File
|
||||
*/
|
||||
require_once 'hotp.php';
|
||||
|
||||
$key = '12345678901234567890';
|
||||
|
||||
$table = array(
|
||||
'HOTP' => array(
|
||||
0 => array(
|
||||
'HMAC' => 'cc93cf18508d94934c64b65d8ba7667fb7cde4b0',
|
||||
'hex' => '4c93cf18',
|
||||
'dec' => '1284755224',
|
||||
'hotp' => '755224',
|
||||
),
|
||||
1 => array(
|
||||
'HMAC' => '75a48a19d4cbe100644e8ac1397eea747a2d33ab',
|
||||
'hex' => '41397eea',
|
||||
'dec' => '1094287082',
|
||||
'hotp' => '287082',
|
||||
),
|
||||
2 => array(
|
||||
'HMAC' => '0bacb7fa082fef30782211938bc1c5e70416ff44',
|
||||
'hex' => '82fef30',
|
||||
'dec' => '137359152',
|
||||
'hotp' => '359152',
|
||||
),
|
||||
3 => array(
|
||||
'HMAC' => '66c28227d03a2d5529262ff016a1e6ef76557ece',
|
||||
'hex' => '66ef7655',
|
||||
'dec' => '1726969429',
|
||||
'hotp' => '969429',
|
||||
),
|
||||
4 => array(
|
||||
'HMAC' => 'a904c900a64b35909874b33e61c5938a8e15ed1c',
|
||||
'hex' => '61c5938a',
|
||||
'dec' => '1640338314',
|
||||
'hotp' => '338314',
|
||||
),
|
||||
5 => array(
|
||||
'HMAC' => 'a37e783d7b7233c083d4f62926c7a25f238d0316',
|
||||
'hex' => '33c083d4',
|
||||
'dec' => '868254676',
|
||||
'hotp' => '254676',
|
||||
),
|
||||
6 => array(
|
||||
'HMAC' => 'bc9cd28561042c83f219324d3c607256c03272ae',
|
||||
'hex' => '7256c032',
|
||||
'dec' => '1918287922',
|
||||
'hotp' => '287922',
|
||||
),
|
||||
7 => array(
|
||||
'HMAC' => 'a4fb960c0bc06e1eabb804e5b397cdc4b45596fa',
|
||||
'hex' => '4e5b397',
|
||||
'dec' => '82162583',
|
||||
'hotp' => '162583',
|
||||
),
|
||||
8 => array(
|
||||
'HMAC' => '1b3c89f65e6c9e883012052823443f048b4332db',
|
||||
'hex' => '2823443f',
|
||||
'dec' => '673399871',
|
||||
'hotp' => '399871',
|
||||
),
|
||||
9 => array(
|
||||
'HMAC' => '1637409809a679dc698207310c8c7fc07290d9e5',
|
||||
'hex' => '2679dc69',
|
||||
'dec' => '645520489',
|
||||
'hotp' => '520489',
|
||||
),
|
||||
),
|
||||
'TOTP' => array(
|
||||
'59' => array(
|
||||
'totp' => '94287082',
|
||||
),
|
||||
'1111111109' => array(
|
||||
'totp' => '07081804',
|
||||
),
|
||||
'1111111111' => array(
|
||||
'totp' => '14050471',
|
||||
),
|
||||
'1234567890' => array(
|
||||
'totp' => '89005924',
|
||||
),
|
||||
'2000000000' => array(
|
||||
'totp' => '69279037',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
echo <<<DOCBLOCK
|
||||
<!DOCTYPE><html><head></head><body><pre>
|
||||
http://www.ietf.org/rfc/rfc4226.txt
|
||||
http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
|
||||
|
||||
TEST VECTOR VERIFICATION
|
||||
|
||||
HOTP Tests:
|
||||
|
||||
DOCBLOCK;
|
||||
|
||||
echo "Count Method Value Pass/Fail\n";
|
||||
echo "----------------------------------------------------------------------\n";
|
||||
|
||||
// loop over all HOTP table results, and calculate the matching value
|
||||
foreach ($table['HOTP'] as $seed => $results) {
|
||||
$hotp = HOTP::generateByCounter($key, $seed);
|
||||
$first = true;
|
||||
foreach ($results as $type => $calc) {
|
||||
if ($first) {
|
||||
echo str_pad($seed, 4, ' ', STR_PAD_LEFT);
|
||||
$first = false;
|
||||
}
|
||||
else {
|
||||
echo ' ';
|
||||
}
|
||||
echo ' ';
|
||||
echo str_pad($type, 5, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
$method = 'to'.(ucfirst(str_replace('HMAC', 'string', $type)));
|
||||
echo str_pad(($calc == $hotp->$method(6)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo <<<DOCBLOCK
|
||||
|
||||
TOTP Tests:
|
||||
|
||||
DOCBLOCK;
|
||||
|
||||
echo "Time (sec) Value Pass/Fail\n";
|
||||
echo "----------------------------------------------------------------------\n";
|
||||
|
||||
// now echo over the TOTP table
|
||||
foreach ($table['TOTP'] as $seed => $results) {
|
||||
$totp = HOTP::generateByTime($key, 30, $seed);
|
||||
$first = true;
|
||||
foreach ($results as $type => $calc) {
|
||||
if ($first) {
|
||||
echo str_pad($seed, 10, ' ', STR_PAD_LEFT);
|
||||
$first = false;
|
||||
}
|
||||
else {
|
||||
echo ' ';
|
||||
}
|
||||
echo ' ';
|
||||
echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
$method = 'to'.(ucfirst(str_replace('totp', 'hotp', $type)));
|
||||
echo str_pad(($calc == $totp->$method(8)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo '</pre></body></html>';
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* HOTP Class
|
||||
* Based on the work of OAuth, and the sample implementation of HMAC OTP
|
||||
* http://tools.ietf.org/html/draft-mraihi-oath-hmac-otp-04#appendix-D
|
||||
* @author Jakob Heuser (firstname)@felocity.com
|
||||
* @copyright 2011
|
||||
* @license BSD
|
||||
* @version 1.0
|
||||
*/
|
||||
class HOTP {
|
||||
/**
|
||||
* Generate a HOTP key based on a counter value (event based HOTP)
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $counter the number of attempts represented in this hashing
|
||||
* @return HOTPResult a HOTP Result which can be truncated or output
|
||||
*/
|
||||
public static function generateByCounter($key, $counter) {
|
||||
// the counter value can be more than one byte long,
|
||||
// so we need to pack it down properly.
|
||||
$cur_counter = array(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
for($i = 7; $i >= 0; $i--) {
|
||||
$cur_counter[$i] = pack ('C*', $counter);
|
||||
$counter = $counter >> 8;
|
||||
}
|
||||
|
||||
$bin_counter = implode($cur_counter);
|
||||
|
||||
// Pad to 8 chars
|
||||
if (strlen($bin_counter) < 8) {
|
||||
$bin_counter = str_repeat (chr(0), 8 - strlen ($bin_counter)) . $bin_counter;
|
||||
}
|
||||
|
||||
// HMAC
|
||||
$hash = hash_hmac('sha1', $bin_counter, $key);
|
||||
|
||||
return new HOTPResult($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HOTP key based on a timestamp and window size
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $window the size of the window a key is valid for in seconds
|
||||
* @param int $timestamp a timestamp to calculate for, defaults to time()
|
||||
* @return HOTPResult a HOTP Result which can be truncated or output
|
||||
*/
|
||||
public static function generateByTime($key, $window, $timestamp = false) {
|
||||
if (!$timestamp && $timestamp !== 0) {
|
||||
$timestamp = HOTP::getTime();
|
||||
}
|
||||
|
||||
$counter = intval($timestamp / $window);
|
||||
|
||||
return HOTP::generateByCounter($key, $counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HOTP key collection based on a timestamp and window size
|
||||
* all keys that could exist between a start and end time will be included
|
||||
* in the returned array
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $window the size of the window a key is valid for in seconds
|
||||
* @param int $min the minimum window to accept before $timestamp
|
||||
* @param int $max the maximum window to accept after $timestamp
|
||||
* @param int $timestamp a timestamp to calculate for, defaults to time()
|
||||
* @return array of HOTPResult
|
||||
*/
|
||||
public static function generateByTimeWindow($key, $window, $min = -1, $max = 1, $timestamp = false) {
|
||||
if (!$timestamp && $timestamp !== 0) {
|
||||
$timestamp = HOTP::getTime();
|
||||
}
|
||||
|
||||
$counter = intval($timestamp / $window);
|
||||
$window = range($min, $max);
|
||||
|
||||
$out = array();
|
||||
for ($i = 0; $i < count($window); $i++) {
|
||||
$shift_counter = $window[$i];
|
||||
$out[$shift_counter] = HOTP::generateByCounter($key, $counter + $shift_counter);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current time
|
||||
* Ensures we are operating in UTC for the entire framework
|
||||
* Restores the timezone on exit.
|
||||
* @return int the current time
|
||||
*/
|
||||
public static function getTime() {
|
||||
return time(); // PHP's time is always UTC
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The HOTPResult Class converts an HOTP item to various forms
|
||||
* Supported formats include hex, decimal, string, and HOTP
|
||||
* @author Jakob Heuser (firstname)@felocity.com
|
||||
*/
|
||||
class HOTPResult {
|
||||
protected $hash;
|
||||
protected $binary;
|
||||
protected $decimal;
|
||||
|
||||
/**
|
||||
* Build an HOTP Result
|
||||
* @param string $value the value to construct with
|
||||
*/
|
||||
public function __construct($value) {
|
||||
// store raw
|
||||
$this->hash = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string version of the HOTP
|
||||
* @return string
|
||||
*/
|
||||
public function toString() {
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hex version of the HOTP
|
||||
* @return string
|
||||
*/
|
||||
public function toHex() {
|
||||
if( !$this->hex )
|
||||
{
|
||||
$this->hex = dechex($this->toDec());
|
||||
}
|
||||
return $this->hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decimal version of the HOTP
|
||||
* @return int
|
||||
*/
|
||||
public function toDec() {
|
||||
if( !$this->decimal )
|
||||
{
|
||||
// store calculate decimal
|
||||
$hmac_result = array();
|
||||
|
||||
// Convert to decimal
|
||||
foreach(str_split($this->hash,2) as $hex)
|
||||
{
|
||||
$hmac_result[] = hexdec($hex);
|
||||
}
|
||||
|
||||
$offset = $hmac_result[19] & 0xf;
|
||||
|
||||
$this->decimal = (
|
||||
(($hmac_result[$offset+0] & 0x7f) << 24 ) |
|
||||
(($hmac_result[$offset+1] & 0xff) << 16 ) |
|
||||
(($hmac_result[$offset+2] & 0xff) << 8 ) |
|
||||
($hmac_result[$offset+3] & 0xff)
|
||||
);
|
||||
}
|
||||
return $this->decimal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the truncated decimal form of the HOTP
|
||||
* @param int $length the length of the HOTP to return
|
||||
* @return string
|
||||
*/
|
||||
public function toHOTP($length) {
|
||||
$str = str_pad($this->toDec(), $length, "0", STR_PAD_LEFT);
|
||||
$str = substr($str, (-1 * $length));
|
||||
return $str;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+1034
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user