版权声明:本文为博主原创文章,未经博主允许不得转载。
在一次项目实战中,前端登录使用了RSA加密,使用LoadRunner压测的第一步,就是模拟用户登录,可惜loadRunner11并不能录制前端的加密过程,并且安装的LR是基于C语言版,网络上关于RSA的加密更多的是Java版,最后,选择在Jmeter中先尝试一下能否解决加密的问题,毕竟它有很多处理器,用于脚本的插入;
把解决过程中遇到的问题,简单做个记录,防止遗忘,也算是给自己下一次项目一个经验总结了;
【1】了解加密方式-----RSA
询问开发前端的加密方式:先请求public_key,再加密密码,再提交。
加密的代码前端代码实现:
$.getJSON('/public_key?t='+timestamp).then((rsa) => {
let rsaKey = new RSAKey();
rsaKey.setPublic(b64tohex(rsa.modulus), b64tohex(rsa.exponent));
data.password = hex2b64(rsaKey.encrypt(data.password));
$.post('/ajax_login_check', data).then(this.completed, this.failed);
}, this.failed);
备注:以上来自开发,后来在了解RSA的实现方式中,发现大家的RSA前端加密方式是一样的~
已知了上面这些,下面开始自己玩前端RSA加密的方式,抓包查看登录的请求,有三个重要的请求:
①GET /public_key?t=1495537754854 :用于获取RAS生成公钥时的两个重要参数exponent 和 modulus;
②POST /ajax_login_check:用于将已加密的密码 && 登录名post到服务器去验证,验证成功后返回success;
③GET /:在 /ajax_login_check验证成功后,GET /请求会返回一个TOKEN值,作为该用户进入系统后的令牌,执行系统内的每一个操作时,对应的请求都需要在头部添加该参数,否则会报403错误;
【2】查找加密使用的js文件
也是走了很多弯路,先在DOS下折腾,后又安装了eclipse,在网上找寻各种加密代码,打成jar包,在LoadRunner中却无法使用;将网上关于RSA的java类及方法直接放在Jmeter中进行加密,Jmeter连import都不支持;
然后,仔细查看登录的每一个请求包,注意到一个js文件,其中有关于BigInteger和RSA的函数定义(C语言中是这样称呼的,我也这样称呼了),想一想既然是在前端加密,那服务器会不会直接将加密使用的方法返回给客户端呢,谷歌浏览器按“F12”查看登录页面的Sources,查找js文件,后来发现前面提到的js文件sec.min.js中竟然有开发用于加密的函数hex2b64(),急忙将该js文件保存在本地,开发使用到的加密的方法都可以在这个文件中找到,喜极而泣;
【3】使用Jmeter的JSR223后置处理器,完成加密
使用apache-jmeter-2.12 + jdk 1.6,在JSR223中load("sec.min.js");,总是报错“jmeter.modifiers.JSR223PreProcessor: Problem in JSR223 script JSR223 PreProcessor javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "load" is not defined.”,后考虑是不是版本问题,换了apache-jmeter-3.2 + jdk1.8,load不再报错;
注:①使用到的js文件需要放在jmeter的bin目录下;②JSR223中,Language选择“JavaScript”;
Jmeter中加密的调用实现如下:
JSR223中使用到的modules的正则表达式提取如下:
【4】调试js文件
勾选Jmeter“选项”→“Log Viewer”,添加Debug后置处理器;在Jmeter中会打印代码执行的情况,有错误的话就逐步排除;PS:调试很艰难,且调且珍惜;
①navigator 报错,求助网络,这是浏览器对象,因为录制时使用的谷歌浏览器,所以我选择了保留关于谷歌的设置(其实不一定要选择谷歌相关的,只要js文件中使用同一浏览器的相关属性值即可),将不重要的直接可以注释掉,类似的还有 window;
②alert()在Jmeter中无法执行(会报错):直接将js中的alert()注释,并用return null; 替换,便于调试;
③我在调试过程中还遇到 toRadix & signum & chunkSize & intValue未定义;继续使用F12查看自己是否有遗漏需要load的js文件,并没有找到,然后在网上搜索 toRadix 直接就出来了,O(∩_∩)O~~,于是添加属性及方法在js文件中,正确执行,耶耶耶~~~~链接:http://blog.csdn.net/huaye2007/article/details/41727921
【4】后续处理
①GET /public_key?t=1495537754854这里的t是Unix时间戳,在该请求中添加 JSR223前置处理器,使用如下语句完成处理:
var timestamp=new Date().getTime(); //精确到毫秒;
vars.put("timestamp",timestamp);
②依旧显示密码错误:一步步排查,注意到在POST时,“查看结果树”的“请求”中显示的内容与log中打印的不一致(密文为base64编码),具体为“+”显示不正确,再次询问网络,有人提到含有“+”的字符串在URL中传递时,需要替换加号为%2B,否则在服务器解码的时候会出错;
后来勾选了 /ajax_login_check请求对应的参数“password”值的“编码”,在该请求的结果树中,可以看到POST的密文已经将“+”及“/”进行了转码,因此最终并未使用替换语句;
附上替换语句:data = data.replace(/+/g,"%2B"); data = data.replace(///g,"%2F"); // g代表全部替换
至此,完成了前端模拟RSA加密,进行登录,ajax校验用户名&密码通过;
总结及感悟:对于前端加密,服务器应该是要返回加密方式给客户端的,否则客户端无从知晓如何加密,至于加密的方式是否可以直接识别,1在于服务端的返回内容,2在于测试人员是否有很好的观察及辨识能力,而这种辨识能力就在于平时的多涉猎多接触,一开始抓包也有看到sec.min.js,但是并没有敏锐的意识到加密就藏在这里,兜兜转转才发现,所以还是要多学习,开发知识也好,测试知识也罢O(∩_∩)O~~
附1----------Jmeter中JSR前置处理器的javascript脚本
load("sec.min.js"); var modulus = vars.get("modulus"); log.info(modulus); var exponent = vars.get("exponent"); log.info(exponent); function RSA(){ var rsaKey = new RSAKey(); rsaKey.setPublic(b64tohex("${modulus}"),b64tohex("${exponent}")); var Enpassword = hex2b64(rsaKey.encrypt("${password}")); return Enpassword } var data = RSA(); log.info(data); //base64在url中的传输,要注意+ /两个符号 //data = data.replace(/+/g,"%2B"); //data = data.replace(///g,"%2F"); vars.put("Password",data);
附2----------sec.min.js修改后的js文件
var dbits; var canary = 244837814094590; var j_lm = ((canary & 16777215) == 15715070); function BigInteger(e, d, f) { if (e != null) { if ("number" == typeof e) { this.fromNumber(e, d, f) } else { if (d == null && "string" != typeof e) { this.fromString(e, 256) } else { this.fromString(e, d) } } } } function nbi() { return new BigInteger(null) } function am1(f, a, b, e, h, g) { while (--g >= 0) { var d = a * this[f++] + b[e] + h; h = Math.floor(d / 67108864); b[e++] = d & 67108863 } return h } function am2(f, q, r, e, o, a) { var k = q & 32767, p = q >> 15; while (--a >= 0) { var d = this[f] & 32767; var g = this[f++] >> 15; var b = p * d + g * k; d = k * d + ((b & 32767) << 15) + r[e] + (o & 1073741823); o = (d >>> 30) + (b >>> 15) + p * g + (o >>> 30); r[e++] = d & 1073741823 } return o } function am3(f, q, r, e, o, a) { var k = q & 16383, p = q >> 14; while (--a >= 0) { var d = this[f] & 16383; var g = this[f++] >> 14; var b = p * d + g * k; d = k * d + ((b & 16383) << 14) + r[e] + o; o = (d >> 28) + (b >> 14) + p * g; r[e++] = d & 268435455 } return o } //if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { //xpp注释 // BigInteger.prototype.am = am2; // dbits = 30 //} else { // if (j_lm && (navigator.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_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; var BI_RC = new Array(); var rr, 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 int2char(a) { return BI_RM.charAt(a) } function intAt(b, a) { var d = BI_RC[b.charCodeAt(a)]; return (d == null) ? -1 : d } //-----摘自网络-----start function bnpToRadix(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), y = nbi(), z = nbi(), 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 } function bnSigNum() { if (this.s < 0) { return -1 } else { if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) { return 0 } else { return 1 } } } function bnpChunkSize(r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)) } function bnIntValue() { 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] } //-----摘自网络-----end function bnpCopyTo(b) { for (var a = this.t - 1; a >= 0; --a) { b[a] = this[a] } b.t = this.t; b.s = this.s } function bnpFromInt(a) { this.t = 1; this.s = (a < 0) ? -1 : 0; if (a > 0) { this[0] = a } else { if (a < -1) { this[0] = a + DV } else { this.t = 0 } } } function nbv(a) { var b = nbi(); b.fromInt(a); return b } function bnpFromString(h, c) { var e; if (c == 16) { e = 4 } else { if (c == 8) { e = 3 } else { if (c == 256) { e = 8 } else { if (c == 2) { e = 1 } else { if (c == 32) { e = 5 } else { if (c == 4) { e = 2 } else { this.fromRadix(h, c); return } } } } } } this.t = 0; this.s = 0; var g = h.length, d = false, f = 0; while (--g >= 0) { var a = (e == 8) ? h[g] & 255 : intAt(h, g); if (a < 0) { if (h.charAt(g) == "-") { d = true } continue } d = false; if (f == 0) { this[this.t++] = a } else { if (f + e > this.DB) { this[this.t - 1] |= (a & ((1 << (this.DB - f)) - 1)) << f; this[this.t++] = (a >> (this.DB - f)) } else { this[this.t - 1] |= a << f } } f += e; if (f >= this.DB) { f -= this.DB } } if (e == 8 && (h[0] & 128) != 0) { this.s = -1; if (f > 0) { this[this.t - 1] |= ((1 << (this.DB - f)) - 1) << f } } this.clamp(); if (d) { BigInteger.ZERO.subTo(this, this) } } function bnpClamp() { var a = this.s & this.DM; while (this.t > 0 && this[this.t - 1] == a) { --this.t } } function bnToString(c) { if (this.s < 0) { return "-" + this.negate().toString(c) } var e; if (c == 16) { e = 4 } else { if (c == 8) { e = 3 } else { if (c == 2) { e = 1 } else { if (c == 32) { e = 5 } else { if (c == 4) { e = 2 } else { return this.toRadix(c) } } } } } var g = (1 << e) - 1, l, a = false, h = "", f = this.t; var j = this.DB - (f * this.DB) % e; if (f-- > 0) { if (j < this.DB && (l = this[f] >> j) > 0) { a = true; h = int2char(l) } while (f >= 0) { if (j < e) { l = (this[f] & ((1 << j) - 1)) << (e - j); l |= this[--f] >> (j += this.DB - e) } else { l = (this[f] >> (j -= e)) & g; if (j <= 0) { j += this.DB; --f } } if (l > 0) { a = true } if (a) { h += int2char(l) } } } return a ? h : "0" } function bnNegate() { var a = nbi(); BigInteger.ZERO.subTo(this, a); return a } function bnAbs() { return (this.s < 0) ? this.negate() : this } function bnCompareTo(b) { var d = this.s - b.s; if (d != 0) { return d } var c = this.t; d = c - b.t; if (d != 0) { return (this.s < 0) ? -d : d } while (--c >= 0) { if ((d = this[c] - b[c]) != 0) { return d } } return 0 } function nbits(a) { var c = 1, b; if ((b = a >>> 16) != 0) { a = b; c += 16 } if ((b = a >> 8) != 0) { a = b; c += 8 } if ((b = a >> 4) != 0) { a = b; c += 4 } if ((b = a >> 2) != 0) { a = b; c += 2 } if ((b = a >> 1) != 0) { a = b; c += 1 } return c } function bnBitLength() { if (this.t <= 0) { return 0 } return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)) } function bnpDLShiftTo(c, b) { var a; for (a = this.t - 1; a >= 0; --a) { b[a + c] = this[a] } for (a = c - 1; a >= 0; --a) { b[a] = 0 } b.t = this.t + c; b.s = this.s } function bnpDRShiftTo(c, b) { for (var a = c; a < this.t; ++a) { b[a - c] = this[a] } b.t = Math.max(this.t - c, 0); b.s = this.s } function bnpLShiftTo(j, e) { var b = j % this.DB; var a = this.DB - b; var g = (1 << a) - 1; var f = Math.floor(j / this.DB), h = (this.s << b) & this.DM, d; for (d = this.t - 1; d >= 0; --d) { e[d + f + 1] = (this[d] >> a) | h; h = (this[d] & g) << b } for (d = f - 1; d >= 0; --d) { e[d] = 0 } e[f] = h; e.t = this.t + f + 1; e.s = this.s; e.clamp() } function bnpRShiftTo(g, d) { d.s = this.s; var e = Math.floor(g / this.DB); if (e >= this.t) { d.t = 0; return } var b = g % this.DB; var a = this.DB - b; var f = (1 << b) - 1; d[0] = this[e] >> b; for (var c = e + 1; c < this.t; ++c) { d[c - e - 1] |= (this[c] & f) << a; d[c - e] = this[c] >> b } if (b > 0) { d[this.t - e - 1] |= (this.s & f) << a } d.t = this.t - e; d.clamp() } function bnpSubTo(d, f) { var e = 0, g = 0, b = Math.min(d.t, this.t); while (e < b) { g += this[e] - d[e]; f[e++] = g & this.DM; g >>= this.DB } if (d.t < this.t) { g -= d.s; while (e < this.t) { g += this[e]; f[e++] = g & this.DM; g >>= this.DB } g += this.s } else { g += this.s; while (e < d.t) { g -= d[e]; f[e++] = g & this.DM; g >>= this.DB } g -= d.s } f.s = (g < 0) ? -1 : 0; if (g < -1) { f[e++] = this.DV + g } else { if (g > 0) { f[e++] = g } } f.t = e; f.clamp() } function bnpMultiplyTo(c, e) { var b = this.abs(), f = c.abs(); var d = b.t; e.t = d + f.t; while (--d >= 0) { e[d] = 0 } for (d = 0; d < f.t; ++d) { e[d + b.t] = b.am(0, f[d], e, d, 0, b.t) } e.s = 0; e.clamp(); if (this.s != c.s) { BigInteger.ZERO.subTo(e, e) } } function bnpSquareTo(d) { var a = this.abs(); var b = d.t = 2 * a.t; while (--b >= 0) { d[b] = 0 } for (b = 0; b < a.t - 1; ++b) { var e = a.am(b, a[b], d, 2 * b, 0, 1); if ((d[b + a.t] += a.am(b + 1, 2 * a[b], d, 2 * b + 1, e, a.t - b - 1)) >= a.DV) { d[b + a.t] -= a.DV; d[b + a.t + 1] = 1 } } if (d.t > 0) { d[d.t - 1] += a.am(b, a[b], d, 2 * b, 0, 1) } d.s = 0; d.clamp() } function bnpDivRemTo(n, h, g) { var w = n.abs(); if (w.t <= 0) { return } var k = this.abs(); if (k.t < w.t) { if (h != null) { h.fromInt(0) } if (g != null) { this.copyTo(g) } return } if (g == null) { g = nbi() } var d = nbi(), a = this.s, l = n.s; var v = this.DB - nbits(w[w.t - 1]); if (v > 0) { w.lShiftTo(v, d); k.lShiftTo(v, g) } else { w.copyTo(d); k.copyTo(g) } var p = d.t; var b = d[p - 1]; if (b == 0) { return } var o = b * (1 << this.F1) + ((p > 1) ? d[p - 2] >> this.F2 : 0); var A = this.FV / o, z = (1 << this.F1) / o, x = 1 << this.F2; var u = g.t, s = u - p, f = (h == null) ? nbi() : h; d.dlShiftTo(s, f); if (g.compareTo(f) >= 0) { g[g.t++] = 1; g.subTo(f, g) } BigInteger.ONE.dlShiftTo(p, f); f.subTo(d, d); while (d.t < p) { d[d.t++] = 0 } while (--s >= 0) { var c = (g[--u] == b) ? this.DM : Math.floor(g[u] * A + (g[u - 1] + x) * z); if ((g[u] += d.am(0, c, g, s, 0, p)) < c) { d.dlShiftTo(s, f); g.subTo(f, g); while (g[u] < --c) { g.subTo(f, g) } } } if (h != null) { g.drShiftTo(p, h); if (a != l) { BigInteger.ZERO.subTo(h, h) } } g.t = p; g.clamp(); if (v > 0) { g.rShiftTo(v, g) } if (a < 0) { BigInteger.ZERO.subTo(g, g) } } function bnMod(b) { var c = nbi(); this.abs().divRemTo(b, null, c); if (this.s < 0 && c.compareTo(BigInteger.ZERO) > 0) { b.subTo(c, c) } return c } function Classic(a) { this.m = a } function cConvert(a) { if (a.s < 0 || a.compareTo(this.m) >= 0) { return a.mod(this.m) } else { return a } } function cRevert(a) { return a } function cReduce(a) { a.divRemTo(this.m, null, a) } function cMulTo(a, c, b) { a.multiplyTo(c, b); this.reduce(b) } function cSqrTo(a, b) { a.squareTo(b); this.reduce(b) } Classic.prototype.convert = cConvert; Classic.prototype.revert = cRevert; Classic.prototype.reduce = cReduce; Classic.prototype.mulTo = cMulTo; Classic.prototype.sqrTo = cSqrTo; function bnpInvDigit() { if (this.t < 1) { return 0 } var a = this[0]; if ((a & 1) == 0) { return 0 } var b = a & 3; b = (b * (2 - (a & 15) * b)) & 15; b = (b * (2 - (a & 255) * b)) & 255; b = (b * (2 - (((a & 65535) * b) & 65535))) & 65535; b = (b * (2 - a * b % this.DV)) % this.DV; return (b > 0) ? this.DV - b : -b } function Montgomery(a) { this.m = a; this.mp = a.invDigit(); this.mpl = this.mp & 32767; this.mph = this.mp >> 15; this.um = (1 << (a.DB - 15)) - 1; this.mt2 = 2 * a.t } function montConvert(a) { var b = nbi(); a.abs().dlShiftTo(this.m.t, b); b.divRemTo(this.m, null, b); if (a.s < 0 && b.compareTo(BigInteger.ZERO) > 0) { this.m.subTo(b, b) } return b } function montRevert(a) { var b = nbi(); a.copyTo(b); this.reduce(b); return b } function montReduce(a) { while (a.t <= this.mt2) { a[a.t++] = 0 } for (var c = 0; c < this.m.t; ++c) { var b = a[c] & 32767; var d = (b * this.mpl + (((b * this.mph + (a[c] >> 15) * this.mpl) & this.um) << 15)) & a.DM; b = c + this.m.t; a[b] += this.m.am(0, d, a, c, 0, this.m.t); while (a[b] >= a.DV) { a[b] -= a.DV; a[++b]++ } } a.clamp(); a.drShiftTo(this.m.t, a); if (a.compareTo(this.m) >= 0) { a.subTo(this.m, a) } } function montSqrTo(a, b) { a.squareTo(b); this.reduce(b) } function montMulTo(a, c, b) { a.multiplyTo(c, b); this.reduce(b) } Montgomery.prototype.convert = montConvert; Montgomery.prototype.revert = montRevert; Montgomery.prototype.reduce = montReduce; Montgomery.prototype.mulTo = montMulTo; Montgomery.prototype.sqrTo = montSqrTo; function bnpIsEven() { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0 } function bnpExp(h, j) { if (h > 4294967295 || h < 1) { return BigInteger.ONE } var f = nbi(), a = nbi(), d = j.convert(this), c = nbits(h) - 1; d.copyTo(f); while (--c >= 0) { j.sqrTo(f, a); if ((h & (1 << c)) > 0) { j.mulTo(a, d, f) } else { var b = f; f = a; a = b } } return j.revert(f) } function bnModPowInt(b, a) { var c; if (b < 256 || a.isEven()) { c = new Classic(a) } else { c = new Montgomery(a) } return this.exp(b, c) } //-----摘自网络-----start BigInteger.prototype.toRadix = bnpToRadix; BigInteger.prototype.signum = bnSigNum; BigInteger.prototype.chunkSize = bnpChunkSize; BigInteger.prototype.intValue = bnIntValue; //-----摘自网络-----end BigInteger.prototype.copyTo = bnpCopyTo; BigInteger.prototype.fromInt = bnpFromInt; BigInteger.prototype.fromString = bnpFromString; BigInteger.prototype.clamp = bnpClamp; BigInteger.prototype.dlShiftTo = bnpDLShiftTo; BigInteger.prototype.drShiftTo = bnpDRShiftTo; BigInteger.prototype.lShiftTo = bnpLShiftTo; BigInteger.prototype.rShiftTo = bnpRShiftTo; BigInteger.prototype.subTo = bnpSubTo; BigInteger.prototype.multiplyTo = bnpMultiplyTo; BigInteger.prototype.squareTo = bnpSquareTo; BigInteger.prototype.divRemTo = bnpDivRemTo; BigInteger.prototype.invDigit = bnpInvDigit; BigInteger.prototype.isEven = bnpIsEven; BigInteger.prototype.exp = bnpExp; BigInteger.prototype.toString = bnToString; BigInteger.prototype.negate = bnNegate; BigInteger.prototype.abs = bnAbs; BigInteger.prototype.compareTo = bnCompareTo; BigInteger.prototype.bitLength = bnBitLength; BigInteger.prototype.mod = bnMod; BigInteger.prototype.modPowInt = bnModPowInt; BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); function Arcfour() { this.i = 0; this.j = 0; this.S = new Array() } function ARC4init(d) { var c, a, b; for (c = 0; c < 256; ++c) { this.S[c] = c } a = 0; for (c = 0; c < 256; ++c) { a = (a + this.S[c] + d[c % d.length]) & 255; b = this.S[c]; this.S[c] = this.S[a]; this.S[a] = b } this.i = 0; this.j = 0 } function ARC4next() { var a; this.i = (this.i + 1) & 255; this.j = (this.j + this.S[this.i]) & 255; a = this.S[this.i]; this.S[this.i] = this.S[this.j]; this.S[this.j] = a; return this.S[(a + this.S[this.i]) & 255] } Arcfour.prototype.init = ARC4init; Arcfour.prototype.next = ARC4next; function prng_newstate() { return new Arcfour() } var rng_psize = 256; var rng_state; var rng_pool; var rng_pptr; function rng_seed_int(a) { rng_pool[rng_pptr++] ^= a & 255; rng_pool[rng_pptr++] ^= (a >> 8) & 255; rng_pool[rng_pptr++] ^= (a >> 16) & 255; rng_pool[rng_pptr++] ^= (a >> 24) & 255; if (rng_pptr >= rng_psize) { rng_pptr -= rng_psize } } function rng_seed_time() { rng_seed_int(new Date().getTime()) } if (rng_pool == null) { //注释 rng_pool = new Array(); rng_pptr = 0; var t; // if (navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) { // var z = window.crypto.random(32); // for (t = 0; t < z.length; ++t) { // rng_pool[rng_pptr++] = z.charCodeAt(t) & 255 // } // } // while (rng_pptr < rng_psize) { // t = Math.floor(65536 * Math.random()); // rng_pool[rng_pptr++] = t >>> 8; // rng_pool[rng_pptr++] = t & 255 // } // rng_pptr = 0; // rng_seed_time() } function rng_get_byte() { if (rng_state == null) { rng_seed_time(); rng_state = prng_newstate(); 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() } function rng_get_bytes(b) { var a; for (a = 0; a < b.length; ++a) { b[a] = rng_get_byte() } } function SecureRandom() {} SecureRandom.prototype.nextBytes = rng_get_bytes; function parseBigInt(b, a) { return new BigInteger(b, a) } function linebrk(c, d) { var a = ""; var b = 0; while (b + d < c.length) { a += c.substring(b, b + d) + " "; b += d } return a + c.substring(b, c.length) } function byte2Hex(a) { if (a < 16) { return "0" + a.toString(16) } else { return a.toString(16) } } function pkcs1pad2(e, h) { if (h < e.length + 11) { // alert("Message too long for RSA"); return null } var g = new Array(); var d = e.length - 1; while (d >= 0 && h > 0) { var f = e.charCodeAt(d--); if (f < 128) { g[--h] = f } else { if ((f > 127) && (f < 2048)) { g[--h] = (f & 63) | 128; g[--h] = (f >> 6) | 192 } else { g[--h] = (f & 63) | 128; g[--h] = ((f >> 6) & 63) | 128; g[--h] = (f >> 12) | 224 } } } g[--h] = 0; var b = new SecureRandom(); var a = new Array(); while (h > 2) { a[0] = 0; while (a[0] == 0) { b.nextBytes(a) } g[--h] = a[0] } g[--h] = 2; g[--h] = 0; return new BigInteger(g) } 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 } function RSASetPublic(b, a) { if (b != null && a != null && b.length > 0 && a.length > 0) { this.n = parseBigInt(b, 16); this.e = parseInt(a, 16); return this.n.toString(); } else { // alert("Invalid RSA public key") return 0; } } function RSADoPublic(a) { return a.modPowInt(this.e, this.n) } function RSAEncrypt(d) { var a = pkcs1pad2(d, (this.n.bitLength() + 7) >> 3); if (a == null) { return null } var e = this.doPublic(a); if (e == null) { return null } var b = e.toString(16); if ((b.length & 1) == 0) { return b } else { return "0" + b } return a; } RSAKey.prototype.doPublic = RSADoPublic; RSAKey.prototype.setPublic = RSASetPublic; RSAKey.prototype.encrypt = RSAEncrypt; var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var b64pad = "="; function hex2b64(d) { var b; var e; var a = ""; for (b = 0; b + 3 <= d.length; b += 3) { e = parseInt(d.substring(b, b + 3), 16); a += b64map.charAt(e >> 6) + b64map.charAt(e & 63) } if (b + 1 == d.length) { e = parseInt(d.substring(b, b + 1), 16); a += b64map.charAt(e << 2) } else { if (b + 2 == d.length) { e = parseInt(d.substring(b, b + 2), 16); a += b64map.charAt(e >> 2) + b64map.charAt((e & 3) << 4) } } while ((a.length & 3) > 0) { a += b64pad } return a } function b64tohex(e) { var c = ""; var d; var a = 0; var b; for (d = 0; d < e.length; ++d) { if (e.charAt(d) == b64pad) { break } v = b64map.indexOf(e.charAt(d)); if (v < 0) { continue } if (a == 0) { c += int2char(v >> 2); b = v & 3; a = 1 } else { if (a == 1) { c += int2char((b << 2) | (v >> 4)); b = v & 15; a = 2 } else { if (a == 2) { c += int2char(b); c += int2char(v >> 2); b = v & 3; a = 3 } else { c += int2char((b << 2) | (v >> 4)); c += int2char(v & 15); a = 0 } } } } if (a == 1) { c += int2char(b << 2) } return c } function b64toBA(e) { var d = b64tohex(e); var c; var b = new Array(); for (c = 0; 2 * c < d.length; ++c) { b[c] = parseInt(d.substring(2 * c, 2 * c + 2), 16) } return b };