/hphp/runtime/ext/ext_hash.cpp
C++ | 407 lines | 321 code | 52 blank | 34 comment | 34 complexity | 1d11573fab91d7d6755060ea576a6e9e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
- /*
- +----------------------------------------------------------------------+
- | HipHop for PHP |
- +----------------------------------------------------------------------+
- | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
- | Copyright (c) 1997-2010 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- */
- #include "hphp/runtime/ext/ext_hash.h"
- #include "hphp/runtime/ext/ext_file.h"
- #include "hphp/runtime/ext/hash/hash_md.h"
- #include "hphp/runtime/ext/hash/hash_sha.h"
- #include "hphp/runtime/ext/hash/hash_ripemd.h"
- #include "hphp/runtime/ext/hash/hash_whirlpool.h"
- #include "hphp/runtime/ext/hash/hash_tiger.h"
- #include "hphp/runtime/ext/hash/hash_snefru.h"
- #include "hphp/runtime/ext/hash/hash_gost.h"
- #include "hphp/runtime/ext/hash/hash_adler32.h"
- #include "hphp/runtime/ext/hash/hash_crc32.h"
- #include "hphp/runtime/ext/hash/hash_haval.h"
- #include "hphp/runtime/ext/hash/hash_fnv1.h"
- #include "hphp/runtime/ext/hash/hash_furc.h"
- #include "hphp/runtime/ext/hash/hash_murmur.h"
- #if defined(HPHP_OSS)
- #define furc_hash furc_hash_internal
- #else
- #include "memcache/ch/hash.h"
- #endif
- namespace HPHP {
- IMPLEMENT_DEFAULT_EXTENSION(hash);
- ///////////////////////////////////////////////////////////////////////////////
- // hash engines
- static HashEngineMap HashEngines;
- class HashEngineMapInitializer {
- public:
- HashEngineMapInitializer() {
- HashEngines["md2"] = HashEnginePtr(new hash_md2());
- HashEngines["md4"] = HashEnginePtr(new hash_md4());
- HashEngines["md5"] = HashEnginePtr(new hash_md5());
- HashEngines["sha1"] = HashEnginePtr(new hash_sha1());
- HashEngines["sha224"] = HashEnginePtr(new hash_sha224());
- HashEngines["sha256"] = HashEnginePtr(new hash_sha256());
- HashEngines["sha384"] = HashEnginePtr(new hash_sha384());
- HashEngines["sha512"] = HashEnginePtr(new hash_sha512());
- HashEngines["ripemd128"] = HashEnginePtr(new hash_ripemd128());
- HashEngines["ripemd160"] = HashEnginePtr(new hash_ripemd160());
- HashEngines["ripemd256"] = HashEnginePtr(new hash_ripemd256());
- HashEngines["ripemd320"] = HashEnginePtr(new hash_ripemd320());
- HashEngines["whirlpool"] = HashEnginePtr(new hash_whirlpool());
- #ifdef FACEBOOK
- HashEngines["tiger128,3-fb"]
- = HashEnginePtr(new hash_tiger(true, 128, true));
- // Temporarily leave tiger128,3 algo inverting its hash output
- // to retain BC pending conversion of user code to correct endianness
- // sgolemon(2013-04-30)
- HashEngines["tiger128,3"] = HashEnginePtr(new hash_tiger(true, 128, true));
- #else
- HashEngines["tiger128,3"] = HashEnginePtr(new hash_tiger(true, 128));
- #endif
- HashEngines["tiger160,3"] = HashEnginePtr(new hash_tiger(true, 160));
- HashEngines["tiger192,3"] = HashEnginePtr(new hash_tiger(true, 192));
- HashEngines["tiger128,4"] = HashEnginePtr(new hash_tiger(false, 128));
- HashEngines["tiger160,4"] = HashEnginePtr(new hash_tiger(false, 160));
- HashEngines["tiger192,4"] = HashEnginePtr(new hash_tiger(false, 192));
- HashEngines["snefru"] = HashEnginePtr(new hash_snefru());
- HashEngines["gost"] = HashEnginePtr(new hash_gost());
- HashEngines["adler32"] = HashEnginePtr(new hash_adler32());
- HashEngines["crc32"] = HashEnginePtr(new hash_crc32(false));
- HashEngines["crc32b"] = HashEnginePtr(new hash_crc32(true));
- HashEngines["haval128,3"] = HashEnginePtr(new hash_haval(3,128));
- HashEngines["haval160,3"] = HashEnginePtr(new hash_haval(3,160));
- HashEngines["haval192,3"] = HashEnginePtr(new hash_haval(3,192));
- HashEngines["haval224,3"] = HashEnginePtr(new hash_haval(3,224));
- HashEngines["haval256,3"] = HashEnginePtr(new hash_haval(3,256));
- HashEngines["haval128,4"] = HashEnginePtr(new hash_haval(4,128));
- HashEngines["haval160,4"] = HashEnginePtr(new hash_haval(4,160));
- HashEngines["haval192,4"] = HashEnginePtr(new hash_haval(4,192));
- HashEngines["haval224,4"] = HashEnginePtr(new hash_haval(4,224));
- HashEngines["haval256,4"] = HashEnginePtr(new hash_haval(4,256));
- HashEngines["haval128,5"] = HashEnginePtr(new hash_haval(5,128));
- HashEngines["haval160,5"] = HashEnginePtr(new hash_haval(5,160));
- HashEngines["haval192,5"] = HashEnginePtr(new hash_haval(5,192));
- HashEngines["haval224,5"] = HashEnginePtr(new hash_haval(5,224));
- HashEngines["haval256,5"] = HashEnginePtr(new hash_haval(5,256));
- HashEngines["fnv132"] = HashEnginePtr(new hash_fnv132(false));
- HashEngines["fnv1a32"] = HashEnginePtr(new hash_fnv132(true));
- HashEngines["fnv164"] = HashEnginePtr(new hash_fnv164(false));
- HashEngines["fnv1a64"] = HashEnginePtr(new hash_fnv164(true));
- }
- };
- static HashEngineMapInitializer s_engine_initializer;
- ///////////////////////////////////////////////////////////////////////////////
- // hash context
- class HashContext : public SweepableResourceData {
- public:
- static StaticString s_class_name;
- // overriding ResourceData
- virtual CStrRef o_getClassNameHook() const { return s_class_name; }
- HashContext(HashEnginePtr ops_, void *context_, int options_)
- : ops(ops_), context(context_), options(options_), key(NULL) {
- }
- ~HashContext() {
- /* Just in case the algo has internally allocated resources */
- if (context) {
- unsigned char *dummy = (unsigned char *)malloc(ops->digest_size);
- ops->hash_final(dummy, context);
- free(dummy);
- free(context);
- }
- if (key) {
- memset(key, 0, ops->block_size);
- free(key);
- }
- }
- HashEnginePtr ops;
- void *context;
- int options;
- char *key;
- };
- StaticString HashContext::s_class_name("Hash Context");
- ///////////////////////////////////////////////////////////////////////////////
- // hash functions
- Array f_hash_algos() {
- Array ret;
- for (HashEngineMap::const_iterator iter = HashEngines.begin();
- iter != HashEngines.end(); ++iter) {
- ret.append(String(iter->first));
- }
- return ret;
- }
- static HashEnginePtr php_hash_fetch_ops(CStrRef algo) {
- HashEngineMap::const_iterator iter =
- HashEngines.find(StringUtil::ToLower(algo).data());
- if (iter == HashEngines.end()) {
- return HashEnginePtr();
- }
- return iter->second;
- }
- static Variant php_hash_do_hash(CStrRef algo, CStrRef data, bool isfilename,
- bool raw_output) {
- HashEnginePtr ops = php_hash_fetch_ops(algo);
- if (!ops) {
- raise_warning("Unknown hashing algorithm: %s", algo.data());
- return false;
- }
- Variant f;
- if (isfilename) {
- f = f_fopen(data, "rb");
- if (same(f, false)) {
- return false;
- }
- }
- void *context = malloc(ops->context_size);
- ops->hash_init(context);
- if (isfilename) {
- for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
- chunk = f_fread(f, 1024)) {
- String schunk = chunk.toString();
- ops->hash_update(context, (unsigned char *)schunk.data(), schunk.size());
- }
- } else {
- ops->hash_update(context, (unsigned char *)data.data(), data.size());
- }
- String raw = String(ops->digest_size, ReserveString);
- char *digest = raw.mutableSlice().ptr;
- ops->hash_final((unsigned char *)digest, context);
- free(context);
- raw.setSize(ops->digest_size);
- if (raw_output) {
- return raw;
- }
- return StringUtil::HexEncode(raw);
- }
- Variant f_hash(CStrRef algo, CStrRef data, bool raw_output /* = false */) {
- return php_hash_do_hash(algo, data, false, raw_output);
- }
- Variant f_hash_file(CStrRef algo, CStrRef filename,
- bool raw_output /* = false */) {
- return php_hash_do_hash(algo, filename, true, raw_output);
- }
- static char *prepare_hmac_key(HashEnginePtr ops, void *context, CStrRef key) {
- char *K = (char*)malloc(ops->block_size);
- memset(K, 0, ops->block_size);
- if (key.size() > ops->block_size) {
- /* Reduce the key first */
- ops->hash_update(context, (unsigned char *)key.data(), key.size());
- ops->hash_final((unsigned char *)K, context);
- /* Make the context ready to start over */
- ops->hash_init(context);
- } else {
- memcpy(K, key.data(), key.size());
- }
- /* XOR ipad */
- for (int i = 0; i < ops->block_size; i++) {
- K[i] ^= 0x36;
- }
- ops->hash_update(context, (unsigned char *)K, ops->block_size);
- return K;
- }
- static void finalize_hmac_key(char *K, HashEnginePtr ops, void *context,
- char *digest) {
- /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
- for (int i = 0; i < ops->block_size; i++) {
- K[i] ^= 0x6A;
- }
- /* Feed this result into the outter hash */
- ops->hash_init(context);
- ops->hash_update(context, (unsigned char *)K, ops->block_size);
- ops->hash_update(context, (unsigned char *)digest, ops->digest_size);
- ops->hash_final((unsigned char *)digest, context);
- /* Zero the key */
- memset(K, 0, ops->block_size);
- free(K);
- }
- static Variant php_hash_do_hash_hmac(CStrRef algo, CStrRef data,
- bool isfilename, CStrRef key,
- bool raw_output /* = false */) {
- HashEnginePtr ops = php_hash_fetch_ops(algo);
- if (!ops) {
- raise_warning("Unknown hashing algorithm: %s", algo.data());
- return false;
- }
- Variant f;
- if (isfilename) {
- f = f_fopen(data, "rb");
- if (same(f, false)) {
- return false;
- }
- }
- void *context = malloc(ops->context_size);
- ops->hash_init(context);
- char *K = prepare_hmac_key(ops, context, key);
- if (isfilename) {
- for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
- chunk = f_fread(f, 1024)) {
- String schunk = chunk.toString();
- ops->hash_update(context, (unsigned char *)schunk.data(), schunk.size());
- }
- } else {
- ops->hash_update(context, (unsigned char *)data.data(), data.size());
- }
- String raw = String(ops->digest_size, ReserveString);
- char *digest = raw.mutableSlice().ptr;
- ops->hash_final((unsigned char *)digest, context);
- finalize_hmac_key(K, ops, context, digest);
- free(context);
- raw.setSize(ops->digest_size);
- if (raw_output) {
- return raw;
- }
- return StringUtil::HexEncode(raw);
- }
- Variant f_hash_hmac(CStrRef algo, CStrRef data, CStrRef key,
- bool raw_output /* = false */) {
- return php_hash_do_hash_hmac(algo, data, false, key, raw_output);
- }
- Variant f_hash_hmac_file(CStrRef algo, CStrRef filename, CStrRef key,
- bool raw_output /* = false */) {
- return php_hash_do_hash_hmac(algo, filename, true, key, raw_output);
- }
- Variant f_hash_init(CStrRef algo, int options /* = 0 */,
- CStrRef key /* = null_string */) {
- HashEnginePtr ops = php_hash_fetch_ops(algo);
- if (!ops) {
- raise_warning("Unknown hashing algorithm: %s", algo.data());
- return false;
- }
- if ((options & k_HASH_HMAC) && key.empty()) {
- raise_warning("HMAC requested without a key");
- return false;
- }
- void *context = malloc(ops->context_size);
- ops->hash_init(context);
- HashContext *hash = new HashContext(ops, context, options);
- if (options & k_HASH_HMAC) {
- hash->key = prepare_hmac_key(ops, context, key);
- }
- return Object(hash);
- }
- bool f_hash_update(CObjRef context, CStrRef data) {
- HashContext *hash = context.getTyped<HashContext>();
- hash->ops->hash_update(hash->context, (unsigned char *)data.data(),
- data.size());
- return true;
- }
- bool f_hash_update_file(CObjRef init_context, CStrRef filename,
- CObjRef stream_context /* = null */) {
- Variant f = f_fopen(filename, "rb");
- if (same(f, false)) {
- return false;
- }
- HashContext *hash = init_context.getTyped<HashContext>();
- for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
- chunk = f_fread(f, 1024)) {
- String schunk = chunk.toString();
- hash->ops->hash_update(hash->context, (unsigned char *)schunk.data(),
- schunk.size());
- }
- return true;
- }
- int64_t f_hash_update_stream(CObjRef context, CObjRef handle,
- int length /* = -1 */) {
- HashContext *hash = context.getTyped<HashContext>();
- int didread = 0;
- while (length) {
- Variant chunk = f_fread(handle, length > 0 ? length : 1024);
- if (is_empty_string(chunk)) {
- return didread;
- }
- String schunk = chunk.toString();
- hash->ops->hash_update(hash->context, (unsigned char *)schunk.data(),
- schunk.size());
- didread += schunk.size();
- length -= schunk.size();
- }
- return didread;
- }
- String f_hash_final(CObjRef context, bool raw_output /* = false */) {
- HashContext *hash = context.getTyped<HashContext>();
- String raw = String(hash->ops->digest_size, ReserveString);
- char *digest = raw.mutableSlice().ptr;
- hash->ops->hash_final((unsigned char *)digest, hash->context);
- if (hash->options & k_HASH_HMAC) {
- finalize_hmac_key(hash->key, hash->ops, hash->context, digest);
- hash->key = NULL;
- }
- free(hash->context);
- hash->context = NULL;
- raw.setSize(hash->ops->digest_size);
- if (raw_output) {
- return raw;
- }
- return StringUtil::HexEncode(raw);
- }
- int64_t f_furchash_hphp_ext(CStrRef key, int len, int nPart) {
- len = std::max(std::min(len, key.size()), 0);
- return furc_hash(key.data(), len, nPart);
- }
- bool f_furchash_hphp_ext_supported() {
- return true;
- }
- int64_t f_hphp_murmurhash(CStrRef key, int len, int seed) {
- len = std::max(std::min(len, key.size()), 0);
- return murmur_hash_64A(key.data(), len, seed);
- }
- ///////////////////////////////////////////////////////////////////////////////
- }