From f1b824b5c0be76a818f44690294790d00fa9d066 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 30 May 2013 16:49:58 +0200 Subject: added HMAC support to PassHash class FS#2794 --- inc/PassHash.class.php | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'inc') 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; + } } -- cgit v1.2.3 From 3c124064ad6f670d52c3678335caa57892408362 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 30 May 2013 16:56:34 +0200 Subject: use HMAC in media_token FS#2794 --- inc/media.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'inc') 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 + * * @param string $id id of the image * @param int $w resize/crop width * @param int $h resize/crop height - * - * @author Christopher Smith + * @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 ''; -- cgit v1.2.3 From cdcd66dfc2bcf16e481d10bfa2d3ff1b4d433f99 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:22:45 +0200 Subject: use hmac for external ressource hash FS#2794 --- inc/common.php | 2 +- inc/fetch.functions.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'inc') diff --git a/inc/common.php b/inc/common.php index 4d939ac77..e096d8b30 100644 --- a/inc/common.php +++ b/inc/common.php @@ -470,7 +470,7 @@ function ml($id = '', $more = '', $direct = true, $sep = '&', $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 -- cgit v1.2.3 From a132f948f22ae344760ee3da82f9f92cf0f18b7b Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:25:43 +0200 Subject: use HMAC for CSRF security tokens FS#2794 --- inc/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc') diff --git a/inc/common.php b/inc/common.php index e096d8b30..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()); } /** -- cgit v1.2.3 From 8fcfc7abfd65ccd920753bee341c6bfdebcecd99 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:29:08 +0200 Subject: use HMAC in password reset token FS#2794 --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc') diff --git a/inc/auth.php b/inc/auth.php index af9f35b38..dac67bcb7 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 = PassHash::hmac('md5', $user, auth_cookiesalt()); //secret but user based $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 183a7b8845875e4a6b67e466cfff9f5163da3f17 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 14:43:31 +0200 Subject: make password reset token completely random No need for HMAC here because there's no length attack vector here. We only care for the existance of the file and each reset request is completely (random) independent from each other. --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc') diff --git a/inc/auth.php b/inc/auth.php index dac67bcb7..1f8489f03 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -993,7 +993,7 @@ function act_resendpwd() { } // generate auth token - $token = PassHash::hmac('md5', $user, auth_cookiesalt()); //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, '&'); -- cgit v1.2.3