WbiSign

Usage Description:\nconst signer = new WbiSign();\nconst signedParams = signer.encWbi({ foo: 'bar', baz: 123 },'abc123_img_key','xyz456_sub_key');

目前为 2025-04-17 提交的版本,查看 最新版本

此脚本不应直接安装,它是供其他脚本使用的外部库。如果你需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/533087/1572491/WbiSign.js

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