key * @param string $kid_id key_id to use * @param int $now, default 0 for current time * @param string $alg, default "sha1" * * @return the new string if ok, throw Exception if bad input */ function securestring_create($str, $key_array, $kid, $now=0, $alg="sha1") { if ($now <= 0) { $now = time(); } if (strlen($str) == 0 || strlen($kid) == 0 || strlen($key_array[$kid]) == 0){ // this should truly never happen throw new Exception("Invalid data or key data"); } // TBD -- add VERSION metadata // TBD -- add algorithm metadata // note: we are also hashing _all_ of the meta data $payload = $str . "&_created=" . $now . "&_kid=" . $kid . "&_mac="; // make the HMAC $hmac = hash_hmac($alg, $payload, $key_array[$kid], true); $hmac = securestring_b64_encode($hmac); return $payload . $hmac; } /** * Validate the HMAC on a 'secure string' * * @param string str the input string * @param array key_array, key database * @param string alg the hmac algorithm * @return boolean true if validated, untampered, false otherwise */ function securestring_validate($str, $key_array, $alg="sha1") { $mac_marker = "&_mac="; $kid_marker = "&_kid="; // NOTE: that's strRpos, since we expect it to be at the end // we don't want to bump into the marker in the user data $pos = strrpos($str, $mac_marker); if ($pos === false) { return false; } $pos += strlen($mac_marker); $payload = substr($str, 0, $pos); $given_mac = substr($str, $pos); // Now find key id in payload // there is probably a better way of doing this $kstart = strrpos($payload, $kid_marker); if ($kstart === false) { return false; } $kstart += strlen($kid_marker); $kend = strrpos($payload, '&', $kstart); if ($kend === false) { return false; } $kid = substr($payload, $kstart, $kend-$kstart); // recompute hmac, with raw binary output $computed = hash_hmac($alg, $payload, $key_array[$kid], true); $computed = securestring_b64_encode($computed); // match or die if ($computed != $given_mac) { return false; } return true; } ?>