WbiSign

Usage:new WbiSign().encWbi(params, img_key, sub_key) => URL签名字符串(直接拼接到请求域名后边)

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/533087/1572495/WbiSign.js

  1. // ==UserScript==
  2. // @name WbiSign
  3. // @namespace vruses
  4. // @version 1.0
  5. // @author layenh
  6. // ==/UserScript==
  7.  
  8. //WBI Algorithm: https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
  9. //MD5 Algorithm: https://github.com/satazor/js-spark-md5
  10.  
  11. /**
  12. * Utility class for generating Wbi signature used in Bilibili API requests.
  13. * @class
  14. */
  15. class WbiSign {
  16. constructor() {
  17. this.mixinKeyEncTab = [
  18. 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5,
  19. 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55,
  20. 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57,
  21. 62, 11, 36, 20, 34, 44, 52,
  22. ];
  23. }
  24. // 对 imgKey 和 subKey 进行字符顺序打乱编码
  25. getMixinKey = (orig) =>
  26. this.mixinKeyEncTab
  27. .map((n) => orig[n])
  28. .join("")
  29. .slice(0, 32);
  30.  
  31. /**
  32. * @param {Object} params - The parameters of a bili request.
  33. * @param {string} img_key - A disguised field used as part of the signature generation.
  34. * @param {string} sub_key - A disguised field paired with img_key to form a verification token.
  35. * @return {string} - A URL query string including the original parameters,
  36. * plus `wts` (timestamp) and `w_rid` (signature).
  37. * @description 为请求参数进行 wbi 签名
  38. */
  39. encWbi(params, img_key, sub_key) {
  40. const mixin_key = this.getMixinKey(img_key + sub_key),
  41. curr_time = Math.round(Date.now() / 1000),
  42. chr_filter = /[!'()*]/g;
  43.  
  44. Object.assign(params, { wts: curr_time }); // 添加 wts 字段
  45. // 按照 key 重排参数
  46. const query = Object.keys(params)
  47. .sort()
  48. .map((key) => {
  49. // 过滤 value 中的 "!'()*" 字符
  50. const value = params[key].toString().replace(chr_filter, "");
  51. return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
  52. })
  53. .join("&");
  54.  
  55. const wbi_sign = SparkMD5.hash(query + mixin_key); // 计算 w_rid
  56.  
  57. return query + "&w_rid=" + wbi_sign;
  58. }
  59. }
  60.  
  61. const SparkMD5 = (function (undefined) {
  62. "use strict";
  63.  
  64. /*
  65. * Fastest md5 implementation around (JKM md5).
  66. * Credits: Joseph Myers
  67. *
  68. * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
  69. * @see http://jsperf.com/md5-shootout/7
  70. */
  71.  
  72. /* this function is much faster,
  73. so if possible we use it. Some IEs
  74. are the only ones I know of that
  75. need the idiotic second function,
  76. generated by an if clause. */
  77. var add32 = function (a, b) {
  78. return (a + b) & 0xffffffff;
  79. },
  80. hex_chr = [
  81. "0",
  82. "1",
  83. "2",
  84. "3",
  85. "4",
  86. "5",
  87. "6",
  88. "7",
  89. "8",
  90. "9",
  91. "a",
  92. "b",
  93. "c",
  94. "d",
  95. "e",
  96. "f",
  97. ];
  98.  
  99. function cmn(q, a, b, x, s, t) {
  100. a = add32(add32(a, q), add32(x, t));
  101. return add32((a << s) | (a >>> (32 - s)), b);
  102. }
  103.  
  104. function md5cycle(x, k) {
  105. var a = x[0],
  106. b = x[1],
  107. c = x[2],
  108. d = x[3];
  109.  
  110. a += (((b & c) | (~b & d)) + k[0] - 680876936) | 0;
  111. a = (((a << 7) | (a >>> 25)) + b) | 0;
  112. d += (((a & b) | (~a & c)) + k[1] - 389564586) | 0;
  113. d = (((d << 12) | (d >>> 20)) + a) | 0;
  114. c += (((d & a) | (~d & b)) + k[2] + 606105819) | 0;
  115. c = (((c << 17) | (c >>> 15)) + d) | 0;
  116. b += (((c & d) | (~c & a)) + k[3] - 1044525330) | 0;
  117. b = (((b << 22) | (b >>> 10)) + c) | 0;
  118. a += (((b & c) | (~b & d)) + k[4] - 176418897) | 0;
  119. a = (((a << 7) | (a >>> 25)) + b) | 0;
  120. d += (((a & b) | (~a & c)) + k[5] + 1200080426) | 0;
  121. d = (((d << 12) | (d >>> 20)) + a) | 0;
  122. c += (((d & a) | (~d & b)) + k[6] - 1473231341) | 0;
  123. c = (((c << 17) | (c >>> 15)) + d) | 0;
  124. b += (((c & d) | (~c & a)) + k[7] - 45705983) | 0;
  125. b = (((b << 22) | (b >>> 10)) + c) | 0;
  126. a += (((b & c) | (~b & d)) + k[8] + 1770035416) | 0;
  127. a = (((a << 7) | (a >>> 25)) + b) | 0;
  128. d += (((a & b) | (~a & c)) + k[9] - 1958414417) | 0;
  129. d = (((d << 12) | (d >>> 20)) + a) | 0;
  130. c += (((d & a) | (~d & b)) + k[10] - 42063) | 0;
  131. c = (((c << 17) | (c >>> 15)) + d) | 0;
  132. b += (((c & d) | (~c & a)) + k[11] - 1990404162) | 0;
  133. b = (((b << 22) | (b >>> 10)) + c) | 0;
  134. a += (((b & c) | (~b & d)) + k[12] + 1804603682) | 0;
  135. a = (((a << 7) | (a >>> 25)) + b) | 0;
  136. d += (((a & b) | (~a & c)) + k[13] - 40341101) | 0;
  137. d = (((d << 12) | (d >>> 20)) + a) | 0;
  138. c += (((d & a) | (~d & b)) + k[14] - 1502002290) | 0;
  139. c = (((c << 17) | (c >>> 15)) + d) | 0;
  140. b += (((c & d) | (~c & a)) + k[15] + 1236535329) | 0;
  141. b = (((b << 22) | (b >>> 10)) + c) | 0;
  142.  
  143. a += (((b & d) | (c & ~d)) + k[1] - 165796510) | 0;
  144. a = (((a << 5) | (a >>> 27)) + b) | 0;
  145. d += (((a & c) | (b & ~c)) + k[6] - 1069501632) | 0;
  146. d = (((d << 9) | (d >>> 23)) + a) | 0;
  147. c += (((d & b) | (a & ~b)) + k[11] + 643717713) | 0;
  148. c = (((c << 14) | (c >>> 18)) + d) | 0;
  149. b += (((c & a) | (d & ~a)) + k[0] - 373897302) | 0;
  150. b = (((b << 20) | (b >>> 12)) + c) | 0;
  151. a += (((b & d) | (c & ~d)) + k[5] - 701558691) | 0;
  152. a = (((a << 5) | (a >>> 27)) + b) | 0;
  153. d += (((a & c) | (b & ~c)) + k[10] + 38016083) | 0;
  154. d = (((d << 9) | (d >>> 23)) + a) | 0;
  155. c += (((d & b) | (a & ~b)) + k[15] - 660478335) | 0;
  156. c = (((c << 14) | (c >>> 18)) + d) | 0;
  157. b += (((c & a) | (d & ~a)) + k[4] - 405537848) | 0;
  158. b = (((b << 20) | (b >>> 12)) + c) | 0;
  159. a += (((b & d) | (c & ~d)) + k[9] + 568446438) | 0;
  160. a = (((a << 5) | (a >>> 27)) + b) | 0;
  161. d += (((a & c) | (b & ~c)) + k[14] - 1019803690) | 0;
  162. d = (((d << 9) | (d >>> 23)) + a) | 0;
  163. c += (((d & b) | (a & ~b)) + k[3] - 187363961) | 0;
  164. c = (((c << 14) | (c >>> 18)) + d) | 0;
  165. b += (((c & a) | (d & ~a)) + k[8] + 1163531501) | 0;
  166. b = (((b << 20) | (b >>> 12)) + c) | 0;
  167. a += (((b & d) | (c & ~d)) + k[13] - 1444681467) | 0;
  168. a = (((a << 5) | (a >>> 27)) + b) | 0;
  169. d += (((a & c) | (b & ~c)) + k[2] - 51403784) | 0;
  170. d = (((d << 9) | (d >>> 23)) + a) | 0;
  171. c += (((d & b) | (a & ~b)) + k[7] + 1735328473) | 0;
  172. c = (((c << 14) | (c >>> 18)) + d) | 0;
  173. b += (((c & a) | (d & ~a)) + k[12] - 1926607734) | 0;
  174. b = (((b << 20) | (b >>> 12)) + c) | 0;
  175.  
  176. a += ((b ^ c ^ d) + k[5] - 378558) | 0;
  177. a = (((a << 4) | (a >>> 28)) + b) | 0;
  178. d += ((a ^ b ^ c) + k[8] - 2022574463) | 0;
  179. d = (((d << 11) | (d >>> 21)) + a) | 0;
  180. c += ((d ^ a ^ b) + k[11] + 1839030562) | 0;
  181. c = (((c << 16) | (c >>> 16)) + d) | 0;
  182. b += ((c ^ d ^ a) + k[14] - 35309556) | 0;
  183. b = (((b << 23) | (b >>> 9)) + c) | 0;
  184. a += ((b ^ c ^ d) + k[1] - 1530992060) | 0;
  185. a = (((a << 4) | (a >>> 28)) + b) | 0;
  186. d += ((a ^ b ^ c) + k[4] + 1272893353) | 0;
  187. d = (((d << 11) | (d >>> 21)) + a) | 0;
  188. c += ((d ^ a ^ b) + k[7] - 155497632) | 0;
  189. c = (((c << 16) | (c >>> 16)) + d) | 0;
  190. b += ((c ^ d ^ a) + k[10] - 1094730640) | 0;
  191. b = (((b << 23) | (b >>> 9)) + c) | 0;
  192. a += ((b ^ c ^ d) + k[13] + 681279174) | 0;
  193. a = (((a << 4) | (a >>> 28)) + b) | 0;
  194. d += ((a ^ b ^ c) + k[0] - 358537222) | 0;
  195. d = (((d << 11) | (d >>> 21)) + a) | 0;
  196. c += ((d ^ a ^ b) + k[3] - 722521979) | 0;
  197. c = (((c << 16) | (c >>> 16)) + d) | 0;
  198. b += ((c ^ d ^ a) + k[6] + 76029189) | 0;
  199. b = (((b << 23) | (b >>> 9)) + c) | 0;
  200. a += ((b ^ c ^ d) + k[9] - 640364487) | 0;
  201. a = (((a << 4) | (a >>> 28)) + b) | 0;
  202. d += ((a ^ b ^ c) + k[12] - 421815835) | 0;
  203. d = (((d << 11) | (d >>> 21)) + a) | 0;
  204. c += ((d ^ a ^ b) + k[15] + 530742520) | 0;
  205. c = (((c << 16) | (c >>> 16)) + d) | 0;
  206. b += ((c ^ d ^ a) + k[2] - 995338651) | 0;
  207. b = (((b << 23) | (b >>> 9)) + c) | 0;
  208.  
  209. a += ((c ^ (b | ~d)) + k[0] - 198630844) | 0;
  210. a = (((a << 6) | (a >>> 26)) + b) | 0;
  211. d += ((b ^ (a | ~c)) + k[7] + 1126891415) | 0;
  212. d = (((d << 10) | (d >>> 22)) + a) | 0;
  213. c += ((a ^ (d | ~b)) + k[14] - 1416354905) | 0;
  214. c = (((c << 15) | (c >>> 17)) + d) | 0;
  215. b += ((d ^ (c | ~a)) + k[5] - 57434055) | 0;
  216. b = (((b << 21) | (b >>> 11)) + c) | 0;
  217. a += ((c ^ (b | ~d)) + k[12] + 1700485571) | 0;
  218. a = (((a << 6) | (a >>> 26)) + b) | 0;
  219. d += ((b ^ (a | ~c)) + k[3] - 1894986606) | 0;
  220. d = (((d << 10) | (d >>> 22)) + a) | 0;
  221. c += ((a ^ (d | ~b)) + k[10] - 1051523) | 0;
  222. c = (((c << 15) | (c >>> 17)) + d) | 0;
  223. b += ((d ^ (c | ~a)) + k[1] - 2054922799) | 0;
  224. b = (((b << 21) | (b >>> 11)) + c) | 0;
  225. a += ((c ^ (b | ~d)) + k[8] + 1873313359) | 0;
  226. a = (((a << 6) | (a >>> 26)) + b) | 0;
  227. d += ((b ^ (a | ~c)) + k[15] - 30611744) | 0;
  228. d = (((d << 10) | (d >>> 22)) + a) | 0;
  229. c += ((a ^ (d | ~b)) + k[6] - 1560198380) | 0;
  230. c = (((c << 15) | (c >>> 17)) + d) | 0;
  231. b += ((d ^ (c | ~a)) + k[13] + 1309151649) | 0;
  232. b = (((b << 21) | (b >>> 11)) + c) | 0;
  233. a += ((c ^ (b | ~d)) + k[4] - 145523070) | 0;
  234. a = (((a << 6) | (a >>> 26)) + b) | 0;
  235. d += ((b ^ (a | ~c)) + k[11] - 1120210379) | 0;
  236. d = (((d << 10) | (d >>> 22)) + a) | 0;
  237. c += ((a ^ (d | ~b)) + k[2] + 718787259) | 0;
  238. c = (((c << 15) | (c >>> 17)) + d) | 0;
  239. b += ((d ^ (c | ~a)) + k[9] - 343485551) | 0;
  240. b = (((b << 21) | (b >>> 11)) + c) | 0;
  241.  
  242. x[0] = (a + x[0]) | 0;
  243. x[1] = (b + x[1]) | 0;
  244. x[2] = (c + x[2]) | 0;
  245. x[3] = (d + x[3]) | 0;
  246. }
  247.  
  248. function md5blk(s) {
  249. var md5blks = [],
  250. i; /* Andy King said do it this way. */
  251.  
  252. for (i = 0; i < 64; i += 4) {
  253. md5blks[i >> 2] =
  254. s.charCodeAt(i) +
  255. (s.charCodeAt(i + 1) << 8) +
  256. (s.charCodeAt(i + 2) << 16) +
  257. (s.charCodeAt(i + 3) << 24);
  258. }
  259. return md5blks;
  260. }
  261.  
  262. function md5blk_array(a) {
  263. var md5blks = [],
  264. i; /* Andy King said do it this way. */
  265.  
  266. for (i = 0; i < 64; i += 4) {
  267. md5blks[i >> 2] =
  268. a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
  269. }
  270. return md5blks;
  271. }
  272.  
  273. function md51(s) {
  274. var n = s.length,
  275. state = [1732584193, -271733879, -1732584194, 271733878],
  276. i,
  277. length,
  278. tail,
  279. tmp,
  280. lo,
  281. hi;
  282.  
  283. for (i = 64; i <= n; i += 64) {
  284. md5cycle(state, md5blk(s.substring(i - 64, i)));
  285. }
  286. s = s.substring(i - 64);
  287. length = s.length;
  288. tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  289. for (i = 0; i < length; i += 1) {
  290. tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
  291. }
  292. tail[i >> 2] |= 0x80 << (i % 4 << 3);
  293. if (i > 55) {
  294. md5cycle(state, tail);
  295. for (i = 0; i < 16; i += 1) {
  296. tail[i] = 0;
  297. }
  298. }
  299.  
  300. // Beware that the final length might not fit in 32 bits so we take care of that
  301. tmp = n * 8;
  302. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  303. lo = parseInt(tmp[2], 16);
  304. hi = parseInt(tmp[1], 16) || 0;
  305.  
  306. tail[14] = lo;
  307. tail[15] = hi;
  308.  
  309. md5cycle(state, tail);
  310. return state;
  311. }
  312.  
  313. function md51_array(a) {
  314. var n = a.length,
  315. state = [1732584193, -271733879, -1732584194, 271733878],
  316. i,
  317. length,
  318. tail,
  319. tmp,
  320. lo,
  321. hi;
  322.  
  323. for (i = 64; i <= n; i += 64) {
  324. md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
  325. }
  326.  
  327. // Not sure if it is a bug, however IE10 will always produce a sub array of length 1
  328. // containing the last element of the parent array if the sub array specified starts
  329. // beyond the length of the parent array - weird.
  330. // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
  331. a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0);
  332.  
  333. length = a.length;
  334. tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  335. for (i = 0; i < length; i += 1) {
  336. tail[i >> 2] |= a[i] << (i % 4 << 3);
  337. }
  338.  
  339. tail[i >> 2] |= 0x80 << (i % 4 << 3);
  340. if (i > 55) {
  341. md5cycle(state, tail);
  342. for (i = 0; i < 16; i += 1) {
  343. tail[i] = 0;
  344. }
  345. }
  346.  
  347. // Beware that the final length might not fit in 32 bits so we take care of that
  348. tmp = n * 8;
  349. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  350. lo = parseInt(tmp[2], 16);
  351. hi = parseInt(tmp[1], 16) || 0;
  352.  
  353. tail[14] = lo;
  354. tail[15] = hi;
  355.  
  356. md5cycle(state, tail);
  357.  
  358. return state;
  359. }
  360.  
  361. function rhex(n) {
  362. var s = "",
  363. j;
  364. for (j = 0; j < 4; j += 1) {
  365. s += hex_chr[(n >> (j * 8 + 4)) & 0x0f] + hex_chr[(n >> (j * 8)) & 0x0f];
  366. }
  367. return s;
  368. }
  369.  
  370. function hex(x) {
  371. var i;
  372. for (i = 0; i < x.length; i += 1) {
  373. x[i] = rhex(x[i]);
  374. }
  375. return x.join("");
  376. }
  377.  
  378. // In some cases the fast add32 function cannot be used..
  379. if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") {
  380. add32 = function (x, y) {
  381. var lsw = (x & 0xffff) + (y & 0xffff),
  382. msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  383. return (msw << 16) | (lsw & 0xffff);
  384. };
  385. }
  386.  
  387. // ---------------------------------------------------
  388.  
  389. /**
  390. * ArrayBuffer slice polyfill.
  391. *
  392. * @see https://github.com/ttaubert/node-arraybuffer-slice
  393. */
  394.  
  395. if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) {
  396. (function () {
  397. function clamp(val, length) {
  398. val = val | 0 || 0;
  399.  
  400. if (val < 0) {
  401. return Math.max(val + length, 0);
  402. }
  403.  
  404. return Math.min(val, length);
  405. }
  406.  
  407. ArrayBuffer.prototype.slice = function (from, to) {
  408. var length = this.byteLength,
  409. begin = clamp(from, length),
  410. end = length,
  411. num,
  412. target,
  413. targetArray,
  414. sourceArray;
  415.  
  416. if (to !== undefined) {
  417. end = clamp(to, length);
  418. }
  419.  
  420. if (begin > end) {
  421. return new ArrayBuffer(0);
  422. }
  423.  
  424. num = end - begin;
  425. target = new ArrayBuffer(num);
  426. targetArray = new Uint8Array(target);
  427.  
  428. sourceArray = new Uint8Array(this, begin, num);
  429. targetArray.set(sourceArray);
  430.  
  431. return target;
  432. };
  433. })();
  434. }
  435.  
  436. // ---------------------------------------------------
  437.  
  438. /**
  439. * Helpers.
  440. */
  441.  
  442. function toUtf8(str) {
  443. if (/[\u0080-\uFFFF]/.test(str)) {
  444. str = unescape(encodeURIComponent(str));
  445. }
  446.  
  447. return str;
  448. }
  449.  
  450. function utf8Str2ArrayBuffer(str, returnUInt8Array) {
  451. var length = str.length,
  452. buff = new ArrayBuffer(length),
  453. arr = new Uint8Array(buff),
  454. i;
  455.  
  456. for (i = 0; i < length; i += 1) {
  457. arr[i] = str.charCodeAt(i);
  458. }
  459.  
  460. return returnUInt8Array ? arr : buff;
  461. }
  462.  
  463. function arrayBuffer2Utf8Str(buff) {
  464. return String.fromCharCode.apply(null, new Uint8Array(buff));
  465. }
  466.  
  467. function concatenateArrayBuffers(first, second, returnUInt8Array) {
  468. var result = new Uint8Array(first.byteLength + second.byteLength);
  469.  
  470. result.set(new Uint8Array(first));
  471. result.set(new Uint8Array(second), first.byteLength);
  472.  
  473. return returnUInt8Array ? result : result.buffer;
  474. }
  475.  
  476. function hexToBinaryString(hex) {
  477. var bytes = [],
  478. length = hex.length,
  479. x;
  480.  
  481. for (x = 0; x < length - 1; x += 2) {
  482. bytes.push(parseInt(hex.substr(x, 2), 16));
  483. }
  484.  
  485. return String.fromCharCode.apply(String, bytes);
  486. }
  487.  
  488. // ---------------------------------------------------
  489.  
  490. /**
  491. * SparkMD5 OOP implementation.
  492. *
  493. * Use this class to perform an incremental md5, otherwise use the
  494. * static methods instead.
  495. */
  496.  
  497. function SparkMD5() {
  498. // call reset to init the instance
  499. this.reset();
  500. }
  501.  
  502. /**
  503. * Appends a string.
  504. * A conversion will be applied if an utf8 string is detected.
  505. *
  506. * @param {String} str The string to be appended
  507. *
  508. * @return {SparkMD5} The instance itself
  509. */
  510. SparkMD5.prototype.append = function (str) {
  511. // Converts the string to utf8 bytes if necessary
  512. // Then append as binary
  513. this.appendBinary(toUtf8(str));
  514.  
  515. return this;
  516. };
  517.  
  518. /**
  519. * Appends a binary string.
  520. *
  521. * @param {String} contents The binary string to be appended
  522. *
  523. * @return {SparkMD5} The instance itself
  524. */
  525. SparkMD5.prototype.appendBinary = function (contents) {
  526. this._buff += contents;
  527. this._length += contents.length;
  528.  
  529. var length = this._buff.length,
  530. i;
  531.  
  532. for (i = 64; i <= length; i += 64) {
  533. md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
  534. }
  535.  
  536. this._buff = this._buff.substring(i - 64);
  537.  
  538. return this;
  539. };
  540.  
  541. /**
  542. * Finishes the incremental computation, reseting the internal state and
  543. * returning the result.
  544. *
  545. * @param {Boolean} raw True to get the raw string, false to get the hex string
  546. *
  547. * @return {String} The result
  548. */
  549. SparkMD5.prototype.end = function (raw) {
  550. var buff = this._buff,
  551. length = buff.length,
  552. i,
  553. tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  554. ret;
  555.  
  556. for (i = 0; i < length; i += 1) {
  557. tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3);
  558. }
  559.  
  560. this._finish(tail, length);
  561. ret = hex(this._hash);
  562.  
  563. if (raw) {
  564. ret = hexToBinaryString(ret);
  565. }
  566.  
  567. this.reset();
  568.  
  569. return ret;
  570. };
  571.  
  572. /**
  573. * Resets the internal state of the computation.
  574. *
  575. * @return {SparkMD5} The instance itself
  576. */
  577. SparkMD5.prototype.reset = function () {
  578. this._buff = "";
  579. this._length = 0;
  580. this._hash = [1732584193, -271733879, -1732584194, 271733878];
  581.  
  582. return this;
  583. };
  584.  
  585. /**
  586. * Gets the internal state of the computation.
  587. *
  588. * @return {Object} The state
  589. */
  590. SparkMD5.prototype.getState = function () {
  591. return {
  592. buff: this._buff,
  593. length: this._length,
  594. hash: this._hash.slice(),
  595. };
  596. };
  597.  
  598. /**
  599. * Gets the internal state of the computation.
  600. *
  601. * @param {Object} state The state
  602. *
  603. * @return {SparkMD5} The instance itself
  604. */
  605. SparkMD5.prototype.setState = function (state) {
  606. this._buff = state.buff;
  607. this._length = state.length;
  608. this._hash = state.hash;
  609.  
  610. return this;
  611. };
  612.  
  613. /**
  614. * Releases memory used by the incremental buffer and other additional
  615. * resources. If you plan to use the instance again, use reset instead.
  616. */
  617. SparkMD5.prototype.destroy = function () {
  618. delete this._hash;
  619. delete this._buff;
  620. delete this._length;
  621. };
  622.  
  623. /**
  624. * Finish the final calculation based on the tail.
  625. *
  626. * @param {Array} tail The tail (will be modified)
  627. * @param {Number} length The length of the remaining buffer
  628. */
  629. SparkMD5.prototype._finish = function (tail, length) {
  630. var i = length,
  631. tmp,
  632. lo,
  633. hi;
  634.  
  635. tail[i >> 2] |= 0x80 << (i % 4 << 3);
  636. if (i > 55) {
  637. md5cycle(this._hash, tail);
  638. for (i = 0; i < 16; i += 1) {
  639. tail[i] = 0;
  640. }
  641. }
  642.  
  643. // Do the final computation based on the tail and length
  644. // Beware that the final length may not fit in 32 bits so we take care of that
  645. tmp = this._length * 8;
  646. tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
  647. lo = parseInt(tmp[2], 16);
  648. hi = parseInt(tmp[1], 16) || 0;
  649.  
  650. tail[14] = lo;
  651. tail[15] = hi;
  652. md5cycle(this._hash, tail);
  653. };
  654.  
  655. /**
  656. * Performs the md5 hash on a string.
  657. * A conversion will be applied if utf8 string is detected.
  658. *
  659. * @param {String} str The string
  660. * @param {Boolean} [raw] True to get the raw string, false to get the hex string
  661. *
  662. * @return {String} The result
  663. */
  664. SparkMD5.hash = function (str, raw) {
  665. // Converts the string to utf8 bytes if necessary
  666. // Then compute it using the binary function
  667. return SparkMD5.hashBinary(toUtf8(str), raw);
  668. };
  669.  
  670. /**
  671. * Performs the md5 hash on a binary string.
  672. *
  673. * @param {String} content The binary string
  674. * @param {Boolean} [raw] True to get the raw string, false to get the hex string
  675. *
  676. * @return {String} The result
  677. */
  678. SparkMD5.hashBinary = function (content, raw) {
  679. var hash = md51(content),
  680. ret = hex(hash);
  681.  
  682. return raw ? hexToBinaryString(ret) : ret;
  683. };
  684.  
  685. // ---------------------------------------------------
  686.  
  687. /**
  688. * SparkMD5 OOP implementation for array buffers.
  689. *
  690. * Use this class to perform an incremental md5 ONLY for array buffers.
  691. */
  692. SparkMD5.ArrayBuffer = function () {
  693. // call reset to init the instance
  694. this.reset();
  695. };
  696.  
  697. /**
  698. * Appends an array buffer.
  699. *
  700. * @param {ArrayBuffer} arr The array to be appended
  701. *
  702. * @return {SparkMD5.ArrayBuffer} The instance itself
  703. */
  704. SparkMD5.ArrayBuffer.prototype.append = function (arr) {
  705. var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
  706. length = buff.length,
  707. i;
  708.  
  709. this._length += arr.byteLength;
  710.  
  711. for (i = 64; i <= length; i += 64) {
  712. md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
  713. }
  714.  
  715. this._buff =
  716. i - 64 < length
  717. ? new Uint8Array(buff.buffer.slice(i - 64))
  718. : new Uint8Array(0);
  719.  
  720. return this;
  721. };
  722.  
  723. /**
  724. * Finishes the incremental computation, reseting the internal state and
  725. * returning the result.
  726. *
  727. * @param {Boolean} raw True to get the raw string, false to get the hex string
  728. *
  729. * @return {String} The result
  730. */
  731. SparkMD5.ArrayBuffer.prototype.end = function (raw) {
  732. var buff = this._buff,
  733. length = buff.length,
  734. tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  735. i,
  736. ret;
  737.  
  738. for (i = 0; i < length; i += 1) {
  739. tail[i >> 2] |= buff[i] << (i % 4 << 3);
  740. }
  741.  
  742. this._finish(tail, length);
  743. ret = hex(this._hash);
  744.  
  745. if (raw) {
  746. ret = hexToBinaryString(ret);
  747. }
  748.  
  749. this.reset();
  750.  
  751. return ret;
  752. };
  753.  
  754. /**
  755. * Resets the internal state of the computation.
  756. *
  757. * @return {SparkMD5.ArrayBuffer} The instance itself
  758. */
  759. SparkMD5.ArrayBuffer.prototype.reset = function () {
  760. this._buff = new Uint8Array(0);
  761. this._length = 0;
  762. this._hash = [1732584193, -271733879, -1732584194, 271733878];
  763.  
  764. return this;
  765. };
  766.  
  767. /**
  768. * Gets the internal state of the computation.
  769. *
  770. * @return {Object} The state
  771. */
  772. SparkMD5.ArrayBuffer.prototype.getState = function () {
  773. var state = SparkMD5.prototype.getState.call(this);
  774.  
  775. // Convert buffer to a string
  776. state.buff = arrayBuffer2Utf8Str(state.buff);
  777.  
  778. return state;
  779. };
  780.  
  781. /**
  782. * Gets the internal state of the computation.
  783. *
  784. * @param {Object} state The state
  785. *
  786. * @return {SparkMD5.ArrayBuffer} The instance itself
  787. */
  788. SparkMD5.ArrayBuffer.prototype.setState = function (state) {
  789. // Convert string to buffer
  790. state.buff = utf8Str2ArrayBuffer(state.buff, true);
  791.  
  792. return SparkMD5.prototype.setState.call(this, state);
  793. };
  794.  
  795. SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
  796.  
  797. SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
  798.  
  799. /**
  800. * Performs the md5 hash on an array buffer.
  801. *
  802. * @param {ArrayBuffer} arr The array buffer
  803. * @param {Boolean} [raw] True to get the raw string, false to get the hex one
  804. *
  805. * @return {String} The result
  806. */
  807. SparkMD5.ArrayBuffer.hash = function (arr, raw) {
  808. var hash = md51_array(new Uint8Array(arr)),
  809. ret = hex(hash);
  810.  
  811. return raw ? hexToBinaryString(ret) : ret;
  812. };
  813.  
  814. return SparkMD5;
  815. })();