summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_test/tests/inc/PassHash.test.php22
-rw-r--r--inc/PassHash.class.php47
-rw-r--r--inc/auth.php2
-rw-r--r--inc/common.php4
-rw-r--r--inc/fetch.functions.php2
-rw-r--r--inc/media.php9
6 files changed, 78 insertions, 8 deletions
diff --git a/_test/tests/inc/PassHash.test.php b/_test/tests/inc/PassHash.test.php
new file mode 100644
index 000000000..b6cb07090
--- /dev/null
+++ b/_test/tests/inc/PassHash.test.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * Class PassHash_test
+ *
+ * most tests are in auth_password.test.php
+ */
+class PassHash_test extends PHPUnit_Framework_TestCase {
+
+ function test_hmac(){
+ // known hashes taken from https://code.google.com/p/yii/issues/detail?id=1942
+ $this->assertEquals('df08aef118f36b32e29d2f47cda649b6', PassHash::hmac('md5','data','secret'));
+ $this->assertEquals('9818e3306ba5ac267b5f2679fe4abd37e6cd7b54', PassHash::hmac('sha1','data','secret'));
+
+ // known hashes from https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
+ $this->assertEquals('74e6f7298a9c2d168935f58c001bad88', PassHash::hmac('md5','',''));
+ $this->assertEquals('fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', PassHash::hmac('sha1','',''));
+ $this->assertEquals('80070713463e7749b90c2dc24911e275', PassHash::hmac('md5','The quick brown fox jumps over the lazy dog','key'));
+ $this->assertEquals('de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', PassHash::hmac('sha1','The quick brown fox jumps over the lazy dog','key'));
+
+ }
+} \ No newline at end of file
diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php
index 080fb4778..61bd74939 100644
--- a/inc/PassHash.class.php
+++ b/inc/PassHash.class.php
@@ -494,4 +494,51 @@ class PassHash {
$this->init_salt($salt, 8, false);
return ':B:'.$salt.':'.md5($salt.'-'.md5($clear));
}
+
+ /**
+ * Wraps around native hash_hmac() or reimplents it
+ *
+ * This is not directly used as password hashing method, and thus isn't callable via the
+ * verify_hash() method. It should be used to create signatures and might be used in other
+ * password hashing methods.
+ *
+ * @see hash_hmac()
+ * @author KC Cloyd
+ * @link http://www.php.net/manual/en/function.hash-hmac.php#93440
+ *
+ * @param string $algo Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4",
+ * etc..) See hash_algos() for a list of supported algorithms.
+ * @param string $data Message to be hashed.
+ * @param string $key Shared secret key used for generating the HMAC variant of the message digest.
+ * @param bool $raw_output When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
+ *
+ * @return string
+ */
+ public static function hmac($algo, $data, $key, $raw_output = false) {
+ // use native function if available and not in unit test
+ if(function_exists('hash_hmac') && !defined('SIMPLE_TEST')){
+ return hash_hmac($algo, $data, $key, $raw_output);
+ }
+
+ $algo = strtolower($algo);
+ $pack = 'H' . strlen($algo('test'));
+ $size = 64;
+ $opad = str_repeat(chr(0x5C), $size);
+ $ipad = str_repeat(chr(0x36), $size);
+
+ if(strlen($key) > $size) {
+ $key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
+ } else {
+ $key = str_pad($key, $size, chr(0x00));
+ }
+
+ for($i = 0; $i < strlen($key) - 1; $i++) {
+ $opad[$i] = $opad[$i] ^ $key[$i];
+ $ipad[$i] = $ipad[$i] ^ $key[$i];
+ }
+
+ $output = $algo($opad . pack($pack, $algo($ipad . $data)));
+
+ return ($raw_output) ? pack($pack, $output) : $output;
+ }
}
diff --git a/inc/auth.php b/inc/auth.php
index af9f35b38..1f8489f03 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -993,7 +993,7 @@ function act_resendpwd() {
}
// generate auth token
- $token = md5(auth_cookiesalt().$user); //secret but user based
+ $token = md5(uniqid(mt_rand(), true)); // random secret
$tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth';
$url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&');
diff --git a/inc/common.php b/inc/common.php
index 4d939ac77..55c5b5ac4 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -56,7 +56,7 @@ function stripctl($string) {
* @return string
*/
function getSecurityToken() {
- return md5(auth_cookiesalt().session_id().$_SERVER['REMOTE_USER']);
+ return PassHash::hmac('md5', session_id().$_SERVER['REMOTE_USER'], auth_cookiesalt());
}
/**
@@ -470,7 +470,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&amp;', $abs = false)
if(preg_match('#^(https?|ftp)://#i', $id)) {
$xlink .= 'lib/exe/fetch.php';
// add hash:
- $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id), 0, 6);
+ $xlink .= '?hash='.substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6);
if($more) {
$xlink .= $sep.$more;
$xlink .= $sep.'media='.rawurlencode($id);
diff --git a/inc/fetch.functions.php b/inc/fetch.functions.php
index 5801e96fa..ea524a37a 100644
--- a/inc/fetch.functions.php
+++ b/inc/fetch.functions.php
@@ -99,7 +99,7 @@ function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) {
//media to local file
if(preg_match('#^(https?)://#i', $media)) {
//check hash
- if(substr(md5(auth_cookiesalt().$media), 0, 6) !== $INPUT->str('hash')) {
+ if(substr(PassHash::hmac('md5', $media, auth_cookiesalt()), 0, 6) !== $INPUT->str('hash')) {
return array(412, 'Precondition Failed');
}
//handle external images
diff --git a/inc/media.php b/inc/media.php
index e29a47631..18148a446 100644
--- a/inc/media.php
+++ b/inc/media.php
@@ -1879,20 +1879,21 @@ function media_crop_image($file, $ext, $w, $h=0){
* cropped images have been internally generated - and prevent external
* DDOS attacks via fetch
*
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ *
* @param string $id id of the image
* @param int $w resize/crop width
* @param int $h resize/crop height
- *
- * @author Christopher Smith <chris@jalakai.co.uk>
+ * @return string
*/
function media_get_token($id,$w,$h){
// token is only required for modified images
if ($w || $h) {
- $token = auth_cookiesalt().$id;
+ $token = $id;
if ($w) $token .= '.'.$w;
if ($h) $token .= '.'.$h;
- return substr(md5($token),0,6);
+ return substr(PassHash::hmac('md5', $token, auth_cookiesalt()),0,6);
}
return '';