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(2)
Oct 09 PHP
利用ThinkPHP内置的ThinkAjax实现异步传输技术的实现方法
Dec 19 PHP
PHP数据流应用的一个简单实例
Sep 14 PHP
PHPThumb图片处理实例
May 03 PHP
关于URL最大长度限制的相关资料查证
Dec 23 PHP
php正则表达式验证(邮件地址、Url地址、电话号码、邮政编码)
Mar 14 PHP
thinkPHP统计排行与分页显示功能示例
Dec 02 PHP
php获取网站根目录物理路径的几种方法(推荐)
Mar 04 PHP
php lcg_value与mt_rand生成0~1随机小数的效果对比分析
Apr 05 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
Feb 15 PHP
PHP实现文件上传与下载
Aug 28 PHP
php swoft框架实例用法
Dec 22 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
Zend的MVC机制使用分析(二)
2013/05/02 PHP
ThinkPHP应用模式扩展详解
2014/07/16 PHP
smarty简单分页的实现方法
2014/10/27 PHP
php使用date和strtotime函数输出指定日期的方法
2014/11/14 PHP
VPS中使用LNMP安装WordPress教程
2014/12/28 PHP
Laravel5.5以下版本中如何自定义日志行为详解
2018/08/01 PHP
PHP正则之正向预查与反向预查讲解与实例
2020/04/06 PHP
PHP语言对接抖音快手小红书视频/图片去水印API接口源码
2020/08/11 PHP
在网页中控制wmplayer播放器
2006/07/01 Javascript
为数据添加append,remove功能
2006/10/03 Javascript
JS处理VBArray的函数使用说明
2008/05/11 Javascript
javascript 冒号 使用说明
2009/06/06 Javascript
JavaScript中使用stopPropagation函数停止事件传播例子
2014/08/27 Javascript
javascript实现连续赋值
2015/08/10 Javascript
解决js页面滚动效果scrollTop在FireFox与Chrome浏览器间的兼容问题的方法
2015/12/03 Javascript
提升jQuery的性能需要做好七件事
2016/01/11 Javascript
JS实现的文字间歇循环滚动效果完整示例
2018/02/13 Javascript
JS实现判断数组是否包含某个元素示例
2019/05/24 Javascript
JointJS JavaScript流程图绘制框架解析
2019/08/15 Javascript
ckeditor一键排版功能实现方法分析
2020/02/06 Javascript
JavaScript如何实现监听键盘输入和鼠标监点击
2020/07/20 Javascript
[00:32]2018DOTA2亚洲邀请赛iG出场
2018/04/03 DOTA
Python中使用PyHook监听鼠标和键盘事件实例
2014/07/18 Python
win与linux系统中python requests 安装
2016/12/04 Python
Python实现识别手写数字 简易图片存储管理系统
2018/01/29 Python
Python实现通讯录功能
2018/02/22 Python
解决项目pycharm能运行,在终端却无法运行的问题
2019/01/19 Python
详解Ubuntu环境下部署Django+uwsgi+nginx总结
2020/04/02 Python
PyTorch: Softmax多分类实战操作
2020/07/07 Python
python cookie反爬处理的实现
2020/11/01 Python
css3 border旋转时的动画应用
2016/01/22 HTML / CSS
HTML5中使用postMessage实现Ajax跨域请求的方法
2016/04/19 HTML / CSS
文秘专业应届生求职信范文
2013/11/14 职场文书
庆七一活动总结
2014/08/27 职场文书
礼仪培训心得体会
2016/01/22 职场文书
详解前端任务构建利器Gulp.js使用指南
2021/04/30 Javascript