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生成静态页面详解
Dec 05 PHP
PHP操作MongoDB时的整数问题及对策说明
May 02 PHP
php中模拟POST传递数据的两种方法分享
Sep 16 PHP
探讨如何使用SimpleXML函数来加载和解析XML文档
Jun 07 PHP
深入PHP curl参数的详解
Jun 17 PHP
利用PHP实现短域名互转
Jul 05 PHP
分享最受欢迎的5款PHP框架
Nov 27 PHP
PHP错误机制知识汇总
Mar 24 PHP
php无法连接mysql数据库的正确解决方法
Jul 01 PHP
php生成0~1随机小数的方法(必看)
Apr 05 PHP
PHP定义字符串的四种方式详解
Feb 06 PHP
PHP PDOStatement::setFetchMode讲解
Feb 03 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
PHP中用接口、抽象类、普通基类实现“面向接口编程”与“耦合方法”简述
2011/03/23 PHP
php 模拟GMAIL,HOTMAIL(MSN),YAHOO,163,126邮箱登录的详细介绍
2013/06/18 PHP
PHP中浮点数计算比较及取整不准确的解决方法
2015/01/09 PHP
Js 获取HTML DOM节点元素的方法小结
2009/04/24 Javascript
JavaScript charCodeAt方法入门实例(用于取得指定位置字符的Unicode编码)
2014/10/17 Javascript
jQuery遍历json中多个map的方法
2015/02/12 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(二)
2016/05/17 Javascript
AngularJs Managing Service Dependencies详解
2016/09/02 Javascript
简单实现Bootstrap标签页
2020/08/09 Javascript
浅谈angular4 ng-content 中隐藏的内容
2017/08/18 Javascript
基于DOM节点删除之empty和remove的区别(详解)
2017/09/11 Javascript
vue2.0使用v-for循环制作多级嵌套菜单栏
2018/06/25 Javascript
解决layer.confirm选择完之后消息框不消失的问题
2019/09/16 Javascript
微信小程序实现横向滚动导航栏效果
2019/12/12 Javascript
Jquery高级应用Deferred对象原理及使用实例
2020/05/28 jQuery
Vue2.0 $set()的正确使用详解
2020/07/28 Javascript
JavaScript 如何计算文本的行数的实现
2020/09/14 Javascript
Python学习笔记整理3之输入输出、python eval函数
2015/12/14 Python
学习python之编写简单简单连接数据库并执行查询操作
2016/02/27 Python
Python Socket编程之多线程聊天室
2018/07/28 Python
浅述python2与python3的简单区别
2018/09/19 Python
Python深拷贝与浅拷贝用法实例分析
2019/05/05 Python
python list转置和前后反转的例子
2019/08/26 Python
python中matplotlib条件背景颜色的实现
2019/09/02 Python
python使用rsa非对称加密过程解析
2019/12/28 Python
使用Python爬虫库BeautifulSoup遍历文档树并对标签进行操作详解
2020/01/25 Python
解决keras加入lambda层时shape的问题
2020/06/11 Python
windows+vscode安装paddleOCR运行环境的步骤
2020/11/11 Python
Ticketmaster德国票务网站:购买音乐会和体育等门票
2016/11/14 全球购物
斯图尔特·韦茨曼鞋加拿大官网:Stuart Weitzman加拿大
2019/10/13 全球购物
在什么时候需要使用"常引用"
2015/12/31 面试题
数控技校生自我鉴定
2014/03/02 职场文书
银行求职信怎么写
2014/05/26 职场文书
2014年维稳工作总结
2014/11/18 职场文书
开学季:喜迎新生,迎新标语少不了
2019/11/07 职场文书
剑指Offer之Java算法习题精讲二叉树专项训练
2022/03/21 Java/Android