PageRenderTime 23ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext/ext_hash.cpp

https://bitbucket.org/gnanakeethan/hiphop-php
C++ | 407 lines | 321 code | 52 blank | 34 comment | 34 complexity | 1d11573fab91d7d6755060ea576a6e9e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/ext_hash.h"
  18. #include "hphp/runtime/ext/ext_file.h"
  19. #include "hphp/runtime/ext/hash/hash_md.h"
  20. #include "hphp/runtime/ext/hash/hash_sha.h"
  21. #include "hphp/runtime/ext/hash/hash_ripemd.h"
  22. #include "hphp/runtime/ext/hash/hash_whirlpool.h"
  23. #include "hphp/runtime/ext/hash/hash_tiger.h"
  24. #include "hphp/runtime/ext/hash/hash_snefru.h"
  25. #include "hphp/runtime/ext/hash/hash_gost.h"
  26. #include "hphp/runtime/ext/hash/hash_adler32.h"
  27. #include "hphp/runtime/ext/hash/hash_crc32.h"
  28. #include "hphp/runtime/ext/hash/hash_haval.h"
  29. #include "hphp/runtime/ext/hash/hash_fnv1.h"
  30. #include "hphp/runtime/ext/hash/hash_furc.h"
  31. #include "hphp/runtime/ext/hash/hash_murmur.h"
  32. #if defined(HPHP_OSS)
  33. #define furc_hash furc_hash_internal
  34. #else
  35. #include "memcache/ch/hash.h"
  36. #endif
  37. namespace HPHP {
  38. IMPLEMENT_DEFAULT_EXTENSION(hash);
  39. ///////////////////////////////////////////////////////////////////////////////
  40. // hash engines
  41. static HashEngineMap HashEngines;
  42. class HashEngineMapInitializer {
  43. public:
  44. HashEngineMapInitializer() {
  45. HashEngines["md2"] = HashEnginePtr(new hash_md2());
  46. HashEngines["md4"] = HashEnginePtr(new hash_md4());
  47. HashEngines["md5"] = HashEnginePtr(new hash_md5());
  48. HashEngines["sha1"] = HashEnginePtr(new hash_sha1());
  49. HashEngines["sha224"] = HashEnginePtr(new hash_sha224());
  50. HashEngines["sha256"] = HashEnginePtr(new hash_sha256());
  51. HashEngines["sha384"] = HashEnginePtr(new hash_sha384());
  52. HashEngines["sha512"] = HashEnginePtr(new hash_sha512());
  53. HashEngines["ripemd128"] = HashEnginePtr(new hash_ripemd128());
  54. HashEngines["ripemd160"] = HashEnginePtr(new hash_ripemd160());
  55. HashEngines["ripemd256"] = HashEnginePtr(new hash_ripemd256());
  56. HashEngines["ripemd320"] = HashEnginePtr(new hash_ripemd320());
  57. HashEngines["whirlpool"] = HashEnginePtr(new hash_whirlpool());
  58. #ifdef FACEBOOK
  59. HashEngines["tiger128,3-fb"]
  60. = HashEnginePtr(new hash_tiger(true, 128, true));
  61. // Temporarily leave tiger128,3 algo inverting its hash output
  62. // to retain BC pending conversion of user code to correct endianness
  63. // sgolemon(2013-04-30)
  64. HashEngines["tiger128,3"] = HashEnginePtr(new hash_tiger(true, 128, true));
  65. #else
  66. HashEngines["tiger128,3"] = HashEnginePtr(new hash_tiger(true, 128));
  67. #endif
  68. HashEngines["tiger160,3"] = HashEnginePtr(new hash_tiger(true, 160));
  69. HashEngines["tiger192,3"] = HashEnginePtr(new hash_tiger(true, 192));
  70. HashEngines["tiger128,4"] = HashEnginePtr(new hash_tiger(false, 128));
  71. HashEngines["tiger160,4"] = HashEnginePtr(new hash_tiger(false, 160));
  72. HashEngines["tiger192,4"] = HashEnginePtr(new hash_tiger(false, 192));
  73. HashEngines["snefru"] = HashEnginePtr(new hash_snefru());
  74. HashEngines["gost"] = HashEnginePtr(new hash_gost());
  75. HashEngines["adler32"] = HashEnginePtr(new hash_adler32());
  76. HashEngines["crc32"] = HashEnginePtr(new hash_crc32(false));
  77. HashEngines["crc32b"] = HashEnginePtr(new hash_crc32(true));
  78. HashEngines["haval128,3"] = HashEnginePtr(new hash_haval(3,128));
  79. HashEngines["haval160,3"] = HashEnginePtr(new hash_haval(3,160));
  80. HashEngines["haval192,3"] = HashEnginePtr(new hash_haval(3,192));
  81. HashEngines["haval224,3"] = HashEnginePtr(new hash_haval(3,224));
  82. HashEngines["haval256,3"] = HashEnginePtr(new hash_haval(3,256));
  83. HashEngines["haval128,4"] = HashEnginePtr(new hash_haval(4,128));
  84. HashEngines["haval160,4"] = HashEnginePtr(new hash_haval(4,160));
  85. HashEngines["haval192,4"] = HashEnginePtr(new hash_haval(4,192));
  86. HashEngines["haval224,4"] = HashEnginePtr(new hash_haval(4,224));
  87. HashEngines["haval256,4"] = HashEnginePtr(new hash_haval(4,256));
  88. HashEngines["haval128,5"] = HashEnginePtr(new hash_haval(5,128));
  89. HashEngines["haval160,5"] = HashEnginePtr(new hash_haval(5,160));
  90. HashEngines["haval192,5"] = HashEnginePtr(new hash_haval(5,192));
  91. HashEngines["haval224,5"] = HashEnginePtr(new hash_haval(5,224));
  92. HashEngines["haval256,5"] = HashEnginePtr(new hash_haval(5,256));
  93. HashEngines["fnv132"] = HashEnginePtr(new hash_fnv132(false));
  94. HashEngines["fnv1a32"] = HashEnginePtr(new hash_fnv132(true));
  95. HashEngines["fnv164"] = HashEnginePtr(new hash_fnv164(false));
  96. HashEngines["fnv1a64"] = HashEnginePtr(new hash_fnv164(true));
  97. }
  98. };
  99. static HashEngineMapInitializer s_engine_initializer;
  100. ///////////////////////////////////////////////////////////////////////////////
  101. // hash context
  102. class HashContext : public SweepableResourceData {
  103. public:
  104. static StaticString s_class_name;
  105. // overriding ResourceData
  106. virtual CStrRef o_getClassNameHook() const { return s_class_name; }
  107. HashContext(HashEnginePtr ops_, void *context_, int options_)
  108. : ops(ops_), context(context_), options(options_), key(NULL) {
  109. }
  110. ~HashContext() {
  111. /* Just in case the algo has internally allocated resources */
  112. if (context) {
  113. unsigned char *dummy = (unsigned char *)malloc(ops->digest_size);
  114. ops->hash_final(dummy, context);
  115. free(dummy);
  116. free(context);
  117. }
  118. if (key) {
  119. memset(key, 0, ops->block_size);
  120. free(key);
  121. }
  122. }
  123. HashEnginePtr ops;
  124. void *context;
  125. int options;
  126. char *key;
  127. };
  128. StaticString HashContext::s_class_name("Hash Context");
  129. ///////////////////////////////////////////////////////////////////////////////
  130. // hash functions
  131. Array f_hash_algos() {
  132. Array ret;
  133. for (HashEngineMap::const_iterator iter = HashEngines.begin();
  134. iter != HashEngines.end(); ++iter) {
  135. ret.append(String(iter->first));
  136. }
  137. return ret;
  138. }
  139. static HashEnginePtr php_hash_fetch_ops(CStrRef algo) {
  140. HashEngineMap::const_iterator iter =
  141. HashEngines.find(StringUtil::ToLower(algo).data());
  142. if (iter == HashEngines.end()) {
  143. return HashEnginePtr();
  144. }
  145. return iter->second;
  146. }
  147. static Variant php_hash_do_hash(CStrRef algo, CStrRef data, bool isfilename,
  148. bool raw_output) {
  149. HashEnginePtr ops = php_hash_fetch_ops(algo);
  150. if (!ops) {
  151. raise_warning("Unknown hashing algorithm: %s", algo.data());
  152. return false;
  153. }
  154. Variant f;
  155. if (isfilename) {
  156. f = f_fopen(data, "rb");
  157. if (same(f, false)) {
  158. return false;
  159. }
  160. }
  161. void *context = malloc(ops->context_size);
  162. ops->hash_init(context);
  163. if (isfilename) {
  164. for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
  165. chunk = f_fread(f, 1024)) {
  166. String schunk = chunk.toString();
  167. ops->hash_update(context, (unsigned char *)schunk.data(), schunk.size());
  168. }
  169. } else {
  170. ops->hash_update(context, (unsigned char *)data.data(), data.size());
  171. }
  172. String raw = String(ops->digest_size, ReserveString);
  173. char *digest = raw.mutableSlice().ptr;
  174. ops->hash_final((unsigned char *)digest, context);
  175. free(context);
  176. raw.setSize(ops->digest_size);
  177. if (raw_output) {
  178. return raw;
  179. }
  180. return StringUtil::HexEncode(raw);
  181. }
  182. Variant f_hash(CStrRef algo, CStrRef data, bool raw_output /* = false */) {
  183. return php_hash_do_hash(algo, data, false, raw_output);
  184. }
  185. Variant f_hash_file(CStrRef algo, CStrRef filename,
  186. bool raw_output /* = false */) {
  187. return php_hash_do_hash(algo, filename, true, raw_output);
  188. }
  189. static char *prepare_hmac_key(HashEnginePtr ops, void *context, CStrRef key) {
  190. char *K = (char*)malloc(ops->block_size);
  191. memset(K, 0, ops->block_size);
  192. if (key.size() > ops->block_size) {
  193. /* Reduce the key first */
  194. ops->hash_update(context, (unsigned char *)key.data(), key.size());
  195. ops->hash_final((unsigned char *)K, context);
  196. /* Make the context ready to start over */
  197. ops->hash_init(context);
  198. } else {
  199. memcpy(K, key.data(), key.size());
  200. }
  201. /* XOR ipad */
  202. for (int i = 0; i < ops->block_size; i++) {
  203. K[i] ^= 0x36;
  204. }
  205. ops->hash_update(context, (unsigned char *)K, ops->block_size);
  206. return K;
  207. }
  208. static void finalize_hmac_key(char *K, HashEnginePtr ops, void *context,
  209. char *digest) {
  210. /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
  211. for (int i = 0; i < ops->block_size; i++) {
  212. K[i] ^= 0x6A;
  213. }
  214. /* Feed this result into the outter hash */
  215. ops->hash_init(context);
  216. ops->hash_update(context, (unsigned char *)K, ops->block_size);
  217. ops->hash_update(context, (unsigned char *)digest, ops->digest_size);
  218. ops->hash_final((unsigned char *)digest, context);
  219. /* Zero the key */
  220. memset(K, 0, ops->block_size);
  221. free(K);
  222. }
  223. static Variant php_hash_do_hash_hmac(CStrRef algo, CStrRef data,
  224. bool isfilename, CStrRef key,
  225. bool raw_output /* = false */) {
  226. HashEnginePtr ops = php_hash_fetch_ops(algo);
  227. if (!ops) {
  228. raise_warning("Unknown hashing algorithm: %s", algo.data());
  229. return false;
  230. }
  231. Variant f;
  232. if (isfilename) {
  233. f = f_fopen(data, "rb");
  234. if (same(f, false)) {
  235. return false;
  236. }
  237. }
  238. void *context = malloc(ops->context_size);
  239. ops->hash_init(context);
  240. char *K = prepare_hmac_key(ops, context, key);
  241. if (isfilename) {
  242. for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
  243. chunk = f_fread(f, 1024)) {
  244. String schunk = chunk.toString();
  245. ops->hash_update(context, (unsigned char *)schunk.data(), schunk.size());
  246. }
  247. } else {
  248. ops->hash_update(context, (unsigned char *)data.data(), data.size());
  249. }
  250. String raw = String(ops->digest_size, ReserveString);
  251. char *digest = raw.mutableSlice().ptr;
  252. ops->hash_final((unsigned char *)digest, context);
  253. finalize_hmac_key(K, ops, context, digest);
  254. free(context);
  255. raw.setSize(ops->digest_size);
  256. if (raw_output) {
  257. return raw;
  258. }
  259. return StringUtil::HexEncode(raw);
  260. }
  261. Variant f_hash_hmac(CStrRef algo, CStrRef data, CStrRef key,
  262. bool raw_output /* = false */) {
  263. return php_hash_do_hash_hmac(algo, data, false, key, raw_output);
  264. }
  265. Variant f_hash_hmac_file(CStrRef algo, CStrRef filename, CStrRef key,
  266. bool raw_output /* = false */) {
  267. return php_hash_do_hash_hmac(algo, filename, true, key, raw_output);
  268. }
  269. Variant f_hash_init(CStrRef algo, int options /* = 0 */,
  270. CStrRef key /* = null_string */) {
  271. HashEnginePtr ops = php_hash_fetch_ops(algo);
  272. if (!ops) {
  273. raise_warning("Unknown hashing algorithm: %s", algo.data());
  274. return false;
  275. }
  276. if ((options & k_HASH_HMAC) && key.empty()) {
  277. raise_warning("HMAC requested without a key");
  278. return false;
  279. }
  280. void *context = malloc(ops->context_size);
  281. ops->hash_init(context);
  282. HashContext *hash = new HashContext(ops, context, options);
  283. if (options & k_HASH_HMAC) {
  284. hash->key = prepare_hmac_key(ops, context, key);
  285. }
  286. return Object(hash);
  287. }
  288. bool f_hash_update(CObjRef context, CStrRef data) {
  289. HashContext *hash = context.getTyped<HashContext>();
  290. hash->ops->hash_update(hash->context, (unsigned char *)data.data(),
  291. data.size());
  292. return true;
  293. }
  294. bool f_hash_update_file(CObjRef init_context, CStrRef filename,
  295. CObjRef stream_context /* = null */) {
  296. Variant f = f_fopen(filename, "rb");
  297. if (same(f, false)) {
  298. return false;
  299. }
  300. HashContext *hash = init_context.getTyped<HashContext>();
  301. for (Variant chunk = f_fread(f, 1024); !is_empty_string(chunk);
  302. chunk = f_fread(f, 1024)) {
  303. String schunk = chunk.toString();
  304. hash->ops->hash_update(hash->context, (unsigned char *)schunk.data(),
  305. schunk.size());
  306. }
  307. return true;
  308. }
  309. int64_t f_hash_update_stream(CObjRef context, CObjRef handle,
  310. int length /* = -1 */) {
  311. HashContext *hash = context.getTyped<HashContext>();
  312. int didread = 0;
  313. while (length) {
  314. Variant chunk = f_fread(handle, length > 0 ? length : 1024);
  315. if (is_empty_string(chunk)) {
  316. return didread;
  317. }
  318. String schunk = chunk.toString();
  319. hash->ops->hash_update(hash->context, (unsigned char *)schunk.data(),
  320. schunk.size());
  321. didread += schunk.size();
  322. length -= schunk.size();
  323. }
  324. return didread;
  325. }
  326. String f_hash_final(CObjRef context, bool raw_output /* = false */) {
  327. HashContext *hash = context.getTyped<HashContext>();
  328. String raw = String(hash->ops->digest_size, ReserveString);
  329. char *digest = raw.mutableSlice().ptr;
  330. hash->ops->hash_final((unsigned char *)digest, hash->context);
  331. if (hash->options & k_HASH_HMAC) {
  332. finalize_hmac_key(hash->key, hash->ops, hash->context, digest);
  333. hash->key = NULL;
  334. }
  335. free(hash->context);
  336. hash->context = NULL;
  337. raw.setSize(hash->ops->digest_size);
  338. if (raw_output) {
  339. return raw;
  340. }
  341. return StringUtil::HexEncode(raw);
  342. }
  343. int64_t f_furchash_hphp_ext(CStrRef key, int len, int nPart) {
  344. len = std::max(std::min(len, key.size()), 0);
  345. return furc_hash(key.data(), len, nPart);
  346. }
  347. bool f_furchash_hphp_ext_supported() {
  348. return true;
  349. }
  350. int64_t f_hphp_murmurhash(CStrRef key, int len, int seed) {
  351. len = std::max(std::min(len, key.size()), 0);
  352. return murmur_hash_64A(key.data(), len, seed);
  353. }
  354. ///////////////////////////////////////////////////////////////////////////////
  355. }