PHP+JS+rsa数据加密传输实现代码


Posted in PHP onMarch 23, 2011

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"); 
}

整套加密及解密的方法都在上面了,本人的测试环境为php5.3+WIN7
上面所有文件下载:RSAFILE
PHP 相关文章推荐
由php if 想到的些问题
Mar 22 PHP
深入解析php之sphinx
May 15 PHP
深入密码加salt原理的分析
Jun 06 PHP
php获取参数的几种方法总结
Feb 18 PHP
去掉destoon资讯内容页keywords关键字自带的文章标题的方法
Aug 21 PHP
php中使用GD库做验证码
Mar 31 PHP
PHP导出带样式的Excel示例代码
Aug 28 PHP
探究Laravel使用env函数读取环境变量为null的问题
Dec 06 PHP
PHP设计模式之工厂模式实例总结
Sep 01 PHP
laravel 时间格式转时间戳的例子
Oct 11 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
Oct 16 PHP
PhpSpreadsheet设置单元格常用操作汇总
Nov 13 PHP
PHP 事件机制(2)
Mar 23 #PHP
php函数之子字符串替换&amp;#65279; str_replace
Mar 23 #PHP
php expects parameter 1 to be resource, array given 错误
Mar 23 #PHP
php去掉字符串的最后一个字符附substr()的用法
Mar 23 #PHP
PHPUnit PHP测试框架安装方法
Mar 23 #PHP
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
Mar 19 #PHP
windows下开发并编译PHP扩展的方法
Mar 18 #PHP
You might like
星际流派综述
2020/03/04 星际争霸
使用sockets:从新闻组中获取文章(一)
2006/10/09 PHP
php将时间差转换为字符串提示
2011/09/07 PHP
JS获取IUSR_机器名和IWAM_机器名帐号的密码
2006/12/06 Javascript
基于Jquery的淡入淡出的特效基础练习
2010/12/13 Javascript
基于jquery的二级联动菜单实现代码
2011/04/25 Javascript
firefox下jQuery UI Autocomplete 1.8.*中文输入修正方法
2012/09/19 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
2013/11/14 Javascript
浅析jquery的作用与优势
2013/12/02 Javascript
JavaScript中的关联数组问题
2015/03/04 Javascript
js将json格式的对象拼接成复杂的url参数方法
2016/05/25 Javascript
node.js 中国天气预报 简单实现
2016/06/06 Javascript
JavaScript接口的实现三种方式(推荐)
2016/06/14 Javascript
微信小程序 缓存(本地缓存、异步缓存、同步缓存)详解
2017/01/17 Javascript
Vue 2.x教程之基础API
2017/03/06 Javascript
详解Vue 全局引入bass.scss 处理方案
2018/03/26 Javascript
vue.js中npm安装教程图解
2018/04/10 Javascript
Vue 使用 Mint UI 实现左滑删除效果CellSwipe
2018/04/27 Javascript
vue-cli 默认路由再子路由选中下的选中状态问题及解决代码
2018/09/06 Javascript
vue实现的网易云音乐在线播放和下载功能案例
2019/02/18 Javascript
JavaScript定时器设置、使用与倒计时案例详解
2019/07/08 Javascript
es6函数中的作用域实例分析
2020/04/18 Javascript
Vue.js中使用Vuex实现组件数据共享案例
2020/07/31 Javascript
深入分析在Python模块顶层运行的代码引起的一个Bug
2014/07/04 Python
在阿里云服务器上配置CentOS+Nginx+Python+Flask环境
2016/06/18 Python
Python操作csv文件实例详解
2017/07/31 Python
如何在python字符串中输入纯粹的{}
2018/08/22 Python
pandas通过loc生成新的列方法
2018/11/28 Python
python版本五子棋的实现代码
2018/12/11 Python
Python使用QQ邮箱发送邮件报错smtplib.SMTPAuthenticationError
2019/12/20 Python
Java中的基本数据类型所占存储空间大小固定的吗
2012/02/15 面试题
建筑工程专业学生的自我评价
2013/12/25 职场文书
五好文明家庭事迹材料
2014/12/20 职场文书
单位实习鉴定评语
2015/01/04 职场文书
初三英语教学计划
2015/01/23 职场文书
管理失职检讨书范文
2015/05/05 职场文书