diff options
author | tailor <cygnus@janrain.com> | 2005-12-28 21:52:09 +0000 |
---|---|---|
committer | tailor <cygnus@janrain.com> | 2005-12-28 21:52:09 +0000 |
commit | 3319724398a82a37f785d6b8ba1783a630a08cb2 (patch) | |
tree | 342c9343fa09ed6e04f6e39b14319037e0e5ebf5 | |
parent | 3594ce31eab937a9745c93e45ec341b3e7bc27d0 (diff) | |
download | php-openid-3319724398a82a37f785d6b8ba1783a630a08cb2.zip php-openid-3319724398a82a37f785d6b8ba1783a630a08cb2.tar.gz php-openid-3319724398a82a37f785d6b8ba1783a630a08cb2.tar.bz2 |
[project @ Ported CryptUtils functions and added some tests for CryptUtils.]
-rw-r--r-- | Net/OpenID/CryptUtil.php | 130 | ||||
-rw-r--r-- | Tests/Net/OpenID/CryptUtil.php | 81 |
2 files changed, 211 insertions, 0 deletions
diff --git a/Net/OpenID/CryptUtil.php b/Net/OpenID/CryptUtil.php index f26ca72..9214cd9 100644 --- a/Net/OpenID/CryptUtil.php +++ b/Net/OpenID/CryptUtil.php @@ -8,6 +8,10 @@ if (!defined('Net_OpenID_RAND_SOURCE')) { define('Net_OpenID_RAND_SOURCE', '/dev/urandom'); } +require('HMACSHA1.php'); + +$Net_OpenID_CryptUtil_duplicate_cache = array(); + /** * Cryptographic utility functions */ @@ -45,6 +49,132 @@ class Net_OpenID_CryptUtil { } return $bytes; } + + /** + * Computes the SHA1 hash. + * + * @param string $str The input string. + * @static + * @return string The resulting SHA1 hash. + */ + function sha1($str) { + return sha1($str, true); + } + + /** + * Computes an HMAC-SHA1 digest. + */ + function hmacSha1($key, $text) { + return Net_OpenID_HMACSHA1($key, $text); + } + + function fromBase64($str) { + return base64_decode($str); + } + + function toBase64($str) { + return base64_encode($str); + } + + function longToBinary($long) { + return pack("L", $long); + } + + function binaryToLong($str) { + return unpack($str, "L"); + } + + function base64ToLong($str) { + return Net_OpenID_CryptUtil::binaryToLong(Net_OpenID_CryptUtil::fromBase64($str)); + } + + function longToBase64($long) { + return Net_OpenID_CryptUtil::toBase64(Net_OpenID_CryptUtil::longToBinary($long)); + } + + function strxor($x, $y) { + if (strlen($x) != strlen($y)) { + return null; + } + + $str = ""; + for ($i = 0; $i < strlen($x); $i++) { + $str .= chr(ord($x[$i]) ^ ord($y[$i])); + } + + return $str; + } + + function reversed($list) { + if (is_string($list)) { + return strrev($list); + } else if (is_array($list)) { + return array_reverse($list); + } else { + return null; + } + } + + function randrange($start, $stop = null, $step = 1) { + + global $Net_OpenID_CryptUtil_duplicate_cache; + + if ($stop == null) { + $stop = $start; + $start = 0; + } + + $r = ($stop - $start); + + if (array_key_exists($r, $Net_OpenID_CryptUtil_duplicate_cache)) { + list($duplicate, $nbytes) = $Net_OpenID_CryptUtil_duplicate_cache[$r]; + } else { + $rbytes = Net_OpenID_CryptUtil::longToBinary($r); + if ($rbytes[0] == '\x00') { + $nbytes = strlen($rbytes) - 1; + } else { + $nbytes = strlen($rbytes); + } + + $mxrand = (pow(256, $nbytes)); + + // If we get a number less than this, then it is in the + // duplicated range. + $duplicate = $mxrand % $r; + + if (count($Net_OpenID_CryptUtil_duplicate_cache) > 10) { + $Net_OpenID_CryptUtil_duplicate_cache = array(); + } + + $Net_OpenID_CryptUtil_duplicate_cache[$r] = array($duplicate, $nbytes); + } + + while (1) { + $bytes = '\x00' + Net_OpenID_CryptUtil::getBytes($nbytes); + $n = Net_OpenID_CryptUtil::binaryToLong($bytes); + // Keep looping if this value is in the low duplicated range + if ($n >= $duplicate) { + break; + } + } + return $start + ($n % $r) * $step; + } + + /** + * Produce a string of length random bytes, chosen from chrs. + */ + function randomString($length, $chrs = null) { + if ($chrs == null) { + return getBytes($length); + } else { + $n = strlen($chrs); + $str = ""; + for ($i = 0; $i < $length; $i++) { + $str .= $chrs[Net_OpenID_CryptUtil::randrange($n)]; + } + return $str; + } + } } ?>
\ No newline at end of file diff --git a/Tests/Net/OpenID/CryptUtil.php b/Tests/Net/OpenID/CryptUtil.php index ee1cfe5..af4bd69 100644 --- a/Tests/Net/OpenID/CryptUtil.php +++ b/Tests/Net/OpenID/CryptUtil.php @@ -23,6 +23,87 @@ class Tests_Net_OpenID_CryptUtil extends PHPUnit_TestCase { $this->assertFalse($data == $last); } } + + function test_cryptrand() { + return; + // It's possible, but HIGHLY unlikely that a correct + // implementation will fail by returning the same number twice + + $s = Net_OpenID_CryptUtil::getBytes(32); + $t = Net_OpenID_CryptUtil::getBytes(32); + $this->assertEquals(strlen($s), 32); + $this->assertEquals(strlen($t), 32); + $this->assertFalse($s == $t); + + $a = Net_OpenID_CryptUtil::randrange(pow(2, 128)); + $b = Net_OpenID_CryptUtil::randrange(pow(2, 128)); + // assert(is_long($a)); + // assert(is_long($b)); + // assert($b != $a); + + // Make sure that we can generate random numbers that are + // larger than platform int size + // Net_OpenID_CryptUtil::randrange(INT_MAX + 1); + } + + function test_strxor() { + $NUL = "\x00"; + + $cases = array( + array($NUL, $NUL, $NUL), + array("\x01", $NUL, "\x01"), + array("a", "a", $NUL), + array("a", $NUL, "a"), + array("abc", str_repeat($NUL, 3), "abc"), + array(str_repeat("x", 10), str_repeat($NUL, 10), str_repeat("x", 10)), + array("\x01", "\x02", "\x03"), + array("\xf0", "\x0f", "\xff"), + array("\xff", "\x0f", "\xf0"), + ); + + while (list($index, $values) = each($cases)) { + list($aa, $bb, $expected) = $values; + $actual = Net_OpenID_CryptUtil::strxor($aa, $bb); + $this->assertEquals($actual, $expected); + } + + $exc_cases = array( + array('', 'a'), + array('foo', 'ba'), + array(str_repeat($NUL, 3), str_repeat($NUL, 4)), + array(implode('', array_map('chr', range(0, 255))), + implode('', array_map('chr', range(0, 127)))) + ); + + while(list($index, $values) = each($exc_cases)) { + list($aa, $bb) = $values; + $unexpected = Net_OpenID_CryptUtil::strxor($aa, $bb); + $this->assertNull($unexpected); + } + } + + function test_reversed() { + $cases = array( + array('', ''), + array('a', 'a'), + array('ab', 'ba'), + array('abc', 'cba'), + array('abcdefg', 'gfedcba'), + array(array(), array()), + array(array(1), array(1)), + array(array(1,2), array(2,1)), + array(array(1,2,3), array(3,2,1)), + array(range(0, 999), array_reverse(range(0, 999))) + ); + + while (list($index, $values) = each($cases)) { + list($case, $expected) = $values; + $actual = Net_OpenID_CryptUtil::reversed($case); + $this->assertEquals($actual, $expected); + $twice = Net_OpenID_CryptUtil::reversed($actual); + $this->assertEquals($twice, $case); + } + } } ?>
\ No newline at end of file |