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读取和编写XML DOM的实现代码
Feb 03 PHP
WordPress判断用户是否登录的代码
Mar 17 PHP
php处理json时中文问题的解决方法
Apr 12 PHP
php导出excel格式数据问题
Mar 11 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
Jul 08 PHP
php实现对两个数组进行减法操作的方法
Apr 17 PHP
PHP永久登录、记住我功能实现方法和安全做法
Apr 27 PHP
thinkPHP下ueditor的使用方法详解
Dec 26 PHP
php实现的统计字数函数定义与使用示例
Jul 26 PHP
PHP获取对象属性的三种方法实例分析
Jan 03 PHP
Laravel框架基于ajax和layer.js实现无刷新删除功能示例
Jan 17 PHP
ThinkPHP 5.x远程命令执行漏洞复现
Sep 23 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中使用匿名函数操作数据库的例子
2014/11/17 PHP
php生成验证码函数
2015/10/20 PHP
WordPress中邮件的一些修改和自定义技巧
2015/12/15 PHP
JS随机生成不重复数据的实例方法
2013/07/17 Javascript
Jquery 返回json数据在IE浏览器中提示下载的问题
2014/05/18 Javascript
JavaScript使用二分查找算法在数组中查找数据的方法
2015/04/07 Javascript
JavaScript实现简单的数字倒计时
2015/05/15 Javascript
超漂亮的jQuery图片轮播特效
2015/11/24 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
第四篇Bootstrap网格系统偏移列和嵌套列
2016/06/21 Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
2016/08/19 Javascript
JS实现快速的导航下拉菜单动画效果附源码下载
2016/11/01 Javascript
wap手机端解决返回上一页的js实例
2016/12/08 Javascript
Vue之mixin全局的用法详解
2018/08/22 Javascript
Vue中使用 setTimeout() setInterval()函数的问题
2018/09/13 Javascript
layui问题之模拟table表格中的选中按钮选中事件的方法
2019/09/20 Javascript
JS实现打字游戏
2019/12/17 Javascript
Vue Object.defineProperty及ProxyVue实现双向数据绑定
2020/09/02 Javascript
node.js如何根据URL返回指定的图片详解
2020/10/21 Javascript
js实现移动端轮播图滑动切换
2020/12/21 Javascript
Python 实现 贪吃蛇大作战 代码分享
2016/09/07 Python
Python实现对文件进行单词划分并去重排序操作示例
2018/07/10 Python
基于Python中isfile函数和isdir函数使用详解
2019/11/29 Python
H5新属性audio音频和video视频的控制详解(推荐)
2016/12/09 HTML / CSS
药学专业大学生自荐信
2013/09/28 职场文书
销售员岗位职责范本
2014/02/03 职场文书
高中军训感言200字
2014/02/23 职场文书
3.15国际消费者权益日主题活动活动总结
2014/03/16 职场文书
向国旗敬礼学生寄语大全
2014/09/30 职场文书
2014年公务员转正工作总结
2014/11/07 职场文书
自愿离婚协议书范本
2015/01/26 职场文书
2016年小学党支部创先争优活动总结
2016/04/05 职场文书
Python爬虫入门案例之爬取二手房源数据
2021/10/16 Python
《地。-关于地球的运动-》单行本第七集上市,小说家朝井辽献上期待又害怕的推荐文
2022/03/31 日漫
《模拟人生4》推出新补丁 “婚礼奇缘”DLC终于得到修复
2022/04/03 其他游戏
SpringCloud Function SpEL注入漏洞分析及环境搭建
2022/04/08 Java/Android