¡¡¡¡JS¶Ë´úÂë:
¡¡¡¡
¡¡¡¡//Îļþbase64.js:
¡¡¡¡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;
¡¡¡¡}
¡¡¡¡// convert a base64 string to hex
¡¡¡¡function b64tohex(s) {
¡¡¡¡var ret = ""
¡¡¡¡var i;
¡¡¡¡var k = 0; // b64 state, 0-3
¡¡¡¡var slop;
¡¡¡¡for(i = 0; i < s.length; ++i) {
¡¡¡¡if(s.charAt(i) == b64pad) break;
¡¡¡¡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;
¡¡¡¡}
¡¡¡¡// convert a base64 string to a byte/number array
¡¡¡¡function b64toBA(s) {
¡¡¡¡//piggyback on b64tohex for now, optimize later
¡¡¡¡var h = b64tohex(s);
¡¡¡¡var i;
¡¡¡¡var a = new Array();
¡¡¡¡for(i = 0; 2*i < h.length; ++i) {
¡¡¡¡a[i] = parseInt(h.substring(2*i,2*i+2),16);
¡¡¡¡}
¡¡¡¡return a;
¡¡¡¡}
¡¡¡¡#Îļþjsbn.js
¡¡¡¡// Copyright (c) 2005 Tom Wu
¡¡¡¡// All Rights Reserved.
¡¡¡¡// See "LICENSE" for details.
¡¡¡¡// Basic JavaScript BN library - subset useful for RSA encryption.
¡¡¡¡// Bits per digit
¡¡¡¡var dbits;
¡¡¡¡// JavaScript engine analysis
¡¡¡¡var canary = 0xdeadbeefcafe;
¡¡¡¡var j_lm = ((canary&0xffffff)==0xefcafe);
¡¡¡¡// (public) Constructor
¡¡¡¡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);
¡¡¡¡}
¡¡¡¡// return new, unset BigInteger
¡¡¡¡function nbi() { return new BigInteger(null); }
¡¡¡¡// am: Compute w_j += (x*this_i), propagate carries,
¡¡¡¡// c is initial carry, returns final carry.
¡¡¡¡// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
¡¡¡¡// We need to select the fastest one that works in this environment.
¡¡¡¡// am1: use a single mult and divide to get the high bits,
¡¡¡¡// max digit bits should be 26 because
¡¡¡¡// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
¡¡¡¡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;
¡¡¡¡}
¡¡¡¡// am2 avoids a big mult-and-extract completely.
¡¡¡¡// Max digit bits should be <= 30 because we do bitwise ops
¡¡¡¡// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
¡¡¡¡function am2(i,x,w,j,c,n) {
¡¡¡¡var xl = x&0x7fff, 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;
¡¡¡¡}
¡¡¡¡// Alternately, set max digit bits to 28 since some
¡¡¡¡// browsers slow down when dealing with 32-bit numbers.
¡¡¡¡function am3(i,x,w,j,c,n) {
¡¡¡¡var xl = x&0x3fff, 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 && (navigator.appName == "Microsoft Internet Explorer")) {
¡¡¡¡BigInteger.prototype.am = am2;
¡¡¡¡dbits = 30;
¡¡¡¡}
¡¡¡¡else if(j_lm && (navigator.appName != "Netscape")) {
¡¡¡¡BigInteger.prototype.am = am1;
¡¡¡¡dbits = 26;
¡¡¡¡}
¡¡¡¡else { // Mozilla/Netscape seems to prefer am3
¡¡¡¡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;
¡¡¡¡// Digit conversions
¡¡¡¡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(n) { return BI_RM.charAt(n); }
¡¡¡¡function intAt(s,i) {
¡¡¡¡var c = BI_RC[s.charCodeAt(i)];
¡¡¡¡return (c==null)?-1:c;
¡¡¡¡}
¡¡¡¡// (protected) copy this to r
¡¡¡¡function bnpCopyTo(r) {
¡¡¡¡for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
¡¡¡¡r.t = this.t;
¡¡¡¡r.s = this.s;
¡¡¡¡}
¡¡¡¡// (protected) set from integer value x, -DV <= x < DV
¡¡¡¡function bnpFromInt(x) {
¡¡¡¡this.t = 1;
¡¡¡¡this.s = (x<0)?-1:0;
¡¡¡¡if(x > 0) this[0] = x;
¡¡¡¡else if(x < -1) this[0] = x+DV;
¡¡¡¡else this.t = 0;
¡¡¡¡}
¡¡¡¡// return bigint initialized to value
¡¡¡¡function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
¡¡¡¡// (protected) set from string and radix
¡¡¡¡function bnpFromString(s,b) {
¡¡¡¡var k;
¡¡¡¡if(b == 16) k = 4;
¡¡¡¡else if(b == 8) k = 3;
¡¡¡¡else if(b == 256) k = 8; // byte array
¡¡¡¡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, mi = false, 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);
¡¡¡¡}
¡¡¡¡// (protected) clamp off excess high words
¡¡¡¡function bnpClamp() {
¡¡¡¡var c = this.s&this.DM;
¡¡¡¡while(this.t > 0 && this[this.t-1] == c) --this.t;
¡¡¡¡}
¡¡¡¡// (public) return string representation in given radix
¡¡¡¡function bnToString(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, d, m = false, r = "", 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";
¡¡¡¡}
¡¡¡¡// (public) -this
¡¡¡¡function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
¡¡¡¡// (public) |this|
¡¡¡¡function bnAbs() { return (this.s<0)?this.negate():this; }
¡¡¡¡// (public) return + if this > a, - if this < a, 0 if equal
¡¡¡¡function bnCompareTo(a) {
¡¡¡¡var r = this.s-a.s;
¡¡¡¡if(r != 0) return r;
¡¡¡¡var i = this.t;
¡¡¡¡r = i-a.t;
¡¡¡¡if(r != 0) return r;
¡¡¡¡while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
¡¡¡¡return 0;
¡¡¡¡}
¡¡¡¡// returns bit length of the integer x
¡¡¡¡function nbits(x) {
¡¡¡¡var r = 1, 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;
¡¡¡¡}
¡¡¡¡// (public) return the number of bits in "this"
¡¡¡¡function bnBitLength() {
¡¡¡¡if(this.t <= 0) return 0;
¡¡¡¡return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
¡¡¡¡}
¡¡¡¡// (protected) r = this << n*DB
¡¡¡¡function bnpDLShiftTo(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;
¡¡¡¡}
¡¡¡¡// (protected) r = this >> n*DB
¡¡¡¡function bnpDRShiftTo(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;
¡¡¡¡}
¡¡¡¡// (protected) r = this << n
¡¡¡¡function bnpLShiftTo(n,r) {
¡¡¡¡var bs = n%this.DB;
¡¡¡¡var cbs = this.DB-bs;
¡¡¡¡var bm = (1<<cbs)-1;
¡¡¡¡var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
¡¡¡¡for(i = this.t-1; i >= 0; --i) {
¡¡¡¡r[i+ds+1] = (this[i]>>cbs)|c;
¡¡¡¡c = (this[i]&bm)<<bs;
¡¡¡¡}
¡¡¡¡for(i = ds-1; i >= 0; --i) r[i] = 0;
¡¡¡¡r[ds] = c;
¡¡¡¡r.t = this.t+ds+1;
¡¡¡¡r.s = this.s;
¡¡¡¡r.clamp();
¡¡¡¡}
¡¡¡¡// (protected) r = this >> n
¡¡¡¡function bnpRShiftTo(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();
¡¡¡¡}
¡¡¡¡// (protected) r = this - a
¡¡¡¡function bnpSubTo(a,r) {
¡¡¡¡var i = 0, c = 0, 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();
¡¡¡¡}
¡¡¡¡// (protected) r = this * a, r != this,a (HAC 14.12)
¡¡¡¡// "this" should be the larger one if appropriate.
¡¡¡¡function bnpMultiplyTo(a,r) {
¡¡¡¡var x = this.abs(), 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);
¡¡¡¡}
¡¡¡¡// (protected) r = this^2, r != this (HAC 14.16)
¡¡¡¡function bnpSquareTo(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();
¡¡¡¡}
¡¡¡¡// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
¡¡¡¡// r != q, this != m. q or r may be null.
¡¡¡¡function bnpDivRemTo(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(), ts = this.s, ms = m.s;
¡¡¡¡var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
¡¡¡¡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, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
¡¡¡¡var i = r.t, j = i-ys, 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); // "negative" y so we can replace sub with am later
¡¡¡¡while(y.t < ys) y[y.t++] = 0;
¡¡¡¡while(--j >= 0) {
¡¡¡¡// Estimate quotient digit
¡¡¡¡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) { // Try it out
¡¡¡¡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); // Denormalize remainder
¡¡¡¡if(ts < 0) BigInteger.ZERO.subTo(r,r);
¡¡¡¡}
¡¡¡¡// (public) this mod a
¡¡¡¡function bnMod(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;
¡¡¡¡}
¡¡¡¡// Modular reduction using "classic" algorithm
¡¡¡¡function Classic(m) { this.m = m; }
¡¡¡¡function cConvert(x) {
¡¡¡¡if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
¡¡¡¡else return x;
¡¡¡¡}
¡¡¡¡function cRevert(x) { return x; }
¡¡¡¡function cReduce(x) { x.divRemTo(this.m,null,x); }
¡¡¡¡function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
¡¡¡¡function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
¡¡¡¡Classic.prototype.convert = cConvert;
¡¡¡¡Classic.prototype.revert = cRevert;
¡¡¡¡Classic.prototype.reduce = cReduce;
¡¡¡¡Classic.prototype.mulTo = cMulTo;
¡¡¡¡Classic.prototype.sqrTo = cSqrTo;
¡¡¡¡// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
¡¡¡¡// justification:
¡¡¡¡// xy == 1 (mod m)
¡¡¡¡// xy = 1+km
¡¡¡¡// xy(2-xy) = (1+km)(1-km)
¡¡¡¡// x[y(2-xy)] = 1-k^2m^2
¡¡¡¡// x[y(2-xy)] == 1 (mod m^2)
¡¡¡¡// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
¡¡¡¡// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
¡¡¡¡// JS multiply "overflows" differently from C/C++, so care is needed here.
¡¡¡¡function bnpInvDigit() {
¡¡¡¡if(this.t < 1) return 0;
¡¡¡¡var x = this[0];
¡¡¡¡if((x&1) == 0) return 0;
¡¡¡¡var y = x&3; // y == 1/x mod 2^2
¡¡¡¡y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
¡¡¡¡y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
¡¡¡¡y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
¡¡¡¡// last step - calculate inverse mod DV directly;
¡¡¡¡// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
¡¡¡¡y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
¡¡¡¡// we really want the negative inverse, and -DV < y < DV
¡¡¡¡return (y>0)?this.DV-y:-y;
¡¡¡¡}
¡¡¡¡// Montgomery reduction
¡¡¡¡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;
¡¡¡¡}
¡¡¡¡// xR mod m
¡¡¡¡function montConvert(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;
¡¡¡¡}
¡¡¡¡// x/R mod m
¡¡¡¡function montRevert(x) {
¡¡¡¡var r = nbi();
¡¡¡¡x.copyTo(r);
¡¡¡¡this.reduce(r);
¡¡¡¡return r;
¡¡¡¡}
¡¡¡¡// x = x/R mod m (HAC 14.32)
¡¡¡¡function montReduce(x) {
¡¡¡¡while(x.t <= this.mt2) // pad x so am has enough room later
¡¡¡¡x[x.t++] = 0;
¡¡¡¡for(var i = 0; i < this.m.t; ++i) {
¡¡¡¡// faster way of calculating u0 = x[i]*mp mod DV
¡¡¡¡var j = x[i]&0x7fff;
¡¡¡¡var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
¡¡¡¡// use am to combine the multiply-shift-add into one call
¡¡¡¡j = i+this.m.t;
¡¡¡¡x[j] += this.m.am(0,u0,x,i,0,this.m.t);
¡¡¡¡// propagate carry
¡¡¡¡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);
¡¡¡¡}
¡¡¡¡// r = "x^2/R mod m"; x != r
¡¡¡¡function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
¡¡¡¡// r = "xy/R mod m"; x,y != r
¡¡¡¡function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
¡¡¡¡Montgomery.prototype.convert = montConvert;
¡¡¡¡Montgomery.prototype.revert = montRevert;
¡¡¡¡Montgomery.prototype.reduce = montReduce;
¡¡¡¡Montgomery.prototype.mulTo = montMulTo;
¡¡¡¡Montgomery.prototype.sqrTo = montSqrTo;
¡¡¡¡// (protected) true iff this is even
¡¡¡¡function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
¡¡¡¡// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
¡¡¡¡function bnpExp(e,z) {
¡¡¡¡if(e > 0xffffffff || e < 1) return BigInteger.ONE;
¡¡¡¡var r = nbi(), r2 = nbi(), g = z.convert(this), 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);
¡¡¡¡}
¡¡¡¡// (public) this^e % m, 0 <= e < 2^32
¡¡¡¡function bnModPowInt(e,m) {
¡¡¡¡var z;
¡¡¡¡if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
¡¡¡¡return this.exp(e,z);
¡¡¡¡}
¡¡¡¡// protected
¡¡¡¡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;
¡¡¡¡// public
¡¡¡¡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;
¡¡¡¡// "constants"
¡¡¡¡BigInteger.ZERO = nbv(0);
¡¡¡¡BigInteger.ONE = nbv(1);
¡¡¡¡#Îļþprng4.js
¡¡¡¡// prng4.js - uses Arcfour as a PRNG
¡¡¡¡function Arcfour() {
¡¡¡¡this.i = 0;
¡¡¡¡this.j = 0;
¡¡¡¡this.S = new Array();
¡¡¡¡}
¡¡¡¡// Initialize arcfour context from key, an array of ints, each from [0..255]
¡¡¡¡function ARC4init(key) {
¡¡¡¡var i, j, 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;
¡¡¡¡}
¡¡¡¡function ARC4next() {
¡¡¡¡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];
¡¡¡¡}
¡¡¡¡Arcfour.prototype.init = ARC4init;
¡¡¡¡Arcfour.prototype.next = ARC4next;
¡¡¡¡// Plug in your RNG constructor here
¡¡¡¡function prng_newstate() {
¡¡¡¡return new Arcfour();
¡¡¡¡}
¡¡¡¡// Pool size must be a multiple of 4 and greater than 32.
¡¡¡¡// An array of bytes the size of the pool will be passed to init()
¡¡¡¡var rng_psize = 256;
¡¡¡¡Îļþ:rng.js
¡¡¡¡// Random number generator - requires a PRNG backend, e.g. prng4.js
¡¡¡¡// For best results, put code like
¡¡¡¡// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>
¡¡¡¡// in your main HTML document.
¡¡¡¡var rng_state;
¡¡¡¡var rng_pool;
¡¡¡¡var rng_pptr;
¡¡¡¡// Mix in a 32-bit integer into the pool
¡¡¡¡function rng_seed_int(x) {
¡¡¡¡rng_pool[rng_pptr++] ^= x & 255;
¡¡¡¡rng_pool[rng_pptr++] ^= (x >> 8) & 255;
¡¡¡¡rng_pool[rng_pptr++] ^= (x >> 16) & 255;
¡¡¡¡rng_pool[rng_pptr++] ^= (x >> 24) & 255;
¡¡¡¡if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;
¡¡¡¡}
¡¡¡¡// Mix in the current time (w/milliseconds) into the pool
¡¡¡¡function rng_seed_time() {
¡¡¡¡rng_seed_int(new Date().getTime());
¡¡¡¡}
¡¡¡¡// Initialize the pool with junk if needed.
¡¡¡¡if(rng_pool == null) {
¡¡¡¡rng_pool = new Array();
¡¡¡¡rng_pptr = 0;
¡¡¡¡var t;
¡¡¡¡if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) {
¡¡¡¡// Extract entropy (256 bits) from NS4 RNG if available
¡¡¡¡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) { // extract some randomness from Math.random()
¡¡¡¡t = Math.floor(65536 * Math.random());
¡¡¡¡rng_pool[rng_pptr++] = t >>> 8;
¡¡¡¡rng_pool[rng_pptr++] = t & 255;
¡¡¡¡}
¡¡¡¡rng_pptr = 0;
¡¡¡¡rng_seed_time();
¡¡¡¡//rng_seed_int(window.screenX);
¡¡¡¡//rng_seed_int(window.screenY);
¡¡¡¡}
¡¡¡¡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;
¡¡¡¡//rng_pool = null;
¡¡¡¡}
¡¡¡¡// TODO: allow reseeding after first request
¡¡¡¡return rng_state.next();
¡¡¡¡}
¡¡¡¡function rng_get_bytes(ba) {
¡¡¡¡var i;
¡¡¡¡for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();
¡¡¡¡}
¡¡¡¡function SecureRandom() {}
¡¡¡¡SecureRandom.prototype.nextBytes = rng_get_bytes;
¡¡¡¡#Îļþ:rsa.js
¡¡¡¡// Depends on jsbn.js and rng.js
¡¡¡¡// Version 1.1: support utf-8 encoding in pkcs1pad2
¡¡¡¡// convert a (hex) string to a bignum object
¡¡¡¡function parseBigInt(str,r) {
¡¡¡¡return new BigInteger(str,r);
¡¡¡¡}
¡¡¡¡function linebrk(s,n) {
¡¡¡¡var ret = "";
¡¡¡¡var i = 0;
¡¡¡¡while(i + n < s.length) {
¡¡¡¡ret += s.substring(i,i+n) + "\n";
¡¡¡¡i += n;
¡¡¡¡}
¡¡¡¡return ret + s.substring(i,s.length);
¡¡¡¡}
¡¡¡¡function byte2Hex(b) {
¡¡¡¡if(b < 0x10)
¡¡¡¡return "0" + b.toString(16);
¡¡¡¡else
¡¡¡¡return b.toString(16);
¡¡¡¡}
¡¡¡¡// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
¡¡¡¡function pkcs1pad2(s,n) {
¡¡¡¡if(n < s.length + 11) { // TODO: fix for utf-8
¡¡¡¡alert("Message too long for RSA");
¡¡¡¡return null;
¡¡¡¡}
¡¡¡¡var ba = new Array();
¡¡¡¡var i = s.length - 1;
¡¡¡¡while(i >= 0 && n > 0) {
¡¡¡¡var c = s.charCodeAt(i--);
¡¡¡¡if(c < 128) { // encode using utf-8
¡¡¡¡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 = new Array();
¡¡¡¡while(n > 2) { // random non-zero pad
¡¡¡¡x[0] = 0;
¡¡¡¡while(x[0] == 0) rng.nextBytes(x);
¡¡¡¡ba[--n] = x[0];
¡¡¡¡}
¡¡¡¡ba[--n] = 2;
¡¡¡¡ba[--n] = 0;
¡¡¡¡return new BigInteger(ba);
¡¡¡¡}
¡¡¡¡// "empty" RSA key constructor
¡¡¡¡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;
¡¡¡¡}
¡¡¡¡// Set the public key fields N and e from hex strings
¡¡¡¡function RSASetPublic(N,E) {
¡¡¡¡if(N != null && E != null && N.length > 0 && E.length > 0) {
¡¡¡¡this.n = parseBigInt(N,16);
¡¡¡¡this.e = parseInt(E,16);
¡¡¡¡}
¡¡¡¡else
¡¡¡¡alert("Invalid RSA public key");
¡¡¡¡}
¡¡¡¡// Perform raw public operation on "x": return x^e (mod n)
¡¡¡¡function RSADoPublic(x) {
¡¡¡¡return x.modPowInt(this.e, this.n);
¡¡¡¡}
¡¡¡¡// Return the PKCS#1 RSA encryption of "text" as an even-length hex string
¡¡¡¡function RSAEncrypt(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;
¡¡¡¡}
¡¡¡¡// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
¡¡¡¡//function RSAEncryptB64(text) {
¡¡¡¡// var h = this.encrypt(text);
¡¡¡¡// if(h) return hex2b64(h); else return null;
¡¡¡¡//}
¡¡¡¡// protected
¡¡¡¡RSAKey.prototype.doPublic = RSADoPublic;
¡¡¡¡// public
¡¡¡¡RSAKey.prototype.setPublic = RSASetPublic;
¡¡¡¡RSAKey.prototype.encrypt = RSAEncrypt;
¡¡¡¡//RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
¡¡¡¡HTML´úÂ벿·Ö:
¡¡¡¡
¡¡¡¡<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
¡¡¡¡<html>
¡¡¡¡<head>
¡¡¡¡<title>JavaScript RSA Encryption Demo</title>
¡¡¡¡</head>
¡¡¡¡<script language="JavaScript" type="text/javascript" src="./js/jsbn.js"></script>
¡¡¡¡<script language="JavaScript" type="text/javascript" src="./js/prng4.js"></script>
¡¡¡¡<script language="JavaScript" type="text/javascript" src="./js/rng.js"></script>
¡¡¡¡<script language="JavaScript" type="text/javascript" src="./js/rsa.js"></script>
¡¡¡¡<script language="JavaScript" type="text/javascript" src="./js/base64.js"></script>
¡¡¡¡<script language="JavaScript">
¡¡¡¡//publc key and public length 16 binary data
¡¡¡¡var public_key="00b0c2732193eebde5b2e278736a22977a5ee1bb99bea18c0681ad97484b4c7f681e963348eb80667b954534293b0a6cbe2f9651fc98c9ee833f343e719c97c670ead8bec704282f94d9873e083cfd41554f356f00aea38d2b07551733541b64790c2c8f400486fd662a3e95fd5edd2acf4d59ca97fad65cc59b8d10cbc5430c53";
¡¡¡¡var public_length="10001";
¡¡¡¡function do_encrypt() {
¡¡¡¡var before = new Date();
¡¡¡¡var rsa = new RSAKey();
¡¡¡¡rsa.setPublic(public_key, public_length);
¡¡¡¡var res = rsa.encrypt(document.rsatest.plaintext.value);
¡¡¡¡var after = new Date();
¡¡¡¡if(res) {
¡¡¡¡document.rsatest.ciphertext.value =res;
¡¡¡¡document.rsatest.cipherb64.value = hex2b64(res);
¡¡¡¡document.rsatest.status.value = "Time: " + (after - before) + "ms";
¡¡¡¡}
¡¡¡¡}
¡¡¡¡//-->
¡¡¡¡</script>
¡¡¡¡<form name="rsatest" action="rsa-example.php" method="post">
¡¡¡¡Plaintext (string):<br>
¡¡¡¡<input name="plaintext" type="text" value="test" size=40>
¡¡¡¡<input type="button" value="encrypt" onClick="do_encrypt();"><p>
¡¡¡¡Ciphertext (hex):<br>
¡¡¡¡<textarea name="ciphertext" rows=4 cols=70></textarea><p>
¡¡¡¡Ciphertext (base64):(Not used)<br>
¡¡¡¡<textarea name="cipherb64" rows=3 cols=70></textarea><p>
¡¡¡¡Status:<br>
¡¡¡¡<input name="status" type="text" size=40><p>
¡¡¡¡<input type="submit" value="go php" />
¡¡¡¡</form>
¡¡¡¡</body>
¡¡¡¡</html>
¡¡¡¡ºó¶ËPHP²¿·Ö:
¡¡¡¡RSA¿â:
¡¡¡¡
¡¡¡¡<?php
¡¡¡¡/*
¡¡¡¡* PHP implementation of the RSA algorithm
¡¡¡¡* (C) Copyright 2004 Edsko de Vries, Ireland
¡¡¡¡*
¡¡¡¡* Licensed under the GNU Public License (GPL)
¡¡¡¡*
¡¡¡¡* This implementation has been verified against [3]
¡¡¡¡* (tested Java/PHP interoperability).
¡¡¡¡*
¡¡¡¡* References:
¡¡¡¡* [1] "Applied Cryptography", Bruce Schneier, John Wiley & Sons, 1996
¡¡¡¡* [2] "Prime Number Hide-and-Seek", Brian Raiter, Muppetlabs (online)
¡¡¡¡* [3] "The Bouncy Castle Crypto Package", Legion of the Bouncy Castle,
¡¡¡¡* (open source cryptography library for Java, online)
¡¡¡¡* [4] "PKCS #1: RSA Encryption Standard", RSA Laboratories Technical Note,
¡¡¡¡* version 1.5, revised November 1, 1993
¡¡¡¡*/
¡¡¡¡/*
¡¡¡¡* Functions that are meant to be used by the user of this PHP module.
¡¡¡¡*
¡¡¡¡* Notes:
¡¡¡¡* - $key and $modulus should be numbers in (decimal) string format
¡¡¡¡* - $message is expected to be binary data
¡¡¡¡* - $keylength should be a multiple of 8, and should be in bits
¡¡¡¡* - For rsa_encrypt/rsa_sign, the length of $message should not exceed
¡¡¡¡* ($keylength / 8) - 11 (as mandated by [4]).
¡¡¡¡* - rsa_encrypt and rsa_sign will automatically add padding to the message.
¡¡¡¡* For rsa_encrypt, this padding will consist of random values; for rsa_sign,
¡¡¡¡* padding will consist of the appropriate number of 0xFF values (see [4])
¡¡¡¡* - rsa_decrypt and rsa_verify will automatically remove message padding.
¡¡¡¡* - Blocks for decoding (rsa_decrypt, rsa_verify) should be exactly
¡¡¡¡* ($keylength / 8) bytes long.
¡¡¡¡* - rsa_encrypt and rsa_verify expect a public key; rsa_decrypt and rsa_sign
¡¡¡¡* expect a private key.
¡¡¡¡*/
¡¡¡¡/**
¡¡¡¡* ÓÚ2010-11-12 1:06·ÖÓÚLONELYÐÞ¸Ä
¡¡¡¡*/
¡¡¡¡function rsa_encrypt($message, $public_key, $modulus, $keylength)
¡¡¡¡{
¡¡¡¡$padded = add_PKCS1_padding($message, true, $keylength / 8);
¡¡¡¡$number = binary_to_number($padded);
¡¡¡¡$encrypted = pow_mod($number, $public_key, $modulus);
¡¡¡¡$result = number_to_binary($encrypted, $keylength / 8);
¡¡¡¡return $result;
¡¡¡¡}
¡¡¡¡function rsa_decrypt($message, $private_key, $modulus, $keylength)
¡¡¡¡{
¡¡¡¡$number = binary_to_number($message);
¡¡¡¡$decrypted = pow_mod($number, $private_key, $modulus);
¡¡¡¡$result = number_to_binary($decrypted, $keylength / 8);
¡¡¡¡return remove_PKCS1_padding($result, $keylength / 8);
¡¡¡¡}
¡¡¡¡function rsa_sign($message, $private_key, $modulus, $keylength)
¡¡¡¡{
¡¡¡¡$padded = add_PKCS1_padding($message, false, $keylength / 8);
¡¡¡¡$number = binary_to_number($padded);
¡¡¡¡$signed = pow_mod($number, $private_key, $modulus);
¡¡¡¡$result = number_to_binary($signed, $keylength / 8);
¡¡¡¡return $result;
¡¡¡¡}
¡¡¡¡function rsa_verify($message, $public_key, $modulus, $keylength)
¡¡¡¡{
¡¡¡¡return rsa_decrypt($message, $public_key, $modulus, $keylength);
¡¡¡¡}
¡¡¡¡function rsa_kyp_verify($message, $public_key, $modulus, $keylength)
¡¡¡¡{
¡¡¡¡$number = binary_to_number($message);
¡¡¡¡$decrypted = pow_mod($number, $public_key, $modulus);
¡¡¡¡$result = number_to_binary($decrypted, $keylength / 8);
¡¡¡¡return remove_KYP_padding($result, $keylength / 8);
¡¡¡¡}
¡¡¡¡/*
¡¡¡¡* Some constants
¡¡¡¡*/
¡¡¡¡define("BCCOMP_LARGER", 1);
¡¡¡¡/*
¡¡¡¡* The actual implementation.
¡¡¡¡* Requires BCMath support in PHP (compile with --enable-bcmath)
¡¡¡¡*/
¡¡¡¡//--
¡¡¡¡// Calculate (p ^ q) mod r
¡¡¡¡//
¡¡¡¡// We need some trickery to [2]:
¡¡¡¡// (a) Avoid calculating (p ^ q) before (p ^ q) mod r, because for typical RSA
¡¡¡¡// applications, (p ^ q) is going to be _WAY_ too large.
¡¡¡¡// (I mean, __WAY__ too large - won't fit in your computer's memory.)
¡¡¡¡// (b) Still be reasonably efficient.
¡¡¡¡//
¡¡¡¡// We assume p, q and r are all positive, and that r is non-zero.
¡¡¡¡//
¡¡¡¡// Note that the more simple algorithm of multiplying $p by itself $q times, and
¡¡¡¡// applying "mod $r" at every step is also valid, but is O($q), whereas this
¡¡¡¡// algorithm is O(log $q). Big difference.
¡¡¡¡//
¡¡¡¡// As far as I can see, the algorithm I use is optimal; there is no redundancy
¡¡¡¡// in the calculation of the partial results.
¡¡¡¡//--
¡¡¡¡function pow_mod($p, $q, $r)
¡¡¡¡{
¡¡¡¡// Extract powers of 2 from $q
¡¡¡¡$factors = array();
¡¡¡¡$div = $q;
¡¡¡¡$power_of_two = 0;
¡¡¡¡while(bccomp($div, "0") == BCCOMP_LARGER)
¡¡¡¡{
¡¡¡¡$rem = bcmod($div, 2);
¡¡¡¡$div = bcdiv($div, 2);
¡¡¡¡if($rem) array_push($factors, $power_of_two);
¡¡¡¡$power_of_two++;
¡¡¡¡}
¡¡¡¡// Calculate partial results for each factor, using each partial result as a
¡¡¡¡// starting point for the next. This depends of the factors of two being
¡¡¡¡// generated in increasing order.
¡¡¡¡$partial_results = array();
¡¡¡¡$part_res = $p;
¡¡¡¡$idx = 0;
¡¡¡¡foreach($factors as $factor)
¡¡¡¡{
¡¡¡¡while($idx < $factor)
¡¡¡¡{
¡¡¡¡$part_res = bcpow($part_res, "2");
¡¡¡¡$part_res = bcmod($part_res, $r);
¡¡¡¡$idx++;
¡¡¡¡}
¡¡¡¡array_push($partial_results, $part_res);
¡¡¡¡}
¡¡¡¡// Calculate final result
¡¡¡¡$result = "1";
¡¡¡¡foreach($partial_results as $part_res)
¡¡¡¡{
¡¡¡¡$result = bcmul($result, $part_res);
¡¡¡¡$result = bcmod($result, $r);
¡¡¡¡}
¡¡¡¡return $result;
¡¡¡¡}
¡¡¡¡//--
¡¡¡¡// Function to add padding to a decrypted string
¡¡¡¡// We need to know if this is a private or a public key operation [4]
¡¡¡¡//--
¡¡¡¡function add_PKCS1_padding($data, $isPublicKey, $blocksize)
¡¡¡¡{
¡¡¡¡$pad_length = $blocksize - 3 - strlen($data);
¡¡¡¡if($isPublicKey)
¡¡¡¡{
¡¡¡¡$block_type = "\x02";
¡¡¡¡$padding = "";
¡¡¡¡for($i = 0; $i < $pad_length; $i++)
¡¡¡¡{
¡¡¡¡$rnd = mt_rand(1, 255);
¡¡¡¡$padding .= chr($rnd);
¡¡¡¡}
¡¡¡¡}
¡¡¡¡else
¡¡¡¡{
¡¡¡¡$block_type = "\x01";
¡¡¡¡$padding = str_repeat("\xFF", $pad_length);
¡¡¡¡}
¡¡¡¡return "\x00" . $block_type . $padding . "\x00" . $data;
¡¡¡¡}
¡¡¡¡//--
¡¡¡¡// Remove padding from a decrypted string
¡¡¡¡// See [4] for more details.
¡¡¡¡//--
¡¡¡¡function remove_PKCS1_padding($data, $blocksize)
¡¡¡¡{
¡¡¡¡//ÒÔϲ¿·ÖÓÚÔ°æµÄRSAÓÐËù²»Í¬,ÐÞ¸´ÁËÔ°æµÄÒ»¸öBUG
¡¡¡¡//assert(strlen($data) == $blocksize);
¡¡¡¡$data = substr($data, 1);
¡¡¡¡// We cannot deal with block type 0
¡¡¡¡if($data{0} == '\0')
¡¡¡¡die("Block type 0 not implemented.");
¡¡¡¡// Then the block type must be 1 or 2
¡¡¡¡//assert(($data{0} == "\x01") || ($data{0} == "\x02"));
¡¡¡¡// echo $data;
¡¡¡¡// Remove the padding
¡¡¡¡$i=1;
¡¡¡¡while (1){
¡¡¡¡$offset = strpos($data, "\0", $i);
¡¡¡¡if(!$offset){
¡¡¡¡$offset=$i;
¡¡¡¡break;
¡¡¡¡}
¡¡¡¡$i=$offset+1;
¡¡¡¡}
¡¡¡¡//$offset = strpos($data, "\0", 100);
¡¡¡¡return substr($data, $offset);
¡¡¡¡}
¡¡¡¡//--
¡¡¡¡// Remove "kyp" padding
¡¡¡¡// (Non standard)
¡¡¡¡//--
¡¡¡¡function remove_KYP_padding($data, $blocksize)
¡¡¡¡{
¡¡¡¡assert(strlen($data) == $blocksize);
¡¡¡¡$offset = strpos($data, "\0");
¡¡¡¡return substr($data, 0, $offset);
¡¡¡¡}
¡¡¡¡//--
¡¡¡¡// Convert binary data to a decimal number
¡¡¡¡//--
¡¡¡¡function binary_to_number($data)
¡¡¡¡{
¡¡¡¡$base = "256";
¡¡¡¡$radix = "1";
¡¡¡¡$result = "0";
¡¡¡¡for($i = strlen($data) - 1; $i >= 0; $i--)
¡¡¡¡{
¡¡¡¡$digit = ord($data{$i});
¡¡¡¡$part_res = bcmul($digit, $radix);
¡¡¡¡$result = bcadd($result, $part_res);
¡¡¡¡$radix = bcmul($radix, $base);
¡¡¡¡}
¡¡¡¡return $result;
¡¡¡¡}
¡¡¡¡//--
¡¡¡¡// Convert a number back into binary form
¡¡¡¡//--
¡¡¡¡function number_to_binary($number, $blocksize)
¡¡¡¡{
¡¡¡¡$base = "256";
¡¡¡¡$result = "";
¡¡¡¡$div = $number;
¡¡¡¡while($div > 0)
¡¡¡¡{
¡¡¡¡$mod = bcmod($div, $base);
¡¡¡¡$div = bcdiv($div, $base);
¡¡¡¡$result = chr($mod) . $result;
¡¡¡¡}
¡¡¡¡return str_pad($result, $blocksize, "\x00", STR_PAD_LEFT);
¡¡¡¡}
¡¡¡¡?>
¡¡¡¡´¦ÀíµÄPHP´úÂë:
¡¡¡¡
¡¡¡¡<?php
¡¡¡¡//Decimal Data
¡¡¡¡include "rsa.php";
¡¡¡¡$modulus='124124790696783899579957666732205416556275207289308772677367395397704314099727565633927507139389670490184904760526156031441045563225987129220634807383637837918320623518532877734472159024203477820731033762885040862183213160281165618500092483026873487507336293388981515466164416989192069833140532570993394388051.0000000000';
¡¡¡¡$private='59940207454900542501281722336097731406274284149290386158861762508911700758780200454438527029729836453810395133453343700246367853044479311924174899432036400630350527132581124575735909908195078492323048176864577497230467497768502277772070557874686662727818507841304646138785432507752788647631021854537869399041.0000000000';
¡¡¡¡$public="65537";
¡¡¡¡$keylength="1024";
¡¡¡¡//php encrypt create
¡¡¡¡//$encrypted = rsa_encrypt("vzxcvz bdxf", $public, $modulus, $keylength);
¡¡¡¡//$str= bin2hex($encrypted);//bin data to hex data
¡¡¡¡$str=$_POST['ciphertext'];
¡¡¡¡//echo $str."<br>";
¡¡¡¡$encrypted=convert($str); //hex data to bin data
¡¡¡¡$decrypted = rsa_decrypt($encrypted, $private, $modulus, $keylength);
¡¡¡¡echo $decrypted."<br>";
¡¡¡¡/**
¡¡¡¡* 16 to 2
¡¡¡¡* @param unknown_type $hexString
¡¡¡¡* @return string|unknown
¡¡¡¡*/
¡¡¡¡function convert($hexString)
¡¡¡¡{
¡¡¡¡$hexLenght = strlen($hexString);
¡¡¡¡// only hex numbers is allowed
¡¡¡¡if ($hexLenght % 2 != 0 || preg_match("/[^\da-fA-F]/",$hexString)) return FALSE;
¡¡¡¡unset($binString);
¡¡¡¡for ($x = 1; $x <= $hexLenght/2; $x++)
¡¡¡¡{
¡¡¡¡$binString .= chr(hexdec(substr($hexString,2 * $x - 2,2)));
¡¡¡¡}
¡¡¡¡return $binString;
¡¡¡¡}
¡¡¡¡?>
¡¡¡¡Éú³ÉPRMÎļþ¼°Éú²úÐèÒªµÄÃÜÔ¿¼°¹«Ô¿µÄPHPÎļþ:
¡¡¡¡
¡¡¡¡<?php
¡¡¡¡//create pem file
¡¡¡¡//run openssl genrsa -out key.pem 1024
¡¡¡¡//This file is generated variables needed for the operation
¡¡¡¡list($keylength, $modulus, $public, $private,$modulus_js,$private_js) = read_ssl_key("key.pem");
¡¡¡¡echo "keylength:(php and js)(private length)<br>";
¡¡¡¡echo $keylength;
¡¡¡¡echo "<br>";
¡¡¡¡echo "modulus:(php)(10)(pubic key)<br>";
¡¡¡¡echo $modulus;
¡¡¡¡echo "<br>";
¡¡¡¡echo "modulus:(js)(16)(pubic key)<br>";
¡¡¡¡echo $modulus_js;
¡¡¡¡echo "<br>";
¡¡¡¡echo "public:(php)(10)(public exponent)<br>";
¡¡¡¡echo $public;
¡¡¡¡echo "<br>";
¡¡¡¡echo "public:(js)(16)(public exponent)<br>";
¡¡¡¡echo "10001";
¡¡¡¡echo "<br>";
¡¡¡¡echo "private:(php)(10)(private key)<br>";
¡¡¡¡echo $private;
¡¡¡¡echo "<br>";
¡¡¡¡echo "private:(js)(16)(private key)<br>";
¡¡¡¡echo $private_js;
¡¡¡¡//function
¡¡¡¡function read_ssl_key($filename)
¡¡¡¡{
¡¡¡¡exec("openssl rsa -in $filename -text -noout", $raw);
¡¡¡¡// read the key length
¡¡¡¡$keylength = (int) expect($raw[0], "Private-Key: (");
¡¡¡¡// read the modulus
¡¡¡¡expect($raw[1], "modulus:");
¡¡¡¡for($i = 2; $raw[$i][0] == ' '; $i++) $modulusRaw .= trim($raw[$i]);
¡¡¡¡// read the public exponent
¡¡¡¡$public = (int) expect($raw[$i], "publicExponent: ");
¡¡¡¡// read the private exponent
¡¡¡¡expect($raw[$i + 1], "privateExponent:");
¡¡¡¡for($i += 2; $raw[$i][0] == ' '; $i++) $privateRaw .= trim($raw[$i]);
¡¡¡¡// Just to make sure
¡¡¡¡expect($raw[$i], "prime1:");
¡¡¡¡// Conversion to decimal format for bcmath
¡¡¡¡$modulus = bc_hexdec($modulusRaw);
¡¡¡¡$private = bc_hexdec($privateRaw);
¡¡¡¡return array($keylength, $modulus['php'], $public, $private['php'],$modulus['js'], $private['js']);
¡¡¡¡}
¡¡¡¡/*
¡¡¡¡* Convert a hexadecimal number of the form "XX:YY:ZZ:..." to decimal
¡¡¡¡* Uses BCmath, but the standard normal hexdec function for the components
¡¡¡¡*/
¡¡¡¡function bc_hexdec($hex)
¡¡¡¡{
¡¡¡¡$coefficients = explode(":", $hex);
¡¡¡¡$result_js= implode("",$coefficients);
¡¡¡¡$i = 0;
¡¡¡¡$result = 0;
¡¡¡¡foreach(array_reverse($coefficients) as $coefficient)
¡¡¡¡{
¡¡¡¡$mult = bcpow(256, $i++);
¡¡¡¡$result = bcadd($result, bcmul(hexdec($coefficient), $mult));
¡¡¡¡}
¡¡¡¡return array('php'=>$result,'js'=>$result_js);
¡¡¡¡}
¡¡¡¡/*
¡¡¡¡* If the string has the given prefix, return the remainder.
¡¡¡¡* If not, die with an error
¡¡¡¡*/
¡¡¡¡function expect($str, $prefix)
¡¡¡¡{
¡¡¡¡if(substr($str, 0, strlen($prefix)) == $prefix)
¡¡¡¡return substr($str, strlen($prefix));
¡¡¡¡else
¡¡¡¡die("Error: expected $prefix");
¡¡¡¡}
¡¡¡¡ÕûÌ×¼ÓÃܼ°½âÃܵķ½·¨¶¼ÔÚÉÏÃæÁË,±¾È˵IJâÊÔ»·¾³Îªphp5.3+WIN7
¡¡¡¡ÉÏÃæËùÓÐÎļþÏÂÔØ:RSAFILE