1、什么是RSA

  • 在介绍具体的内容之前,先来介绍一下什么是RSA非对称加密:
    • RSA是指RSA加密算法,是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
    • RSA公开密钥(yuè)密码体制是一种使用不同的加密密钥(yuè)与解密密钥(yuè),“由已知加密密钥(yuè)推导出解密密钥(yuè)在计算上是不可行的”密码体制。
    • 在公开密钥(yuè)密码体制中,加密密钥(yuè)(即公开密钥(yuè))PK是公开信息,而解密密钥(yuè)(即秘密密钥(yuè))SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥(yuè)SK是由公开密钥(yuè)PK决定的,但却不能根据PK计算出SK。
    • 说人话就是每个人都可以用钥匙P进行加密,但用P却解密不了,所以钥匙P可以暴露给每个人;相对的,钥匙S却是可以进行解密而无法进行加密的,所以钥匙S是绝对不能暴露的,必须自己藏着掖着。一般来说,拥有钥匙S的人都拥有钥匙P,因为钥匙P可以暴露给每个人,包括自己。也就是说自己随时都可以对文本进行加密和解密,而别人只能进行加密,而无法进行解密操作。所以,只要钥匙S不丢失,一般都能保障数据的绝密性。

2、为什么使用RSA算法

  • 最近在用微信写一个小程序,其中的一个需求就是在网路数据传输的过程中,要保证数据的安全性。于是作者便想到了3种加密策略:对称加密、非对称加密、摘要算法(散列算法、Hash算法)。
  • 对称加密:其中对称加密算法过于简单,容易被破解,所以没法选择。
  • 摘要算法:摘要算法很不错,如MD5摘要算法、SHA1摘要算法、SHA256摘要算法,之前听说SHA1算法被破解了,已经不安全了,故不再选择SHA1摘要算法了。最后的决定是落在了SHA256摘要算法上,由于SHA256算法所产生的Hash Code长度达256 bit,因此Hash碰撞的可能性大幅度的减少,其安全程度可以保障,因此是一个很好的选择。
    • 但是有一个问题,摘要算法算不上是真正的加解密算法,因为它只能用于加密,而无法进行解密,它所产生的哈希值是从原文本中摘取其中的一些文本片段,通过一定的算法所生成的,文本片段本身就无法还原全文本!故放弃摘要算法。
  • 非对称算法:最后作者命中的是非对称加密,非对称加密算法有很多种,如:
    1. RSA加密算法
    2. DSA(Digital Signature Algorithm,数字签名算法)
    3. ECDSA(Elliptic Curve Digital Signature Algorithm,椭圆曲线签名算法)
    4. 等等…有兴趣的可以再去找找看其他的算法~

由于作者本身也是因为最近在做微信小程序,而想到写这篇博客的,因此本博客就决定围绕着这方面展开了。

既然说到了微信小程序,由于微信所采用的面向对象的编程语言主要包括JavaScript,那么就介绍一下如何在JS中编写加密的代码吧!

3、JS前端使用RSA

首先,算法本身不会让我们自己来写啦,当然有兴趣的话是可以去了解算法本身是如何实现的。

  • 我们需要去引进一个js文件作为我们加解密的工具:jsencrypt.js

  • jsencrypt的github网址:https://github.com/travist/jsencrypt

  • 但由于微信小程序不支持window对象等内容,所以不能直接在微信小程序中使用官方的jsencrypt.js文件,我们需要对源码进行一些简单的增删改,以达到兼容。

  • 网上很多教程,这里就不多赘述了:https://developers.weixin.qq.com/community/develop/doc/000068b497cfc00619b7bcfdc51004

  • 这里直接附带修改后兼容的js文件(经过压缩),以方便日后直接使用:

1
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.JSEncrypt = {}))) }(this, (function (exports) { 'use strict'; var navigator2 = { appName: 'Netscape', userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1' }; var window2 = { ASN1: null, Base64: null, Hex: null, crypto: null, href: null }; var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; function int2char(n) { return BI_RM.charAt(n) } function op_and(x, y) { return x & y } function op_or(x, y) { return x | y } function op_xor(x, y) { return x ^ y } function op_andnot(x, y) { return x & ~y } function lbit(x) { if (x == 0) { return -1 } var r = 0; if ((x & 0xffff) == 0) { x >>= 16; r += 16 } if ((x & 0xff) == 0) { x >>= 8; r += 8 } if ((x & 0xf) == 0) { x >>= 4; r += 4 } if ((x & 3) == 0) { x >>= 2; r += 2 } if ((x & 1) == 0) { ++r } return r } function cbit(x) { var r = 0; while (x != 0) { x &= x - 1; ++r } return r } var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var b64pad = "="; function hex2b64(h) { var i; var c; var ret = ""; for (i = 0; i + 3 <= h.length; i += 3) { c = parseInt(h.substring(i, i + 3), 16); ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63) } if (i + 1 == h.length) { c = parseInt(h.substring(i, i + 1), 16); ret += b64map.charAt(c << 2) } else if (i + 2 == h.length) { c = parseInt(h.substring(i, i + 2), 16); ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4) } while ((ret.length & 3) > 0) { ret += b64pad } return ret } function b64tohex(s) { var ret = ""; var i; var k = 0; var slop = 0; for (i = 0; i < s.length; ++i) { if (s.charAt(i) == b64pad) { break } var v = b64map.indexOf(s.charAt(i)); if (v < 0) { continue } if (k == 0) { ret += int2char(v >> 2); slop = v & 3; k = 1 } else if (k == 1) { ret += int2char((slop << 2) | (v >> 4)); slop = v & 0xf; k = 2 } else if (k == 2) { ret += int2char(slop); ret += int2char(v >> 2); slop = v & 3; k = 3 } else { ret += int2char((slop << 2) | (v >> 4)); ret += int2char(v & 0xf); k = 0 } } if (k == 1) { ret += int2char(slop << 2) } return ret } var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p] }; return extendStatics(d, b) }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()) } var decoder; var Hex = { decode: function (a) { var i; if (decoder === undefined) { var hex = "0123456789ABCDEF"; var ignore = " \f\n\r\t\u00A0\u2028\u2029"; decoder = {}; for (i = 0; i < 16; ++i) { decoder[hex.charAt(i)] = i } hex = hex.toLowerCase(); for (i = 10; i < 16; ++i) { decoder[hex.charAt(i)] = i } for (i = 0; i < ignore.length; ++i) { decoder[ignore.charAt(i)] = -1 } } var out = []; var bits = 0; var char_count = 0; for (i = 0; i < a.length; ++i) { var c = a.charAt(i); if (c == "=") { break } c = decoder[c]; if (c == -1) { continue } if (c === undefined) { throw new Error("Illegal character at offset " + i); } bits |= c; if (++char_count >= 2) { out[out.length] = bits; bits = 0; char_count = 0 } else { bits <<= 4 } } if (char_count) { throw new Error("Hex encoding incomplete: 4 bits missing"); } return out } }; var decoder$1; var Base64 = { decode: function (a) { var i; if (decoder$1 === undefined) { var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var ignore = "= \f\n\r\t\u00A0\u2028\u2029"; decoder$1 = Object.create(null); for (i = 0; i < 64; ++i) { decoder$1[b64.charAt(i)] = i } for (i = 0; i < ignore.length; ++i) { decoder$1[ignore.charAt(i)] = -1 } } var out = []; var bits = 0; var char_count = 0; for (i = 0; i < a.length; ++i) { var c = a.charAt(i); if (c == "=") { break } c = decoder$1[c]; if (c == -1) { continue } if (c === undefined) { throw new Error("Illegal character at offset " + i); } bits |= c; if (++char_count >= 4) { out[out.length] = (bits >> 16); out[out.length] = (bits >> 8) & 0xFF; out[out.length] = bits & 0xFF; bits = 0; char_count = 0 } else { bits <<= 6 } } switch (char_count) { case 1: throw new Error("Base64 encoding incomplete: at least 2 bits missing"); case 2: out[out.length] = (bits >> 10); break; case 3: out[out.length] = (bits >> 16); out[out.length] = (bits >> 8) & 0xFF; break }return out }, re: /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/, unarmor: function (a) { var m = Base64.re.exec(a); if (m) { if (m[1]) { a = m[1] } else if (m[2]) { a = m[2] } else { throw new Error("RegExp out of sync"); } } return Base64.decode(a) } }; var max = 10000000000000; var Int10 = (function () { function Int10(value) { this.buf = [+value || 0] } Int10.prototype.mulAdd = function (m, c) { var b = this.buf; var l = b.length; var i; var t; for (i = 0; i < l; ++i) { t = b[i] * m + c; if (t < max) { c = 0 } else { c = 0 | (t / max); t -= c * max } b[i] = t } if (c > 0) { b[i] = c } }; Int10.prototype.sub = function (c) { var b = this.buf; var l = b.length; var i; var t; for (i = 0; i < l; ++i) { t = b[i] - c; if (t < 0) { t += max; c = 1 } else { c = 0 } b[i] = t } while (b[b.length - 1] === 0) { b.pop() } }; Int10.prototype.toString = function (base) { if ((base || 10) != 10) { throw new Error("only base 10 is supported"); } var b = this.buf; var s = b[b.length - 1].toString(); for (var i = b.length - 2; i >= 0; --i) { s += (max + b[i]).toString().substring(1) } return s }; Int10.prototype.valueOf = function () { var b = this.buf; var v = 0; for (var i = b.length - 1; i >= 0; --i) { v = v * max + b[i] } return v }; Int10.prototype.simplify = function () { var b = this.buf; return (b.length == 1) ? b[0] : this }; return Int10 }()); var ellipsis = "\u2026"; var reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; var reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; function stringCut(str, len) { if (str.length > len) { str = str.substring(0, len) + ellipsis } return str } var Stream = (function () { function Stream(enc, pos) { this.hexDigits = "0123456789ABCDEF"; if (enc instanceof Stream) { this.enc = enc.enc; this.pos = enc.pos } else { this.enc = enc; this.pos = pos } } Stream.prototype.get = function (pos) { if (pos === undefined) { pos = this.pos++ } if (pos >= this.enc.length) { throw new Error("Requesting byte offset " + pos + " on a stream of length " + this.enc.length); } return ("string" === typeof this.enc) ? this.enc.charCodeAt(pos) : this.enc[pos] }; Stream.prototype.hexByte = function (b) { return this.hexDigits.charAt((b >> 4) & 0xF) + this.hexDigits.charAt(b & 0xF) }; Stream.prototype.hexDump = function (start, end, raw) { var s = ""; for (var i = start; i < end; ++i) { s += this.hexByte(this.get(i)); if (raw !== true) { switch (i & 0xF) { case 0x7: s += "  "; break; case 0xF: s += "\n"; break; default: s += " " } } } return s }; Stream.prototype.isASCII = function (start, end) { for (var i = start; i < end; ++i) { var c = this.get(i); if (c < 32 || c > 176) { return false } } return true }; Stream.prototype.parseStringISO = function (start, end) { var s = ""; for (var i = start; i < end; ++i) { s += String.fromCharCode(this.get(i)) } return s }; Stream.prototype.parseStringUTF = function (start, end) { var s = ""; for (var i = start; i < end;) { var c = this.get(i++); if (c < 128) { s += String.fromCharCode(c) } else if ((c > 191) && (c < 224)) { s += String.fromCharCode(((c & 0x1F) << 6) | (this.get(i++) & 0x3F)) } else { s += String.fromCharCode(((c & 0x0F) << 12) | ((this.get(i++) & 0x3F) << 6) | (this.get(i++) & 0x3F)) } } return s }; Stream.prototype.parseStringBMP = function (start, end) { var str = ""; var hi; var lo; for (var i = start; i < end;) { hi = this.get(i++); lo = this.get(i++); str += String.fromCharCode((hi << 8) | lo) } return str }; Stream.prototype.parseTime = function (start, end, shortYear) { var s = this.parseStringISO(start, end); var m = (shortYear ? reTimeS : reTimeL).exec(s); if (!m) { return "Unrecognized time: " + s } if (shortYear) { m[1] = +m[1]; m[1] += (+m[1] < 70) ? 2000 : 1900 } s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4]; if (m[5]) { s += ":" + m[5]; if (m[6]) { s += ":" + m[6]; if (m[7]) { s += "." + m[7] } } } if (m[8]) { s += " UTC"; if (m[8] != "Z") { s += m[8]; if (m[9]) { s += ":" + m[9] } } } return s }; Stream.prototype.parseInteger = function (start, end) { var v = this.get(start); var neg = (v > 127); var pad = neg ? 255 : 0; var len; var s = ""; while (v == pad && ++start < end) { v = this.get(start) } len = end - start; if (len === 0) { return neg ? -1 : 0 } if (len > 4) { s = v; len <<= 3; while (((+s ^ pad) & 0x80) == 0) { s = +s << 1; --len } s = "(" + len + " bit)\n" } if (neg) { v = v - 256 } var n = new Int10(v); for (var i = start + 1; i < end; ++i) { n.mulAdd(256, this.get(i)) } return s + n.toString() }; Stream.prototype.parseBitString = function (start, end, maxLength) { var unusedBit = this.get(start); var lenBit = ((end - start - 1) << 3) - unusedBit; var intro = "(" + lenBit + " bit)\n"; var s = ""; for (var i = start + 1; i < end; ++i) { var b = this.get(i); var skip = (i == end - 1) ? unusedBit : 0; for (var j = 7; j >= skip; --j) { s += (b >> j) & 1 ? "1" : "0" } if (s.length > maxLength) { return intro + stringCut(s, maxLength) } } return intro + s }; Stream.prototype.parseOctetString = function (start, end, maxLength) { if (this.isASCII(start, end)) { return stringCut(this.parseStringISO(start, end), maxLength) } var len = end - start; var s = "(" + len + " byte)\n"; maxLength /= 2; if (len > maxLength) { end = start + maxLength } for (var i = start; i < end; ++i) { s += this.hexByte(this.get(i)) } if (len > maxLength) { s += ellipsis } return s }; Stream.prototype.parseOID = function (start, end, maxLength) { var s = ""; var n = new Int10(); var bits = 0; for (var i = start; i < end; ++i) { var v = this.get(i); n.mulAdd(128, v & 0x7F); bits += 7; if (!(v & 0x80)) { if (s === "") { n = n.simplify(); if (n instanceof Int10) { n.sub(80); s = "2." + n.toString() } else { var m = n < 80 ? n < 40 ? 0 : 1 : 2; s = m + "." + (n - m * 40) } } else { s += "." + n.toString() } if (s.length > maxLength) { return stringCut(s, maxLength) } n = new Int10(); bits = 0 } } if (bits > 0) { s += ".incomplete" } return s }; return Stream }()); var ASN1 = (function () { function ASN1(stream, header, length, tag, sub) { if (!(tag instanceof ASN1Tag)) { throw new Error("Invalid tag value."); } this.stream = stream; this.header = header; this.length = length; this.tag = tag; this.sub = sub } ASN1.prototype.typeName = function () { switch (this.tag.tagClass) { case 0: switch (this.tag.tagNumber) { case 0x00: return "EOC"; case 0x01: return "BOOLEAN"; case 0x02: return "INTEGER"; case 0x03: return "BIT_STRING"; case 0x04: return "OCTET_STRING"; case 0x05: return "NULL"; case 0x06: return "OBJECT_IDENTIFIER"; case 0x07: return "ObjectDescriptor"; case 0x08: return "EXTERNAL"; case 0x09: return "REAL"; case 0x0A: return "ENUMERATED"; case 0x0B: return "EMBEDDED_PDV"; case 0x0C: return "UTF8String"; case 0x10: return "SEQUENCE"; case 0x11: return "SET"; case 0x12: return "NumericString"; case 0x13: return "PrintableString"; case 0x14: return "TeletexString"; case 0x15: return "VideotexString"; case 0x16: return "IA5String"; case 0x17: return "UTCTime"; case 0x18: return "GeneralizedTime"; case 0x19: return "GraphicString"; case 0x1A: return "VisibleString"; case 0x1B: return "GeneralString"; case 0x1C: return "UniversalString"; case 0x1E: return "BMPString" }return "Universal_" + this.tag.tagNumber.toString(); case 1: return "Application_" + this.tag.tagNumber.toString(); case 2: return "[" + this.tag.tagNumber.toString() + "]"; case 3: return "Private_" + this.tag.tagNumber.toString() } }; ASN1.prototype.content = function (maxLength) { if (this.tag === undefined) { return null } if (maxLength === undefined) { maxLength = Infinity } var content = this.posContent(); var len = Math.abs(this.length); if (!this.tag.isUniversal()) { if (this.sub !== null) { return "(" + this.sub.length + " elem)" } return this.stream.parseOctetString(content, content + len, maxLength) } switch (this.tag.tagNumber) { case 0x01: return (this.stream.get(content) === 0) ? "false" : "true"; case 0x02: return this.stream.parseInteger(content, content + len); case 0x03: return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseBitString(content, content + len, maxLength); case 0x04: return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(content, content + len, maxLength); case 0x06: return this.stream.parseOID(content, content + len, maxLength); case 0x10: case 0x11: if (this.sub !== null) { return "(" + this.sub.length + " elem)" } else { return "(no elem)" } case 0x0C: return stringCut(this.stream.parseStringUTF(content, content + len), maxLength); case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x1A: return stringCut(this.stream.parseStringISO(content, content + len), maxLength); case 0x1E: return stringCut(this.stream.parseStringBMP(content, content + len), maxLength); case 0x17: case 0x18: return this.stream.parseTime(content, content + len, (this.tag.tagNumber == 0x17)) }return null }; ASN1.prototype.toString = function () { return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub === null) ? "null" : this.sub.length) + "]" }; ASN1.prototype.toPrettyString = function (indent) { if (indent === undefined) { indent = "" } var s = indent + this.typeName() + " @" + this.stream.pos; if (this.length >= 0) { s += "+" } s += this.length; if (this.tag.tagConstructed) { s += " (constructed)" } else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null)) { s += " (encapsulates)" } s += "\n"; if (this.sub !== null) { indent += "  "; for (var i = 0, max = this.sub.length; i < max; ++i) { s += this.sub[i].toPrettyString(indent) } } return s }; ASN1.prototype.posStart = function () { return this.stream.pos }; ASN1.prototype.posContent = function () { return this.stream.pos + this.header }; ASN1.prototype.posEnd = function () { return this.stream.pos + this.header + Math.abs(this.length) }; ASN1.prototype.toHexString = function () { return this.stream.hexDump(this.posStart(), this.posEnd(), true) }; ASN1.decodeLength = function (stream) { var buf = stream.get(); var len = buf & 0x7F; if (len == buf) { return len } if (len > 6) { throw new Error("Length over 48 bits not supported at position " + (stream.pos - 1)); } if (len === 0) { return null } buf = 0; for (var i = 0; i < len; ++i) { buf = (buf * 256) + stream.get() } return buf }; ASN1.prototype.getHexStringValue = function () { var hexString = this.toHexString(); var offset = this.header * 2; var length = this.length * 2; return hexString.substr(offset, length) }; ASN1.decode = function (str) { var stream; if (!(str instanceof Stream)) { stream = new Stream(str, 0) } else { stream = str } var streamStart = new Stream(stream); var tag = new ASN1Tag(stream); var len = ASN1.decodeLength(stream); var start = stream.pos; var header = start - streamStart.pos; var sub = null; var getSub = function () { var ret = []; if (len !== null) { var end = start + len; while (stream.pos < end) { ret[ret.length] = ASN1.decode(stream) } if (stream.pos != end) { throw new Error("Content size is not correct for container starting at offset " + start); } } else { try { for (; ;) { var s = ASN1.decode(stream); if (s.tag.isEOC()) { break } ret[ret.length] = s } len = start - stream.pos } catch (e) { throw new Error("Exception while decoding undefined length content: " + e); } } return ret }; if (tag.tagConstructed) { sub = getSub() } else if (tag.isUniversal() && ((tag.tagNumber == 0x03) || (tag.tagNumber == 0x04))) { try { if (tag.tagNumber == 0x03) { if (stream.get() != 0) { throw new Error("BIT STRINGs with unused bits cannot encapsulate."); } } sub = getSub(); for (var i = 0; i < sub.length; ++i) { if (sub[i].tag.isEOC()) { throw new Error("EOC is not supposed to be actual content."); } } } catch (e) { sub = null } } if (sub === null) { if (len === null) { throw new Error("We can't skip over an invalid tag with undefined length at offset " + start); } stream.pos = start + Math.abs(len) } return new ASN1(streamStart, header, len, tag, sub) }; return ASN1 }()); var ASN1Tag = (function () { function ASN1Tag(stream) { var buf = stream.get(); this.tagClass = buf >> 6; this.tagConstructed = ((buf & 0x20) !== 0); this.tagNumber = buf & 0x1F; if (this.tagNumber == 0x1F) { var n = new Int10(); do { buf = stream.get(); n.mulAdd(128, buf & 0x7F) } while (buf & 0x80); this.tagNumber = n.simplify() } } ASN1Tag.prototype.isUniversal = function () { return this.tagClass === 0x00 }; ASN1Tag.prototype.isEOC = function () { return this.tagClass === 0x00 && this.tagNumber === 0x00 }; return ASN1Tag }()); var dbits; var canary = 0xdeadbeefcafe; var j_lm = ((canary & 0xffffff) == 0xefcafe); var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]; var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; var BigInteger = (function () { function BigInteger(a, b, c) { if (a != null) { if ("number" == typeof a) { this.fromNumber(a, b, c) } else if (b == null && "string" != typeof a) { this.fromString(a, 256) } else { this.fromString(a, b) } } } BigInteger.prototype.toString = function (b) { if (this.s < 0) { return "-" + this.negate().toString(b) } var k; if (b == 16) { k = 4 } else if (b == 8) { k = 3 } else if (b == 2) { k = 1 } else if (b == 32) { k = 5 } else if (b == 4) { k = 2 } else { return this.toRadix(b) } var km = (1 << k) - 1; var d; var m = false; var r = ""; var i = this.t; var p = this.DB - (i * this.DB) % k; if (i-- > 0) { if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d) } while (i >= 0) { if (p < k) { d = (this[i] & ((1 << p) - 1)) << (k - p); d |= this[--i] >> (p += this.DB - k) } else { d = (this[i] >> (p -= k)) & km; if (p <= 0) { p += this.DB; --i } } if (d > 0) { m = true } if (m) { r += int2char(d) } } } return m ? r : "0" }; BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r }; BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this }; BigInteger.prototype.compareTo = function (a) { var r = this.s - a.s; if (r != 0) { return r } var i = this.t; r = i - a.t; if (r != 0) { return (this.s < 0) ? -r : r } while (--i >= 0) { if ((r = this[i] - a[i]) != 0) { return r } } return 0 }; BigInteger.prototype.bitLength = function () { if (this.t <= 0) { return 0 } return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)) }; BigInteger.prototype.mod = function (a) { var r = nbi(); this.abs().divRemTo(a, null, r); if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) { a.subTo(r, r) } return r }; BigInteger.prototype.modPowInt = function (e, m) { var z; if (e < 256 || m.isEven()) { z = new Classic(m) } else { z = new Montgomery(m) } return this.exp(e, z) }; BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r }; BigInteger.prototype.intValue = function () { if (this.s < 0) { if (this.t == 1) { return this[0] - this.DV } else if (this.t == 0) { return -1 } } else if (this.t == 1) { return this[0] } else if (this.t == 0) { return 0 } return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0] }; BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24 }; BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16 }; BigInteger.prototype.signum = function () { if (this.s < 0) { return -1 } else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) { return 0 } else { return 1 } }; BigInteger.prototype.toByteArray = function () { var i = this.t; var r = []; r[0] = this.s; var p = this.DB - (i * this.DB) % 8; var d; var k = 0; if (i-- > 0) { if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) { r[k++] = d | (this.s << (this.DB - p)) } while (i >= 0) { if (p < 8) { d = (this[i] & ((1 << p) - 1)) << (8 - p); d |= this[--i] >> (p += this.DB - 8) } else { d = (this[i] >> (p -= 8)) & 0xff; if (p <= 0) { p += this.DB; --i } } if ((d & 0x80) != 0) { d |= -256 } if (k == 0 && (this.s & 0x80) != (d & 0x80)) { ++k } if (k > 0 || d != this.s) { r[k++] = d } } } return r }; BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0) }; BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a }; BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a }; BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r }; BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r }; BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r }; BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r }; BigInteger.prototype.not = function () { var r = nbi(); for (var i = 0; i < this.t; ++i) { r[i] = this.DM & ~this[i] } r.t = this.t; r.s = ~this.s; return r }; BigInteger.prototype.shiftLeft = function (n) { var r = nbi(); if (n < 0) { this.rShiftTo(-n, r) } else { this.lShiftTo(n, r) } return r }; BigInteger.prototype.shiftRight = function (n) { var r = nbi(); if (n < 0) { this.lShiftTo(-n, r) } else { this.rShiftTo(n, r) } return r }; BigInteger.prototype.getLowestSetBit = function () { for (var i = 0; i < this.t; ++i) { if (this[i] != 0) { return i * this.DB + lbit(this[i]) } } if (this.s < 0) { return this.t * this.DB } return -1 }; BigInteger.prototype.bitCount = function () { var r = 0; var x = this.s & this.DM; for (var i = 0; i < this.t; ++i) { r += cbit(this[i] ^ x) } return r }; BigInteger.prototype.testBit = function (n) { var j = Math.floor(n / this.DB); if (j >= this.t) { return (this.s != 0) } return ((this[j] & (1 << (n % this.DB))) != 0) }; BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or) }; BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot) }; BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor) }; BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r }; BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r }; BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r }; BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r }; BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r }; BigInteger.prototype.divideAndRemainder = function (a) { var q = nbi(); var r = nbi(); this.divRemTo(a, q, r); return [q, r] }; BigInteger.prototype.modPow = function (e, m) { var i = e.bitLength(); var k; var r = nbv(1); var z; if (i <= 0) { return r } else if (i < 18) { k = 1 } else if (i < 48) { k = 3 } else if (i < 144) { k = 4 } else if (i < 768) { k = 5 } else { k = 6 } if (i < 8) { z = new Classic(m) } else if (m.isEven()) { z = new Barrett(m) } else { z = new Montgomery(m) } var g = []; var n = 3; var k1 = k - 1; var km = (1 << k) - 1; g[1] = z.convert(this); if (k > 1) { var g2 = nbi(); z.sqrTo(g[1], g2); while (n <= km) { g[n] = nbi(); z.mulTo(g2, g[n - 2], g[n]); n += 2 } } var j = e.t - 1; var w; var is1 = true; var r2 = nbi(); var t; i = nbits(e[j]) - 1; while (j >= 0) { if (i >= k1) { w = (e[j] >> (i - k1)) & km } else { w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); if (j > 0) { w |= e[j - 1] >> (this.DB + i - k1) } } n = k; while ((w & 1) == 0) { w >>= 1; --n } if ((i -= n) < 0) { i += this.DB; --j } if (is1) { g[w].copyTo(r); is1 = false } else { while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2 } if (n > 0) { z.sqrTo(r, r2) } else { t = r; r = r2; r2 = t } z.mulTo(r2, g[w], r) } while (j >= 0 && (e[j] & (1 << i)) == 0) { z.sqrTo(r, r2); t = r; r = r2; r2 = t; if (--i < 0) { i = this.DB - 1; --j } } } return z.revert(r) }; BigInteger.prototype.modInverse = function (m) { var ac = m.isEven(); if ((this.isEven() && ac) || m.signum() == 0) { return BigInteger.ZERO } var u = m.clone(); var v = this.clone(); var a = nbv(1); var b = nbv(0); var c = nbv(0); var d = nbv(1); while (u.signum() != 0) { while (u.isEven()) { u.rShiftTo(1, u); if (ac) { if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b) } a.rShiftTo(1, a) } else if (!b.isEven()) { b.subTo(m, b) } b.rShiftTo(1, b) } while (v.isEven()) { v.rShiftTo(1, v); if (ac) { if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d) } c.rShiftTo(1, c) } else if (!d.isEven()) { d.subTo(m, d) } d.rShiftTo(1, d) } if (u.compareTo(v) >= 0) { u.subTo(v, u); if (ac) { a.subTo(c, a) } b.subTo(d, b) } else { v.subTo(u, v); if (ac) { c.subTo(a, c) } d.subTo(b, d) } } if (v.compareTo(BigInteger.ONE) != 0) { return BigInteger.ZERO } if (d.compareTo(m) >= 0) { return d.subtract(m) } if (d.signum() < 0) { d.addTo(m, d) } else { return d } if (d.signum() < 0) { return d.add(m) } else { return d } }; BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()) }; BigInteger.prototype.gcd = function (a) { var x = (this.s < 0) ? this.negate() : this.clone(); var y = (a.s < 0) ? a.negate() : a.clone(); if (x.compareTo(y) < 0) { var t = x; x = y; y = t } var i = x.getLowestSetBit(); var g = y.getLowestSetBit(); if (g < 0) { return x } if (i < g) { g = i } if (g > 0) { x.rShiftTo(g, x); y.rShiftTo(g, y) } while (x.signum() > 0) { if ((i = x.getLowestSetBit()) > 0) { x.rShiftTo(i, x) } if ((i = y.getLowestSetBit()) > 0) { y.rShiftTo(i, y) } if (x.compareTo(y) >= 0) { x.subTo(y, x); x.rShiftTo(1, x) } else { y.subTo(x, y); y.rShiftTo(1, y) } } if (g > 0) { y.lShiftTo(g, y) } return y }; BigInteger.prototype.isProbablePrime = function (t) { var i; var x = this.abs(); if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { for (i = 0; i < lowprimes.length; ++i) { if (x[0] == lowprimes[i]) { return true } } return false } if (x.isEven()) { return false } i = 1; while (i < lowprimes.length) { var m = lowprimes[i]; var j = i + 1; while (j < lowprimes.length && m < lplim) { m *= lowprimes[j++] } m = x.modInt(m); while (i < j) { if (m % lowprimes[i++] == 0) { return false } } } return x.millerRabin(t) }; BigInteger.prototype.copyTo = function (r) { for (var i = this.t - 1; i >= 0; --i) { r[i] = this[i] } r.t = this.t; r.s = this.s }; BigInteger.prototype.fromInt = function (x) { this.t = 1; this.s = (x < 0) ? -1 : 0; if (x > 0) { this[0] = x } else if (x < -1) { this[0] = x + this.DV } else { this.t = 0 } }; BigInteger.prototype.fromString = function (s, b) { var k; if (b == 16) { k = 4 } else if (b == 8) { k = 3 } else if (b == 256) { k = 8 } else if (b == 2) { k = 1 } else if (b == 32) { k = 5 } else if (b == 4) { k = 2 } else { this.fromRadix(s, b); return } this.t = 0; this.s = 0; var i = s.length; var mi = false; var sh = 0; while (--i >= 0) { var x = (k == 8) ? (+s[i]) & 0xff : intAt(s, i); if (x < 0) { if (s.charAt(i) == "-") { mi = true } continue } mi = false; if (sh == 0) { this[this.t++] = x } else if (sh + k > this.DB) { this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; this[this.t++] = (x >> (this.DB - sh)) } else { this[this.t - 1] |= x << sh } sh += k; if (sh >= this.DB) { sh -= this.DB } } if (k == 8 && ((+s[0]) & 0x80) != 0) { this.s = -1; if (sh > 0) { this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh } } this.clamp(); if (mi) { BigInteger.ZERO.subTo(this, this) } }; BigInteger.prototype.clamp = function () { var c = this.s & this.DM; while (this.t > 0 && this[this.t - 1] == c) { --this.t } }; BigInteger.prototype.dlShiftTo = function (n, r) { var i; for (i = this.t - 1; i >= 0; --i) { r[i + n] = this[i] } for (i = n - 1; i >= 0; --i) { r[i] = 0 } r.t = this.t + n; r.s = this.s }; BigInteger.prototype.drShiftTo = function (n, r) { for (var i = n; i < this.t; ++i) { r[i - n] = this[i] } r.t = Math.max(this.t - n, 0); r.s = this.s }; BigInteger.prototype.lShiftTo = function (n, r) { var bs = n % this.DB; var cbs = this.DB - bs; var bm = (1 << cbs) - 1; var ds = Math.floor(n / this.DB); var c = (this.s << bs) & this.DM; for (var i = this.t - 1; i >= 0; --i) { r[i + ds + 1] = (this[i] >> cbs) | c; c = (this[i] & bm) << bs } for (var i = ds - 1; i >= 0; --i) { r[i] = 0 } r[ds] = c; r.t = this.t + ds + 1; r.s = this.s; r.clamp() }; BigInteger.prototype.rShiftTo = function (n, r) { r.s = this.s; var ds = Math.floor(n / this.DB); if (ds >= this.t) { r.t = 0; return } var bs = n % this.DB; var cbs = this.DB - bs; var bm = (1 << bs) - 1; r[0] = this[ds] >> bs; for (var i = ds + 1; i < this.t; ++i) { r[i - ds - 1] |= (this[i] & bm) << cbs; r[i - ds] = this[i] >> bs } if (bs > 0) { r[this.t - ds - 1] |= (this.s & bm) << cbs } r.t = this.t - ds; r.clamp() }; BigInteger.prototype.subTo = function (a, r) { var i = 0; var c = 0; var m = Math.min(a.t, this.t); while (i < m) { c += this[i] - a[i]; r[i++] = c & this.DM; c >>= this.DB } if (a.t < this.t) { c -= a.s; while (i < this.t) { c += this[i]; r[i++] = c & this.DM; c >>= this.DB } c += this.s } else { c += this.s; while (i < a.t) { c -= a[i]; r[i++] = c & this.DM; c >>= this.DB } c -= a.s } r.s = (c < 0) ? -1 : 0; if (c < -1) { r[i++] = this.DV + c } else if (c > 0) { r[i++] = c } r.t = i; r.clamp() }; BigInteger.prototype.multiplyTo = function (a, r) { var x = this.abs(); var y = a.abs(); var i = x.t; r.t = i + y.t; while (--i >= 0) { r[i] = 0 } for (i = 0; i < y.t; ++i) { r[i + x.t] = x.am(0, y[i], r, i, 0, x.t) } r.s = 0; r.clamp(); if (this.s != a.s) { BigInteger.ZERO.subTo(r, r) } }; BigInteger.prototype.squareTo = function (r) { var x = this.abs(); var i = r.t = 2 * x.t; while (--i >= 0) { r[i] = 0 } for (i = 0; i < x.t - 1; ++i) { var c = x.am(i, x[i], r, 2 * i, 0, 1); if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { r[i + x.t] -= x.DV; r[i + x.t + 1] = 1 } } if (r.t > 0) { r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1) } r.s = 0; r.clamp() }; BigInteger.prototype.divRemTo = function (m, q, r) { var pm = m.abs(); if (pm.t <= 0) { return } var pt = this.abs(); if (pt.t < pm.t) { if (q != null) { q.fromInt(0) } if (r != null) { this.copyTo(r) } return } if (r == null) { r = nbi() } var y = nbi(); var ts = this.s; var ms = m.s; var nsh = this.DB - nbits(pm[pm.t - 1]); if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r) } else { pm.copyTo(y); pt.copyTo(r) } var ys = y.t; var y0 = y[ys - 1]; if (y0 == 0) { return } var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); var d1 = this.FV / yt; var d2 = (1 << this.F1) / yt; var e = 1 << this.F2; var i = r.t; var j = i - ys; var t = (q == null) ? nbi() : q; y.dlShiftTo(j, t); if (r.compareTo(t) >= 0) { r[r.t++] = 1; r.subTo(t, r) } BigInteger.ONE.dlShiftTo(ys, t); t.subTo(y, y); while (y.t < ys) { y[y.t++] = 0 } while (--j >= 0) { var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { y.dlShiftTo(j, t); r.subTo(t, r); while (r[i] < --qd) { r.subTo(t, r) } } } if (q != null) { r.drShiftTo(ys, q); if (ts != ms) { BigInteger.ZERO.subTo(q, q) } } r.t = ys; r.clamp(); if (nsh > 0) { r.rShiftTo(nsh, r) } if (ts < 0) { BigInteger.ZERO.subTo(r, r) } }; BigInteger.prototype.invDigit = function () { if (this.t < 1) { return 0 } var x = this[0]; if ((x & 1) == 0) { return 0 } var y = x & 3; y = (y * (2 - (x & 0xf) * y)) & 0xf; y = (y * (2 - (x & 0xff) * y)) & 0xff; y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; y = (y * (2 - x * y % this.DV)) % this.DV; return (y > 0) ? this.DV - y : -y }; BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0 }; BigInteger.prototype.exp = function (e, z) { if (e > 0xffffffff || e < 1) { return BigInteger.ONE } var r = nbi(); var r2 = nbi(); var g = z.convert(this); var i = nbits(e) - 1; g.copyTo(r); while (--i >= 0) { z.sqrTo(r, r2); if ((e & (1 << i)) > 0) { z.mulTo(r2, g, r) } else { var t = r; r = r2; r2 = t } } return z.revert(r) }; BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)) }; BigInteger.prototype.toRadix = function (b) { if (b == null) { b = 10 } if (this.signum() == 0 || b < 2 || b > 36) { return "0" } var cs = this.chunkSize(b); var a = Math.pow(b, cs); var d = nbv(a); var y = nbi(); var z = nbi(); var r = ""; this.divRemTo(d, y, z); while (y.signum() > 0) { r = (a + z.intValue()).toString(b).substr(1) + r; y.divRemTo(d, y, z) } return z.intValue().toString(b) + r }; BigInteger.prototype.fromRadix = function (s, b) { this.fromInt(0); if (b == null) { b = 10 } var cs = this.chunkSize(b); var d = Math.pow(b, cs); var mi = false; var j = 0; var w = 0; for (var i = 0; i < s.length; ++i) { var x = intAt(s, i); if (x < 0) { if (s.charAt(i) == "-" && this.signum() == 0) { mi = true } continue } w = b * w + x; if (++j >= cs) { this.dMultiply(d); this.dAddOffset(w, 0); j = 0; w = 0 } } if (j > 0) { this.dMultiply(Math.pow(b, j)); this.dAddOffset(w, 0) } if (mi) { BigInteger.ZERO.subTo(this, this) } }; BigInteger.prototype.fromNumber = function (a, b, c) { if ("number" == typeof b) { if (a < 2) { this.fromInt(1) } else { this.fromNumber(a, c); if (!this.testBit(a - 1)) { this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this) } if (this.isEven()) { this.dAddOffset(1, 0) } while (!this.isProbablePrime(b)) { this.dAddOffset(2, 0); if (this.bitLength() > a) { this.subTo(BigInteger.ONE.shiftLeft(a - 1), this) } } } } else { var x = []; var t = a & 7; x.length = (a >> 3) + 1; b.nextBytes(x); if (t > 0) { x[0] &= ((1 << t) - 1) } else { x[0] = 0 } this.fromString(x, 256) } }; BigInteger.prototype.bitwiseTo = function (a, op, r) { var i; var f; var m = Math.min(a.t, this.t); for (i = 0; i < m; ++i) { r[i] = op(this[i], a[i]) } if (a.t < this.t) { f = a.s & this.DM; for (i = m; i < this.t; ++i) { r[i] = op(this[i], f) } r.t = this.t } else { f = this.s & this.DM; for (i = m; i < a.t; ++i) { r[i] = op(f, a[i]) } r.t = a.t } r.s = op(this.s, a.s); r.clamp() }; BigInteger.prototype.changeBit = function (n, op) { var r = BigInteger.ONE.shiftLeft(n); this.bitwiseTo(r, op, r); return r }; BigInteger.prototype.addTo = function (a, r) { var i = 0; var c = 0; var m = Math.min(a.t, this.t); while (i < m) { c += this[i] + a[i]; r[i++] = c & this.DM; c >>= this.DB } if (a.t < this.t) { c += a.s; while (i < this.t) { c += this[i]; r[i++] = c & this.DM; c >>= this.DB } c += this.s } else { c += this.s; while (i < a.t) { c += a[i]; r[i++] = c & this.DM; c >>= this.DB } c += a.s } r.s = (c < 0) ? -1 : 0; if (c > 0) { r[i++] = c } else if (c < -1) { r[i++] = this.DV + c } r.t = i; r.clamp() }; BigInteger.prototype.dMultiply = function (n) { this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); ++this.t; this.clamp() }; BigInteger.prototype.dAddOffset = function (n, w) { if (n == 0) { return } while (this.t <= w) { this[this.t++] = 0 } this[w] += n; while (this[w] >= this.DV) { this[w] -= this.DV; if (++w >= this.t) { this[this.t++] = 0 } ++this[w] } }; BigInteger.prototype.multiplyLowerTo = function (a, n, r) { var i = Math.min(this.t + a.t, n); r.s = 0; r.t = i; while (i > 0) { r[--i] = 0 } for (var j = r.t - this.t; i < j; ++i) { r[i + this.t] = this.am(0, a[i], r, i, 0, this.t) } for (var j = Math.min(a.t, n); i < j; ++i) { this.am(0, a[i], r, i, 0, n - i) } r.clamp() }; BigInteger.prototype.multiplyUpperTo = function (a, n, r) { --n; var i = r.t = this.t + a.t - n; r.s = 0; while (--i >= 0) { r[i] = 0 } for (i = Math.max(n - this.t, 0); i < a.t; ++i) { r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n) } r.clamp(); r.drShiftTo(1, r) }; BigInteger.prototype.modInt = function (n) { if (n <= 0) { return 0 } var d = this.DV % n; var r = (this.s < 0) ? n - 1 : 0; if (this.t > 0) { if (d == 0) { r = this[0] % n } else { for (var i = this.t - 1; i >= 0; --i) { r = (d * r + this[i]) % n } } } return r }; BigInteger.prototype.millerRabin = function (t) { var n1 = this.subtract(BigInteger.ONE); var k = n1.getLowestSetBit(); if (k <= 0) { return false } var r = n1.shiftRight(k); t = (t + 1) >> 1; if (t > lowprimes.length) { t = lowprimes.length } var a = nbi(); for (var i = 0; i < t; ++i) { a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]); var y = a.modPow(r, this); if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { var j = 1; while (j++ < k && y.compareTo(n1) != 0) { y = y.modPowInt(2, this); if (y.compareTo(BigInteger.ONE) == 0) { return false } } if (y.compareTo(n1) != 0) { return false } } } return true }; BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r }; BigInteger.prototype.gcda = function (a, callback) { var x = (this.s < 0) ? this.negate() : this.clone(); var y = (a.s < 0) ? a.negate() : a.clone(); if (x.compareTo(y) < 0) { var t = x; x = y; y = t } var i = x.getLowestSetBit(); var g = y.getLowestSetBit(); if (g < 0) { callback(x); return } if (i < g) { g = i } if (g > 0) { x.rShiftTo(g, x); y.rShiftTo(g, y) } var gcda1 = function () { if ((i = x.getLowestSetBit()) > 0) { x.rShiftTo(i, x) } if ((i = y.getLowestSetBit()) > 0) { y.rShiftTo(i, y) } if (x.compareTo(y) >= 0) { x.subTo(y, x); x.rShiftTo(1, x) } else { y.subTo(x, y); y.rShiftTo(1, y) } if (!(x.signum() > 0)) { if (g > 0) { y.lShiftTo(g, y) } setTimeout(function () { callback(y) }, 0) } else { setTimeout(gcda1, 0) } }; setTimeout(gcda1, 10) }; BigInteger.prototype.fromNumberAsync = function (a, b, c, callback) { if ("number" == typeof b) { if (a < 2) { this.fromInt(1) } else { this.fromNumber(a, c); if (!this.testBit(a - 1)) { this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this) } if (this.isEven()) { this.dAddOffset(1, 0) } var bnp_1 = this; var bnpfn1_1 = function () { bnp_1.dAddOffset(2, 0); if (bnp_1.bitLength() > a) { bnp_1.subTo(BigInteger.ONE.shiftLeft(a - 1), bnp_1) } if (bnp_1.isProbablePrime(b)) { setTimeout(function () { callback() }, 0) } else { setTimeout(bnpfn1_1, 0) } }; setTimeout(bnpfn1_1, 0) } } else { var x = []; var t = a & 7; x.length = (a >> 3) + 1; b.nextBytes(x); if (t > 0) { x[0] &= ((1 << t) - 1) } else { x[0] = 0 } this.fromString(x, 256) } }; return BigInteger }()); var NullExp = (function () { function NullExp() { } NullExp.prototype.convert = function (x) { return x }; NullExp.prototype.revert = function (x) { return x }; NullExp.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r) }; NullExp.prototype.sqrTo = function (x, r) { x.squareTo(r) }; return NullExp }()); var Classic = (function () { function Classic(m) { this.m = m } Classic.prototype.convert = function (x) { if (x.s < 0 || x.compareTo(this.m) >= 0) { return x.mod(this.m) } else { return x } }; Classic.prototype.revert = function (x) { return x }; Classic.prototype.reduce = function (x) { x.divRemTo(this.m, null, x) }; Classic.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r) }; Classic.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r) }; return Classic }()); var Montgomery = (function () { function Montgomery(m) { this.m = m; this.mp = m.invDigit(); this.mpl = this.mp & 0x7fff; this.mph = this.mp >> 15; this.um = (1 << (m.DB - 15)) - 1; this.mt2 = 2 * m.t } Montgomery.prototype.convert = function (x) { var r = nbi(); x.abs().dlShiftTo(this.m.t, r); r.divRemTo(this.m, null, r); if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) { this.m.subTo(r, r) } return r }; Montgomery.prototype.revert = function (x) { var r = nbi(); x.copyTo(r); this.reduce(r); return r }; Montgomery.prototype.reduce = function (x) { while (x.t <= this.mt2) { x[x.t++] = 0 } for (var i = 0; i < this.m.t; ++i) { var j = x[i] & 0x7fff; var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; j = i + this.m.t; x[j] += this.m.am(0, u0, x, i, 0, this.m.t); while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++ } } x.clamp(); x.drShiftTo(this.m.t, x); if (x.compareTo(this.m) >= 0) { x.subTo(this.m, x) } }; Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r) }; Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r) }; return Montgomery }()); var Barrett = (function () { function Barrett(m) { this.m = m; this.r2 = nbi(); this.q3 = nbi(); BigInteger.ONE.dlShiftTo(2 * m.t, this.r2); this.mu = this.r2.divide(m) } Barrett.prototype.convert = function (x) { if (x.s < 0 || x.t > 2 * this.m.t) { return x.mod(this.m) } else if (x.compareTo(this.m) < 0) { return x } else { var r = nbi(); x.copyTo(r); this.reduce(r); return r } }; Barrett.prototype.revert = function (x) { return x }; Barrett.prototype.reduce = function (x) { x.drShiftTo(this.m.t - 1, this.r2); if (x.t > this.m.t + 1) { x.t = this.m.t + 1; x.clamp() } this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3); this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); while (x.compareTo(this.r2) < 0) { x.dAddOffset(1, this.m.t + 1) } x.subTo(this.r2, x); while (x.compareTo(this.m) >= 0) { x.subTo(this.m, x) } }; Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r) }; Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r) }; return Barrett }()); function nbi() { return new BigInteger(null) } function parseBigInt(str, r) { return new BigInteger(str, r) } function am1(i, x, w, j, c, n) { while (--n >= 0) { var v = x * this[i++] + w[j] + c; c = Math.floor(v / 0x4000000); w[j++] = v & 0x3ffffff } return c } function am2(i, x, w, j, c, n) { var xl = x & 0x7fff; var xh = x >> 15; while (--n >= 0) { var l = this[i] & 0x7fff; var h = this[i++] >> 15; var m = xh * l + h * xl; l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); w[j++] = l & 0x3fffffff } return c } function am3(i, x, w, j, c, n) { var xl = x & 0x3fff; var xh = x >> 14; while (--n >= 0) { var l = this[i] & 0x3fff; var h = this[i++] >> 14; var m = xh * l + h * xl; l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; c = (l >> 28) + (m >> 14) + xh * h; w[j++] = l & 0xfffffff } return c } if (j_lm && (navigator2.appName == "Microsoft Internet Explorer")) { BigInteger.prototype.am = am2; dbits = 30 } else if (j_lm && (navigator2.appName != "Netscape")) { BigInteger.prototype.am = am1; dbits = 26 } else { BigInteger.prototype.am = am3; dbits = 28 } BigInteger.prototype.DB = dbits; BigInteger.prototype.DM = ((1 << dbits) - 1); BigInteger.prototype.DV = (1 << dbits); var BI_FP = 52; BigInteger.prototype.FV = Math.pow(2, BI_FP); BigInteger.prototype.F1 = BI_FP - dbits; BigInteger.prototype.F2 = 2 * dbits - BI_FP; var BI_RC = []; var rr; var vv; rr = "0".charCodeAt(0); for (vv = 0; vv <= 9; ++vv) { BI_RC[rr++] = vv } rr = "a".charCodeAt(0); for (vv = 10; vv < 36; ++vv) { BI_RC[rr++] = vv } rr = "A".charCodeAt(0); for (vv = 10; vv < 36; ++vv) { BI_RC[rr++] = vv } function intAt(s, i) { var c = BI_RC[s.charCodeAt(i)]; return (c == null) ? -1 : c } function nbv(i) { var r = nbi(); r.fromInt(i); return r } function nbits(x) { var r = 1; var t; if ((t = x >>> 16) != 0) { x = t; r += 16 } if ((t = x >> 8) != 0) { x = t; r += 8 } if ((t = x >> 4) != 0) { x = t; r += 4 } if ((t = x >> 2) != 0) { x = t; r += 2 } if ((t = x >> 1) != 0) { x = t; r += 1 } return r } BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); var Arcfour = (function () { function Arcfour() { this.i = 0; this.j = 0; this.S = [] } Arcfour.prototype.init = function (key) { var i; var j; var t; for (i = 0; i < 256; ++i) { this.S[i] = i } j = 0; for (i = 0; i < 256; ++i) { j = (j + this.S[i] + key[i % key.length]) & 255; t = this.S[i]; this.S[i] = this.S[j]; this.S[j] = t } this.i = 0; this.j = 0 }; Arcfour.prototype.next = function () { var t; this.i = (this.i + 1) & 255; this.j = (this.j + this.S[this.i]) & 255; t = this.S[this.i]; this.S[this.i] = this.S[this.j]; this.S[this.j] = t; return this.S[(t + this.S[this.i]) & 255] }; return Arcfour }()); function prng_newstate() { return new Arcfour() } var rng_psize = 256; var rng_state; var rng_pool = null; var rng_pptr; if (rng_pool == null) { rng_pool = []; rng_pptr = 0; var t = void 0; if (window2.crypto && window2.crypto.getRandomValues) { var z = new Uint32Array(256); window2.crypto.getRandomValues(z); for (t = 0; t < z.length; ++t) { rng_pool[rng_pptr++] = z[t] & 255 } } var onMouseMoveListener_1 = function (ev) { this.count = this.count || 0; if (this.count >= 256 || rng_pptr >= rng_psize) { if (window2.removeEventListener) { window2.removeEventListener("mousemove", onMouseMoveListener_1, false) } else if (window2.detachEvent) { window2.detachEvent("onmousemove", onMouseMoveListener_1) } return } try { var mouseCoordinates = ev.x + ev.y; rng_pool[rng_pptr++] = mouseCoordinates & 255; this.count += 1 } catch (e) { } }; if (window2.addEventListener) { window2.addEventListener("mousemove", onMouseMoveListener_1, false) } else if (window2.attachEvent) { window2.attachEvent("onmousemove", onMouseMoveListener_1) } } function rng_get_byte() { if (rng_state == null) { rng_state = prng_newstate(); while (rng_pptr < rng_psize) { var random = Math.floor(65536 * Math.random()); rng_pool[rng_pptr++] = random & 255 } rng_state.init(rng_pool); for (rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) { rng_pool[rng_pptr] = 0 } rng_pptr = 0 } return rng_state.next() } var SecureRandom = (function () { function SecureRandom() { } SecureRandom.prototype.nextBytes = function (ba) { for (var i = 0; i < ba.length; ++i) { ba[i] = rng_get_byte() } }; return SecureRandom }()); function pkcs1pad1(s, n) { if (n < s.length + 22) { console.error("Message too long for RSA"); return null } var len = n - s.length - 6; var filler = ""; for (var f = 0; f < len; f += 2) { filler += "ff" } var m = "0001" + filler + "00" + s; return parseBigInt(m, 16) } function pkcs1pad2(s, n) { if (n < s.length + 11) { console.error("Message too long for RSA"); return null } var ba = []; var i = s.length - 1; while (i >= 0 && n > 0) { var c = s.charCodeAt(i--); if (c < 128) { ba[--n] = c } else if ((c > 127) && (c < 2048)) { ba[--n] = (c & 63) | 128; ba[--n] = (c >> 6) | 192 } else { ba[--n] = (c & 63) | 128; ba[--n] = ((c >> 6) & 63) | 128; ba[--n] = (c >> 12) | 224 } } ba[--n] = 0; var rng = new SecureRandom(); var x = []; while (n > 2) { x[0] = 0; while (x[0] == 0) { rng.nextBytes(x) } ba[--n] = x[0] } ba[--n] = 2; ba[--n] = 0; return new BigInteger(ba) } var RSAKey = (function () { function RSAKey() { this.n = null; this.e = 0; this.d = null; this.p = null; this.q = null; this.dmp1 = null; this.dmq1 = null; this.coeff = null } RSAKey.prototype.doPublic = function (x) { return x.modPowInt(this.e, this.n) }; RSAKey.prototype.doPrivate = function (x) { if (this.p == null || this.q == null) { return x.modPow(this.d, this.n) } var xp = x.mod(this.p).modPow(this.dmp1, this.p); var xq = x.mod(this.q).modPow(this.dmq1, this.q); while (xp.compareTo(xq) < 0) { xp = xp.add(this.p) } return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) }; RSAKey.prototype.setPublic = function (N, E) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16) } else { console.error("Invalid RSA public key") } }; RSAKey.prototype.encrypt = function (text) { var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3); if (m == null) { return null } var c = this.doPublic(m); if (c == null) { return null } var h = c.toString(16); if ((h.length & 1) == 0) { return h } else { return "0" + h } }; RSAKey.prototype.setPrivate = function (N, E, D) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16); this.d = parseBigInt(D, 16) } else { console.error("Invalid RSA private key") } }; RSAKey.prototype.setPrivateEx = function (N, E, D, P, Q, DP, DQ, C) { if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N, 16); this.e = parseInt(E, 16); this.d = parseBigInt(D, 16); this.p = parseBigInt(P, 16); this.q = parseBigInt(Q, 16); this.dmp1 = parseBigInt(DP, 16); this.dmq1 = parseBigInt(DQ, 16); this.coeff = parseBigInt(C, 16) } else { console.error("Invalid RSA private key") } }; RSAKey.prototype.generate = function (B, E) { var rng = new SecureRandom(); var qs = B >> 1; this.e = parseInt(E, 16); var ee = new BigInteger(E, 16); for (; ;) { for (; ;) { this.p = new BigInteger(B - qs, 1, rng); if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) { break } } for (; ;) { this.q = new BigInteger(qs, 1, rng); if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) { break } } if (this.p.compareTo(this.q) <= 0) { var t = this.p; this.p = this.q; this.q = t } var p1 = this.p.subtract(BigInteger.ONE); var q1 = this.q.subtract(BigInteger.ONE); var phi = p1.multiply(q1); if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { this.n = this.p.multiply(this.q); this.d = ee.modInverse(phi); this.dmp1 = this.d.mod(p1); this.dmq1 = this.d.mod(q1); this.coeff = this.q.modInverse(this.p); break } } }; RSAKey.prototype.decrypt = function (ctext) { var c = parseBigInt(ctext, 16); var m = this.doPrivate(c); if (m == null) { return null } return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3) }; RSAKey.prototype.generateAsync = function (B, E, callback) { var rng = new SecureRandom(); var qs = B >> 1; this.e = parseInt(E, 16); var ee = new BigInteger(E, 16); var rsa = this; var loop1 = function () { var loop4 = function () { if (rsa.p.compareTo(rsa.q) <= 0) { var t = rsa.p; rsa.p = rsa.q; rsa.q = t } var p1 = rsa.p.subtract(BigInteger.ONE); var q1 = rsa.q.subtract(BigInteger.ONE); var phi = p1.multiply(q1); if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { rsa.n = rsa.p.multiply(rsa.q); rsa.d = ee.modInverse(phi); rsa.dmp1 = rsa.d.mod(p1); rsa.dmq1 = rsa.d.mod(q1); rsa.coeff = rsa.q.modInverse(rsa.p); setTimeout(function () { callback() }, 0) } else { setTimeout(loop1, 0) } }; var loop3 = function () { rsa.q = nbi(); rsa.q.fromNumberAsync(qs, 1, rng, function () { rsa.q.subtract(BigInteger.ONE).gcda(ee, function (r) { if (r.compareTo(BigInteger.ONE) == 0 && rsa.q.isProbablePrime(10)) { setTimeout(loop4, 0) } else { setTimeout(loop3, 0) } }) }) }; var loop2 = function () { rsa.p = nbi(); rsa.p.fromNumberAsync(B - qs, 1, rng, function () { rsa.p.subtract(BigInteger.ONE).gcda(ee, function (r) { if (r.compareTo(BigInteger.ONE) == 0 && rsa.p.isProbablePrime(10)) { setTimeout(loop3, 0) } else { setTimeout(loop2, 0) } }) }) }; setTimeout(loop2, 0) }; setTimeout(loop1, 0) }; RSAKey.prototype.sign = function (text, digestMethod, digestName) { var header = getDigestHeader(digestName); var digest = header + digestMethod(text).toString(); var m = pkcs1pad1(digest, this.n.bitLength() / 4); if (m == null) { return null } var c = this.doPrivate(m); if (c == null) { return null } var h = c.toString(16); if ((h.length & 1) == 0) { return h } else { return "0" + h } }; RSAKey.prototype.verify = function (text, signature, digestMethod) { var c = parseBigInt(signature, 16); var m = this.doPublic(c); if (m == null) { return null } var unpadded = m.toString(16).replace(/^1f+00/, ""); var digest = removeDigestHeader(unpadded); return digest == digestMethod(text).toString() }; return RSAKey }()); function pkcs1unpad2(d, n) { var b = d.toByteArray(); var i = 0; while (i < b.length && b[i] == 0) { ++i } if (b.length - i != n - 1 || b[i] != 2) { return null } ++i; while (b[i] != 0) { if (++i >= b.length) { return null } } var ret = ""; while (++i < b.length) { var c = b[i] & 255; if (c < 128) { ret += String.fromCharCode(c) } else if ((c > 191) && (c < 224)) { ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); ++i } else { ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); i += 2 } } return ret } var DIGEST_HEADERS = { md2: "3020300c06082a864886f70d020205000410", md5: "3020300c06082a864886f70d020505000410", sha1: "3021300906052b0e03021a05000414", sha224: "302d300d06096086480165030402040500041c", sha256: "3031300d060960864801650304020105000420", sha384: "3041300d060960864801650304020205000430", sha512: "3051300d060960864801650304020305000440", ripemd160: "3021300906052b2403020105000414", }; function getDigestHeader(name) { return DIGEST_HEADERS[name] || "" } function removeDigestHeader(str) { for (var name_1 in DIGEST_HEADERS) { if (DIGEST_HEADERS.hasOwnProperty(name_1)) { var header = DIGEST_HEADERS[name_1]; var len = header.length; if (str.substr(0, len) == header) { return str.substr(len) } } } return str } var YAHOO = {}; YAHOO.lang = { extend: function (subc, superc, overrides) { if (!superc || !subc) { throw new Error("YAHOO.lang.extend failed, please check that all dependencies are included."); } var F = function () { }; F.prototype = superc.prototype; subc.prototype = new F(); subc.prototype.constructor = subc; subc.superclass = superc.prototype; if (superc.prototype.constructor == Object.prototype.constructor) { superc.prototype.constructor = superc } if (overrides) { var i; for (i in overrides) { subc.prototype[i] = overrides[i] } var _IEEnumFix = function () { }, ADD = ["toString", "valueOf"]; try { if (/MSIE/.test(navigator2.userAgent)) { _IEEnumFix = function (r, s) { for (i = 0; i < ADD.length; i = i + 1) { var fname = ADD[i], f = s[fname]; if (typeof f === 'function' && f != Object.prototype[fname]) { r[fname] = f } } } } } catch (ex) { } _IEEnumFix(subc.prototype, overrides) } } }; var KJUR = {}; if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) KJUR.asn1 = {}; KJUR.asn1.ASN1Util = new function () { this.integerToByteHex = function (i) { var h = i.toString(16); if ((h.length % 2) == 1) h = '0' + h; return h }; this.bigIntToMinTwosComplementsHex = function (bigIntegerValue) { var h = bigIntegerValue.toString(16); if (h.substr(0, 1) != '-') { if (h.length % 2 == 1) { h = '0' + h } else { if (!h.match(/^[0-7]/)) { h = '00' + h } } } else { var hPos = h.substr(1); var xorLen = hPos.length; if (xorLen % 2 == 1) { xorLen += 1 } else { if (!h.match(/^[0-7]/)) { xorLen += 2 } } var hMask = ''; for (var i = 0; i < xorLen; i++) { hMask += 'f' } var biMask = new BigInteger(hMask, 16); var biNeg = biMask.xor(bigIntegerValue).add(BigInteger.ONE); h = biNeg.toString(16).replace(/^-/, '') } return h }; this.getPEMStringFromHex = function (dataHex, pemHeader) { return hextopem(dataHex, pemHeader) }; this.newObject = function (param) { var _KJUR = KJUR, _KJUR_asn1 = _KJUR.asn1, _DERBoolean = _KJUR_asn1.DERBoolean, _DERInteger = _KJUR_asn1.DERInteger, _DERBitString = _KJUR_asn1.DERBitString, _DEROctetString = _KJUR_asn1.DEROctetString, _DERNull = _KJUR_asn1.DERNull, _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier, _DEREnumerated = _KJUR_asn1.DEREnumerated, _DERUTF8String = _KJUR_asn1.DERUTF8String, _DERNumericString = _KJUR_asn1.DERNumericString, _DERPrintableString = _KJUR_asn1.DERPrintableString, _DERTeletexString = _KJUR_asn1.DERTeletexString, _DERIA5String = _KJUR_asn1.DERIA5String, _DERUTCTime = _KJUR_asn1.DERUTCTime, _DERGeneralizedTime = _KJUR_asn1.DERGeneralizedTime, _DERSequence = _KJUR_asn1.DERSequence, _DERSet = _KJUR_asn1.DERSet, _DERTaggedObject = _KJUR_asn1.DERTaggedObject, _newObject = _KJUR_asn1.ASN1Util.newObject; var keys = Object.keys(param); if (keys.length != 1) throw "key of param shall be only one."; var key = keys[0]; if (":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:".indexOf(":" + key + ":") == -1) throw "undefined key: " + key; if (key == "bool") return new _DERBoolean(param[key]); if (key == "int") return new _DERInteger(param[key]); if (key == "bitstr") return new _DERBitString(param[key]); if (key == "octstr") return new _DEROctetString(param[key]); if (key == "null") return new _DERNull(param[key]); if (key == "oid") return new _DERObjectIdentifier(param[key]); if (key == "enum") return new _DEREnumerated(param[key]); if (key == "utf8str") return new _DERUTF8String(param[key]); if (key == "numstr") return new _DERNumericString(param[key]); if (key == "prnstr") return new _DERPrintableString(param[key]); if (key == "telstr") return new _DERTeletexString(param[key]); if (key == "ia5str") return new _DERIA5String(param[key]); if (key == "utctime") return new _DERUTCTime(param[key]); if (key == "gentime") return new _DERGeneralizedTime(param[key]); if (key == "seq") { var paramList = param[key]; var a = []; for (var i = 0; i < paramList.length; i++) { var asn1Obj = _newObject(paramList[i]); a.push(asn1Obj) } return new _DERSequence({ 'array': a }) } if (key == "set") { var paramList = param[key]; var a = []; for (var i = 0; i < paramList.length; i++) { var asn1Obj = _newObject(paramList[i]); a.push(asn1Obj) } return new _DERSet({ 'array': a }) } if (key == "tag") { var tagParam = param[key]; if (Object.prototype.toString.call(tagParam) === '[object Array]' && tagParam.length == 3) { var obj = _newObject(tagParam[2]); return new _DERTaggedObject({ tag: tagParam[0], explicit: tagParam[1], obj: obj }) } else { var newParam = {}; if (tagParam.explicit !== undefined) newParam.explicit = tagParam.explicit; if (tagParam.tag !== undefined) newParam.tag = tagParam.tag; if (tagParam.obj === undefined) throw "obj shall be specified for 'tag'."; newParam.obj = _newObject(tagParam.obj); return new _DERTaggedObject(newParam) } } }; this.jsonToASN1HEX = function (param) { var asn1Obj = this.newObject(param); return asn1Obj.getEncodedHex() } }; KJUR.asn1.ASN1Util.oidHexToInt = function (hex) { var s = ""; var i01 = parseInt(hex.substr(0, 2), 16); var i0 = Math.floor(i01 / 40); var i1 = i01 % 40; var s = i0 + "." + i1; var binbuf = ""; for (var i = 2; i < hex.length; i += 2) { var value = parseInt(hex.substr(i, 2), 16); var bin = ("00000000" + value.toString(2)).slice(-8); binbuf = binbuf + bin.substr(1, 7); if (bin.substr(0, 1) == "0") { var bi = new BigInteger(binbuf, 2); s = s + "." + bi.toString(10); binbuf = "" } } return s }; KJUR.asn1.ASN1Util.oidIntToHex = function (oidString) { var itox = function (i) { var h = i.toString(16); if (h.length == 1) h = '0' + h; return h }; var roidtox = function (roid) { var h = ''; var bi = new BigInteger(roid, 10); var b = bi.toString(2); var padLen = 7 - b.length % 7; if (padLen == 7) padLen = 0; var bPad = ''; for (var i = 0; i < padLen; i++)bPad += '0'; b = bPad + b; for (var i = 0; i < b.length - 1; i += 7) { var b8 = b.substr(i, 7); if (i != b.length - 7) b8 = '1' + b8; h += itox(parseInt(b8, 2)) } return h }; if (!oidString.match(/^[0-9.]+$/)) { throw "malformed oid string: " + oidString; } var h = ''; var a = oidString.split('.'); var i0 = parseInt(a[0]) * 40 + parseInt(a[1]); h += itox(i0); a.splice(0, 2); for (var i = 0; i < a.length; i++) { h += roidtox(a[i]) } return h }; KJUR.asn1.ASN1Object = function () { var hV = ''; this.getLengthHexFromValue = function () { if (typeof this.hV == "undefined" || this.hV == null) { throw "this.hV is null or undefined."; } if (this.hV.length % 2 == 1) { throw "value hex must be even length: n=" + hV.length + ",v=" + this.hV; } var n = this.hV.length / 2; var hN = n.toString(16); if (hN.length % 2 == 1) { hN = "0" + hN } if (n < 128) { return hN } else { var hNlen = hN.length / 2; if (hNlen > 15) { throw "ASN.1 length too long to represent by 8x: n = " + n.toString(16); } var head = 128 + hNlen; return head.toString(16) + hN } }; this.getEncodedHex = function () { if (this.hTLV == null || this.isModified) { this.hV = this.getFreshValueHex(); this.hL = this.getLengthHexFromValue(); this.hTLV = this.hT + this.hL + this.hV; this.isModified = false } return this.hTLV }; this.getValueHex = function () { this.getEncodedHex(); return this.hV }; this.getFreshValueHex = function () { return '' } }; KJUR.asn1.DERAbstractString = function (params) { KJUR.asn1.DERAbstractString.superclass.constructor.call(this); this.getString = function () { return this.s }; this.setString = function (newS) { this.hTLV = null; this.isModified = true; this.s = newS; this.hV = stohex(this.s) }; this.setStringHex = function (newHexString) { this.hTLV = null; this.isModified = true; this.s = null; this.hV = newHexString }; this.getFreshValueHex = function () { return this.hV }; if (typeof params != "undefined") { if (typeof params == "string") { this.setString(params) } else if (typeof params['str'] != "undefined") { this.setString(params['str']) } else if (typeof params['hex'] != "undefined") { this.setStringHex(params['hex']) } } }; YAHOO.lang.extend(KJUR.asn1.DERAbstractString, KJUR.asn1.ASN1Object); KJUR.asn1.DERAbstractTime = function (params) { KJUR.asn1.DERAbstractTime.superclass.constructor.call(this); this.localDateToUTC = function (d) { utc = d.getTime() + (d.getTimezoneOffset() * 60000); var utcDate = new Date(utc); return utcDate }; this.formatDate = function (dateObject, type, withMillis) { var pad = this.zeroPadding; var d = this.localDateToUTC(dateObject); var year = String(d.getFullYear()); if (type == 'utc') year = year.substr(2, 2); var month = pad(String(d.getMonth() + 1), 2); var day = pad(String(d.getDate()), 2); var hour = pad(String(d.getHours()), 2); var min = pad(String(d.getMinutes()), 2); var sec = pad(String(d.getSeconds()), 2); var s = year + month + day + hour + min + sec; if (withMillis === true) { var millis = d.getMilliseconds(); if (millis != 0) { var sMillis = pad(String(millis), 3); sMillis = sMillis.replace(/[0]+$/, ""); s = s + "." + sMillis } } return s + "Z" }; this.zeroPadding = function (s, len) { if (s.length >= len) return s; return new Array(len - s.length + 1).join('0') + s }; this.getString = function () { return this.s }; this.setString = function (newS) { this.hTLV = null; this.isModified = true; this.s = newS; this.hV = stohex(newS) }; this.setByDateValue = function (year, month, day, hour, min, sec) { var dateObject = new Date(Date.UTC(year, month - 1, day, hour, min, sec, 0)); this.setByDate(dateObject) }; this.getFreshValueHex = function () { return this.hV } }; YAHOO.lang.extend(KJUR.asn1.DERAbstractTime, KJUR.asn1.ASN1Object); KJUR.asn1.DERAbstractStructured = function (params) { KJUR.asn1.DERAbstractString.superclass.constructor.call(this); this.setByASN1ObjectArray = function (asn1ObjectArray) { this.hTLV = null; this.isModified = true; this.asn1Array = asn1ObjectArray }; this.appendASN1Object = function (asn1Object) { this.hTLV = null; this.isModified = true; this.asn1Array.push(asn1Object) }; this.asn1Array = new Array(); if (typeof params != "undefined") { if (typeof params['array'] != "undefined") { this.asn1Array = params['array'] } } }; YAHOO.lang.extend(KJUR.asn1.DERAbstractStructured, KJUR.asn1.ASN1Object); KJUR.asn1.DERBoolean = function () { KJUR.asn1.DERBoolean.superclass.constructor.call(this); this.hT = "01"; this.hTLV = "0101ff" }; YAHOO.lang.extend(KJUR.asn1.DERBoolean, KJUR.asn1.ASN1Object); KJUR.asn1.DERInteger = function (params) { KJUR.asn1.DERInteger.superclass.constructor.call(this); this.hT = "02"; this.setByBigInteger = function (bigIntegerValue) { this.hTLV = null; this.isModified = true; this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue) }; this.setByInteger = function (intValue) { var bi = new BigInteger(String(intValue), 10); this.setByBigInteger(bi) }; this.setValueHex = function (newHexString) { this.hV = newHexString }; this.getFreshValueHex = function () { return this.hV }; if (typeof params != "undefined") { if (typeof params['bigint'] != "undefined") { this.setByBigInteger(params['bigint']) } else if (typeof params['int'] != "undefined") { this.setByInteger(params['int']) } else if (typeof params == "number") { this.setByInteger(params) } else if (typeof params['hex'] != "undefined") { this.setValueHex(params['hex']) } } }; YAHOO.lang.extend(KJUR.asn1.DERInteger, KJUR.asn1.ASN1Object); KJUR.asn1.DERBitString = function (params) { if (params !== undefined && typeof params.obj !== "undefined") { var o = KJUR.asn1.ASN1Util.newObject(params.obj); params.hex = "00" + o.getEncodedHex() } KJUR.asn1.DERBitString.superclass.constructor.call(this); this.hT = "03"; this.setHexValueIncludingUnusedBits = function (newHexStringIncludingUnusedBits) { this.hTLV = null; this.isModified = true; this.hV = newHexStringIncludingUnusedBits }; this.setUnusedBitsAndHexValue = function (unusedBits, hValue) { if (unusedBits < 0 || 7 < unusedBits) { throw "unused bits shall be from 0 to 7: u = " + unusedBits; } var hUnusedBits = "0" + unusedBits; this.hTLV = null; this.isModified = true; this.hV = hUnusedBits + hValue }; this.setByBinaryString = function (binaryString) { binaryString = binaryString.replace(/0+$/, ''); var unusedBits = 8 - binaryString.length % 8; if (unusedBits == 8) unusedBits = 0; for (var i = 0; i <= unusedBits; i++) { binaryString += '0' } var h = ''; for (var i = 0; i < binaryString.length - 1; i += 8) { var b = binaryString.substr(i, 8); var x = parseInt(b, 2).toString(16); if (x.length == 1) x = '0' + x; h += x } this.hTLV = null; this.isModified = true; this.hV = '0' + unusedBits + h }; this.setByBooleanArray = function (booleanArray) { var s = ''; for (var i = 0; i < booleanArray.length; i++) { if (booleanArray[i] == true) { s += '1' } else { s += '0' } } this.setByBinaryString(s) }; this.newFalseArray = function (nLength) { var a = new Array(nLength); for (var i = 0; i < nLength; i++) { a[i] = false } return a }; this.getFreshValueHex = function () { return this.hV }; if (typeof params != "undefined") { if (typeof params == "string" && params.toLowerCase().match(/^[0-9a-f]+$/)) { this.setHexValueIncludingUnusedBits(params) } else if (typeof params['hex'] != "undefined") { this.setHexValueIncludingUnusedBits(params['hex']) } else if (typeof params['bin'] != "undefined") { this.setByBinaryString(params['bin']) } else if (typeof params['array'] != "undefined") { this.setByBooleanArray(params['array']) } } }; YAHOO.lang.extend(KJUR.asn1.DERBitString, KJUR.asn1.ASN1Object); KJUR.asn1.DEROctetString = function (params) { if (params !== undefined && typeof params.obj !== "undefined") { var o = KJUR.asn1.ASN1Util.newObject(params.obj); params.hex = o.getEncodedHex() } KJUR.asn1.DEROctetString.superclass.constructor.call(this, params); this.hT = "04" }; YAHOO.lang.extend(KJUR.asn1.DEROctetString, KJUR.asn1.DERAbstractString); KJUR.asn1.DERNull = function () { KJUR.asn1.DERNull.superclass.constructor.call(this); this.hT = "05"; this.hTLV = "0500" }; YAHOO.lang.extend(KJUR.asn1.DERNull, KJUR.asn1.ASN1Object); KJUR.asn1.DERObjectIdentifier = function (params) { var itox = function (i) { var h = i.toString(16); if (h.length == 1) h = '0' + h; return h }; var roidtox = function (roid) { var h = ''; var bi = new BigInteger(roid, 10); var b = bi.toString(2); var padLen = 7 - b.length % 7; if (padLen == 7) padLen = 0; var bPad = ''; for (var i = 0; i < padLen; i++)bPad += '0'; b = bPad + b; for (var i = 0; i < b.length - 1; i += 7) { var b8 = b.substr(i, 7); if (i != b.length - 7) b8 = '1' + b8; h += itox(parseInt(b8, 2)) } return h }; KJUR.asn1.DERObjectIdentifier.superclass.constructor.call(this); this.hT = "06"; this.setValueHex = function (newHexString) { this.hTLV = null; this.isModified = true; this.s = null; this.hV = newHexString }; this.setValueOidString = function (oidString) { if (!oidString.match(/^[0-9.]+$/)) { throw "malformed oid string: " + oidString; } var h = ''; var a = oidString.split('.'); var i0 = parseInt(a[0]) * 40 + parseInt(a[1]); h += itox(i0); a.splice(0, 2); for (var i = 0; i < a.length; i++) { h += roidtox(a[i]) } this.hTLV = null; this.isModified = true; this.s = null; this.hV = h }; this.setValueName = function (oidName) { var oid = KJUR.asn1.x509.OID.name2oid(oidName); if (oid !== '') { this.setValueOidString(oid) } else { throw "DERObjectIdentifier oidName undefined: " + oidName; } }; this.getFreshValueHex = function () { return this.hV }; if (params !== undefined) { if (typeof params === "string") { if (params.match(/^[0-2].[0-9.]+$/)) { this.setValueOidString(params) } else { this.setValueName(params) } } else if (params.oid !== undefined) { this.setValueOidString(params.oid) } else if (params.hex !== undefined) { this.setValueHex(params.hex) } else if (params.name !== undefined) { this.setValueName(params.name) } } }; YAHOO.lang.extend(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object); KJUR.asn1.DEREnumerated = function (params) { KJUR.asn1.DEREnumerated.superclass.constructor.call(this); this.hT = "0a"; this.setByBigInteger = function (bigIntegerValue) { this.hTLV = null; this.isModified = true; this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue) }; this.setByInteger = function (intValue) { var bi = new BigInteger(String(intValue), 10); this.setByBigInteger(bi) }; this.setValueHex = function (newHexString) { this.hV = newHexString }; this.getFreshValueHex = function () { return this.hV }; if (typeof params != "undefined") { if (typeof params['int'] != "undefined") { this.setByInteger(params['int']) } else if (typeof params == "number") { this.setByInteger(params) } else if (typeof params['hex'] != "undefined") { this.setValueHex(params['hex']) } } }; YAHOO.lang.extend(KJUR.asn1.DEREnumerated, KJUR.asn1.ASN1Object); KJUR.asn1.DERUTF8String = function (params) { KJUR.asn1.DERUTF8String.superclass.constructor.call(this, params); this.hT = "0c" }; YAHOO.lang.extend(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString); KJUR.asn1.DERNumericString = function (params) { KJUR.asn1.DERNumericString.superclass.constructor.call(this, params); this.hT = "12" }; YAHOO.lang.extend(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString); KJUR.asn1.DERPrintableString = function (params) { KJUR.asn1.DERPrintableString.superclass.constructor.call(this, params); this.hT = "13" }; YAHOO.lang.extend(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString); KJUR.asn1.DERTeletexString = function (params) { KJUR.asn1.DERTeletexString.superclass.constructor.call(this, params); this.hT = "14" }; YAHOO.lang.extend(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString); KJUR.asn1.DERIA5String = function (params) { KJUR.asn1.DERIA5String.superclass.constructor.call(this, params); this.hT = "16" }; YAHOO.lang.extend(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString); KJUR.asn1.DERUTCTime = function (params) { KJUR.asn1.DERUTCTime.superclass.constructor.call(this, params); this.hT = "17"; this.setByDate = function (dateObject) { this.hTLV = null; this.isModified = true; this.date = dateObject; this.s = this.formatDate(this.date, 'utc'); this.hV = stohex(this.s) }; this.getFreshValueHex = function () { if (typeof this.date == "undefined" && typeof this.s == "undefined") { this.date = new Date(); this.s = this.formatDate(this.date, 'utc'); this.hV = stohex(this.s) } return this.hV }; if (params !== undefined) { if (params.str !== undefined) { this.setString(params.str) } else if (typeof params == "string" && params.match(/^[0-9]{12}Z$/)) { this.setString(params) } else if (params.hex !== undefined) { this.setStringHex(params.hex) } else if (params.date !== undefined) { this.setByDate(params.date) } } }; YAHOO.lang.extend(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime); KJUR.asn1.DERGeneralizedTime = function (params) { KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, params); this.hT = "18"; this.withMillis = false; this.setByDate = function (dateObject) { this.hTLV = null; this.isModified = true; this.date = dateObject; this.s = this.formatDate(this.date, 'gen', this.withMillis); this.hV = stohex(this.s) }; this.getFreshValueHex = function () { if (this.date === undefined && this.s === undefined) { this.date = new Date(); this.s = this.formatDate(this.date, 'gen', this.withMillis); this.hV = stohex(this.s) } return this.hV }; if (params !== undefined) { if (params.str !== undefined) { this.setString(params.str) } else if (typeof params == "string" && params.match(/^[0-9]{14}Z$/)) { this.setString(params) } else if (params.hex !== undefined) { this.setStringHex(params.hex) } else if (params.date !== undefined) { this.setByDate(params.date) } if (params.millis === true) { this.withMillis = true } } }; YAHOO.lang.extend(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime); KJUR.asn1.DERSequence = function (params) { KJUR.asn1.DERSequence.superclass.constructor.call(this, params); this.hT = "30"; this.getFreshValueHex = function () { var h = ''; for (var i = 0; i < this.asn1Array.length; i++) { var asn1Obj = this.asn1Array[i]; h += asn1Obj.getEncodedHex() } this.hV = h; return this.hV } }; YAHOO.lang.extend(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured); KJUR.asn1.DERSet = function (params) { KJUR.asn1.DERSet.superclass.constructor.call(this, params); this.hT = "31"; this.sortFlag = true; this.getFreshValueHex = function () { var a = new Array(); for (var i = 0; i < this.asn1Array.length; i++) { var asn1Obj = this.asn1Array[i]; a.push(asn1Obj.getEncodedHex()) } if (this.sortFlag == true) a.sort(); this.hV = a.join(''); return this.hV }; if (typeof params != "undefined") { if (typeof params.sortflag != "undefined" && params.sortflag == false) this.sortFlag = false } }; YAHOO.lang.extend(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured); KJUR.asn1.DERTaggedObject = function (params) { KJUR.asn1.DERTaggedObject.superclass.constructor.call(this); this.hT = "a0"; this.hV = ''; this.isExplicit = true; this.asn1Object = null; this.setASN1Object = function (isExplicitFlag, tagNoHex, asn1Object) { this.hT = tagNoHex; this.isExplicit = isExplicitFlag; this.asn1Object = asn1Object; if (this.isExplicit) { this.hV = this.asn1Object.getEncodedHex(); this.hTLV = null; this.isModified = true } else { this.hV = null; this.hTLV = asn1Object.getEncodedHex(); this.hTLV = this.hTLV.replace(/^../, tagNoHex); this.isModified = false } }; this.getFreshValueHex = function () { return this.hV }; if (typeof params != "undefined") { if (typeof params['tag'] != "undefined") { this.hT = params['tag'] } if (typeof params['explicit'] != "undefined") { this.isExplicit = params['explicit'] } if (typeof params['obj'] != "undefined") { this.asn1Object = params['obj']; this.setASN1Object(this.isExplicit, this.hT, this.asn1Object) } } }; YAHOO.lang.extend(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object); var JSEncryptRSAKey = (function (_super) { __extends(JSEncryptRSAKey, _super); function JSEncryptRSAKey(key) { var _this = _super.call(this) || this; if (key) { if (typeof key === "string") { _this.parseKey(key) } else if (JSEncryptRSAKey.hasPrivateKeyProperty(key) || JSEncryptRSAKey.hasPublicKeyProperty(key)) { _this.parsePropertiesFrom(key) } } return _this } JSEncryptRSAKey.prototype.parseKey = function (pem) { try { var modulus = 0; var public_exponent = 0; var reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/; var der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem); var asn1 = ASN1.decode(der); if (asn1.sub.length === 3) { asn1 = asn1.sub[2].sub[0] } if (asn1.sub.length === 9) { modulus = asn1.sub[1].getHexStringValue(); this.n = parseBigInt(modulus, 16); public_exponent = asn1.sub[2].getHexStringValue(); this.e = parseInt(public_exponent, 16); var private_exponent = asn1.sub[3].getHexStringValue(); this.d = parseBigInt(private_exponent, 16); var prime1 = asn1.sub[4].getHexStringValue(); this.p = parseBigInt(prime1, 16); var prime2 = asn1.sub[5].getHexStringValue(); this.q = parseBigInt(prime2, 16); var exponent1 = asn1.sub[6].getHexStringValue(); this.dmp1 = parseBigInt(exponent1, 16); var exponent2 = asn1.sub[7].getHexStringValue(); this.dmq1 = parseBigInt(exponent2, 16); var coefficient = asn1.sub[8].getHexStringValue(); this.coeff = parseBigInt(coefficient, 16) } else if (asn1.sub.length === 2) { var bit_string = asn1.sub[1]; var sequence = bit_string.sub[0]; modulus = sequence.sub[0].getHexStringValue(); this.n = parseBigInt(modulus, 16); public_exponent = sequence.sub[1].getHexStringValue(); this.e = parseInt(public_exponent, 16) } else { return false } return true } catch (ex) { return false } }; JSEncryptRSAKey.prototype.getPrivateBaseKey = function () { var options = { array: [new KJUR.asn1.DERInteger({ int: 0 }), new KJUR.asn1.DERInteger({ bigint: this.n }), new KJUR.asn1.DERInteger({ int: this.e }), new KJUR.asn1.DERInteger({ bigint: this.d }), new KJUR.asn1.DERInteger({ bigint: this.p }), new KJUR.asn1.DERInteger({ bigint: this.q }), new KJUR.asn1.DERInteger({ bigint: this.dmp1 }), new KJUR.asn1.DERInteger({ bigint: this.dmq1 }), new KJUR.asn1.DERInteger({ bigint: this.coeff })] }; var seq = new KJUR.asn1.DERSequence(options); return seq.getEncodedHex() }; JSEncryptRSAKey.prototype.getPrivateBaseKeyB64 = function () { return hex2b64(this.getPrivateBaseKey()) }; JSEncryptRSAKey.prototype.getPublicBaseKey = function () { var first_sequence = new KJUR.asn1.DERSequence({ array: [new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }), new KJUR.asn1.DERNull()] }); var second_sequence = new KJUR.asn1.DERSequence({ array: [new KJUR.asn1.DERInteger({ bigint: this.n }), new KJUR.asn1.DERInteger({ int: this.e })] }); var bit_string = new KJUR.asn1.DERBitString({ hex: "00" + second_sequence.getEncodedHex() }); var seq = new KJUR.asn1.DERSequence({ array: [first_sequence, bit_string] }); return seq.getEncodedHex() }; JSEncryptRSAKey.prototype.getPublicBaseKeyB64 = function () { return hex2b64(this.getPublicBaseKey()) }; JSEncryptRSAKey.wordwrap = function (str, width) { width = width || 64; if (!str) { return str } var regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})"; return str.match(RegExp(regex, "g")).join("\n") }; JSEncryptRSAKey.prototype.getPrivateKey = function () { var key = "-----BEGIN RSA PRIVATE KEY-----\n"; key += JSEncryptRSAKey.wordwrap(this.getPrivateBaseKeyB64()) + "\n"; key += "-----END RSA PRIVATE KEY-----"; return key }; JSEncryptRSAKey.prototype.getPublicKey = function () { var key = "-----BEGIN PUBLIC KEY-----\n"; key += JSEncryptRSAKey.wordwrap(this.getPublicBaseKeyB64()) + "\n"; key += "-----END PUBLIC KEY-----"; return key }; JSEncryptRSAKey.hasPublicKeyProperty = function (obj) { obj = obj || {}; return (obj.hasOwnProperty("n") && obj.hasOwnProperty("e")) }; JSEncryptRSAKey.hasPrivateKeyProperty = function (obj) { obj = obj || {}; return (obj.hasOwnProperty("n") && obj.hasOwnProperty("e") && obj.hasOwnProperty("d") && obj.hasOwnProperty("p") && obj.hasOwnProperty("q") && obj.hasOwnProperty("dmp1") && obj.hasOwnProperty("dmq1") && obj.hasOwnProperty("coeff")) }; JSEncryptRSAKey.prototype.parsePropertiesFrom = function (obj) { this.n = obj.n; this.e = obj.e; if (obj.hasOwnProperty("d")) { this.d = obj.d; this.p = obj.p; this.q = obj.q; this.dmp1 = obj.dmp1; this.dmq1 = obj.dmq1; this.coeff = obj.coeff } }; return JSEncryptRSAKey }(RSAKey)); var JSEncrypt = (function () { function JSEncrypt(options) { options = options || {}; this.default_key_size = parseInt(options.default_key_size, 10) || 1024; this.default_public_exponent = options.default_public_exponent || "010001"; this.log = options.log || false; this.key = null } JSEncrypt.prototype.setKey = function (key) { if (this.log && this.key) { console.warn("A key was already set, overriding existing.") } this.key = new JSEncryptRSAKey(key) }; JSEncrypt.prototype.setPrivateKey = function (privkey) { this.setKey(privkey) }; JSEncrypt.prototype.setPublicKey = function (pubkey) { this.setKey(pubkey) }; JSEncrypt.prototype.decrypt = function (str) { try { return this.getKey().decrypt(b64tohex(str)) } catch (ex) { return false } }; JSEncrypt.prototype.encrypt = function (str) { try { return hex2b64(this.getKey().encrypt(str)) } catch (ex) { return false } }; JSEncrypt.prototype.sign = function (str, digestMethod, digestName) { try { return hex2b64(this.getKey().sign(str, digestMethod, digestName)) } catch (ex) { return false } }; JSEncrypt.prototype.verify = function (str, signature, digestMethod) { try { return this.getKey().verify(str, b64tohex(signature), digestMethod) } catch (ex) { return false } }; JSEncrypt.prototype.getKey = function (cb) { if (!this.key) { this.key = new JSEncryptRSAKey(); if (cb && {}.toString.call(cb) === "[object Function]") { this.key.generateAsync(this.default_key_size, this.default_public_exponent, cb); return } this.key.generate(this.default_key_size, this.default_public_exponent) } return this.key }; JSEncrypt.prototype.getPrivateKey = function () { return this.getKey().getPrivateKey() }; JSEncrypt.prototype.getPrivateKeyB64 = function () { return this.getKey().getPrivateBaseKeyB64() }; JSEncrypt.prototype.getPublicKey = function () { return this.getKey().getPublicKey() }; JSEncrypt.prototype.getPublicKeyB64 = function () { return this.getKey().getPublicBaseKeyB64() }; JSEncrypt.version = "3.0.0-rc.1"; return JSEncrypt }()); window2.JSEncrypt = JSEncrypt; exports.JSEncrypt = JSEncrypt; exports.default = JSEncrypt; Object.defineProperty(exports, '__esModule', { value: true }) })));

那么在js中如何使用呢?

  • 由于微信小程序本身属于前端部分,不涉及后端,一般不会要求前端持有密钥(yuè),而是只持有公钥(yuè)就足够了。因此我们分为以下步骤:

    1. 引进我们需要的jsencrypt.js文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//为了防止ES5和ES6兼容性的问题,采用ES5的方式引进js文件

//1、引进我们需要的`jsencrypt.js`文件
var jsencrypt = require('../../utils/jsencrypt.min.js');

Page({

data: {},
onLoad: function (options) {},
onReady: function () {},
onShow: function () {},
onHide: function () {},
onUnload: function () {},
onPullDownRefresh: function () {},
onReachBottom: function () {},
onShareAppMessage: function () {}
})
  1. 从服务器端获取公钥(yuè)

  2. 利用从服务器获得的公钥(yuè),对本地进行RSA加密,得到密文

  3. 将密文发给服务器(这样就能保证数据在网路传输过程中的绝密性了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
wx.request({
//2、指定服务器的url,获取公钥(yuè)
url: 'http://localhost:8080/weixin/publickey',
method: 'POST',
success: function(res){
//获取公钥(yuè)
var publicKey = res.data
//如果服务器返回的公钥为空字符串,说明服务器发生错误,无法正常生成公钥
if(publicKey=="") return;
//通过引进的`jsencrypt.js`文件,来创建具有RSA算法的对象
var rsa = new jsencrypt.JSEncrypt();

//3、利用从服务器获得的公钥(yuè),对本地进行RSA加密,得到密文`ciphertext`
rsa.setPublicKey(publicKey)
var ciphertext = rsa.encrypt(JSON.stringify(metaVo))

//4、将密文发给服务器
//(前后端采用统一的cipherObj对象的格式来说明该密文由哪个公钥加密的,方便后端知晓后采用对应的密钥进行解密)
var cipherObj = {}
cipherObj.publicKey = publicKey;
cipherObj.ciphertext = ciphertext;

wx.request({
url: 'http://localhost:8080/weixin/uploader',
data: cipherObj,
dataType: 'json',
method: 'POST',
success: function(res){
console.log(res.data)
},
fail: function(res){
console.log("失败")
}
})
},
fail: function(res){
console.log("失败")
}
})

既然前端是这么写的,那么后端长什么样子的呢?

4、Java后端使用RSA

  1. 首先我们需要像上面的JavaScript一样,有一个类似于jsencrypt.js文件的工具类。

    这里我直接写好了这个工具类,直接附上:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    package top.bingcu.utils.sign;

    import org.apache.commons.codec.binary.Base64;
    import javax.crypto.Cipher;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;


    public class RSAEncrypt {
    //封装随机产生的公钥与密钥
    private static Map<String, String> keyMap = new HashMap<String, String>();

    //测试能否正确生成公钥和密钥,同时测试是否能正确加密解密
    // public static void main(String[] args) throws Exception {
    // String publicKey = generateKeyPair();
    // System.out.println("Public Key:");
    // System.out.println(publicKey);
    // System.out.println("Private Key:");
    // System.out.println(keyMap.get(publicKey));
    //
    // System.out.println();
    // System.out.println("加密后的文本:");
    //
    // String text = encrypt("123", publicKey);
    // System.out.println(text);
    // System.out.println("解密后的文本:");
    // System.out.println(decrypt(text, keyMap.get(publicKey)));
    // }

    /**
    * 随机生成密钥对
    *
    * @throws NoSuchAlgorithmException
    */
    public static String generateKeyPair() throws NoSuchAlgorithmException {
    // KeyPairGenerator类用于生成公钥和密钥对,基于RSA算法生成对象
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    // 初始化密钥对生成器,密钥大小为96-1024位
    keyPairGen.initialize(1024,new SecureRandom());
    // 生成一个密钥对,保存在keyPair中
    KeyPair keyPair = keyPairGen.generateKeyPair();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 获得密钥
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 获得公钥
    String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
    // 获得密钥字符串
    String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));

    synchronized (keyMap){
    // 将公钥和私钥保存到Map
    //key:公钥, value:私钥
    keyMap.put(publicKeyString, privateKeyString);
    }

    //返回当前生成的公钥
    return publicKeyString;
    }
    /**
    * RSA公钥加密
    *
    * @param text 需加密的文本
    * @param publicKey 公钥
    * @return 密文
    * @throws Exception 加密过程中的异常信息
    */
    public static String encrypt( String text, String publicKey ) throws Exception{
    //base64编码的公钥
    byte[] decoded = Base64.decodeBase64(publicKey);
    RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
    //RSA加密
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    String outStr = Base64.encodeBase64String(cipher.doFinal(text.getBytes("UTF-8")));
    return outStr;
    }

    /**
    * RSA密钥解密
    *
    * @param text 需解密的文本
    * @param privateKey 密钥
    * @return 铭文
    * @throws Exception 解密过程中的异常信息
    */
    public static String decrypt(String text, String privateKey) throws Exception{
    //64位解码加密后的字符串
    byte[] inputByte = Base64.decodeBase64(text.getBytes("UTF-8"));
    //base64编码的密钥
    byte[] decoded = Base64.decodeBase64(privateKey);
    RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
    //RSA解密
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, priKey);
    String outStr = new String(cipher.doFinal(inputByte));
    return outStr;
    }

    /**
    * 获取公钥对应的密钥
    *
    * @param publicKey 公钥
    * @return 密钥
    */
    public static String obtainPrivateKey(String publicKey){
    return keyMap.get(publicKey);
    }


    /**
    * 删除键值对
    *
    * @param publicKey 公钥
    * @return 被删除的密钥
    */
    public static String dropKeyPair(String publicKey){
    synchronized (keyMap){
    return keyMap.remove(publicKey);
    }
    }
    }
  2. 虽然工具是就此写好了,那现在就到了使用它的时候了。我们现在就需要编写与微信相关的Controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    package top.bingcu.web.controller.weixin;

    import top.bingcu.utils.sign.RSAEncrypt;
    import top.bingcu.web.domain.to.CipherObj;
    import org.springframework.web.bind.annotation.*;

    import java.security.NoSuchAlgorithmException;

    /**
    * 微信数据上传
    */
    @RestController
    @RequestMapping("/weixin")
    public class uploaderController {

    /**
    * 客户端向本服务器申请一个公钥
    *
    * @return 随机公钥
    */
    @RequestMapping("/publickey")
    public String obtainPublicKey(){
    try {
    String publicKey = RSAEncrypt.generateKeyPair();
    System.out.println("[申请] 对方申请公钥成功");
    //正常生成公钥的话,就正常将该公钥返回给客户端
    return publicKey;
    } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
    }

    //服务器这边生成公钥抛异常了,所以返回空字符串
    return "";
    }

    @RequestMapping("/uploader")
    public String upload(@RequestBody CipherObj cipherObj){

    //获得密钥后就把对应的 密钥对 从密钥管理者中删除
    //因为生成的密钥的一次性的,所以不管执行成不成功,之后该 密钥对 都没用了
    String privateKey = RSAEncrypt.obtainPrivateKey(cipherObj.getPublicKey());
    RSAEncrypt.dropKeyPair(cipherObj.getPublicKey());

    try {
    String clearText = RSAEncrypt.decrypt(cipherObj.getCiphertext(), privateKey);
    System.out.println("解密后的明文:");
    System.out.println(clearText);

    //处理
    //......

    } catch (Exception e) {
    e.printStackTrace();
    return "false";
    }

    return "true";
    }

    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package top.bingcu.web.domain.to;

/**
* 前后端统一的密文收发格式
*/
public class CipherObj {
String publicKey;
String ciphertext;

public String getPublicKey() {
return publicKey;
}

public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}

public String getCiphertext() {
return ciphertext;
}

public void setCiphertext(String ciphertext) {
this.ciphertext = ciphertext;
}

@Override
public String toString() {
return "CipherObj{" +
"publicKey='" + publicKey + '\'' +
", ciphertext='" + ciphertext + '\'' +
'}';
}
}