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 相关文章推荐
其他功能
Oct 09 PHP
PHP中获取变量的变量名的一段代码的bug分析
Jul 07 PHP
PHP在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
Aug 03 PHP
PHPWind与Discuz截取字符函数substrs与cutstr性能比较
Dec 05 PHP
基于php和mysql的简单的dao类实现crud操作功能
Jan 27 PHP
更改localhost为其他名字的方法
Feb 10 PHP
JS异常处理try..catch语句的作用和实例
May 05 PHP
php防止站外远程提交表单的方法
Oct 20 PHP
PHP多态代码实例
Jun 26 PHP
PHP实现可自定义样式的分页类
Mar 29 PHP
php支持断点续传、分块下载的类
May 02 PHP
php usort 使用用户自定义的比较函数对二维数组中的值进行排序
May 02 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运行模式的深入理解
2013/06/03 PHP
Thinkphp中的volist标签用法简介
2014/06/18 PHP
php结合安卓客户端实现查询交互实例
2015/05/05 PHP
PHP中的多种加密技术及代码示例解析
2016/10/20 PHP
PHP调用接口API封装的例子
2019/10/11 PHP
PHP基于进程控制函数实现多线程
2020/12/09 PHP
jQuery弹出(alert)select选择的值
2013/04/21 Javascript
基于Three.js插件制作360度全景图
2016/11/29 Javascript
js实现鼠标单击Tab表单切换效果
2018/05/16 Javascript
vue集成百度UEditor富文本编辑器使用教程
2018/09/21 Javascript
VueJS 组件参数名命名与组件属性转化问题
2018/12/03 Javascript
JS实现的字符串数组去重功能小结
2019/06/17 Javascript
Javascript新手入门之字符串拼接与变量的应用
2020/12/03 Javascript
linux系统使用python获取cpu信息脚本分享
2014/01/15 Python
python循环监控远程端口的方法
2015/03/14 Python
python中文件变化监控示例(watchdog)
2017/10/16 Python
python实现多人聊天室
2020/03/31 Python
Python之Class&amp;Object用法详解
2019/12/25 Python
Matplotlib scatter绘制散点图的方法实现
2020/01/02 Python
python将dict中的unicode打印成中文实例
2020/05/11 Python
django的autoreload机制实现
2020/06/03 Python
Intimissimi德国网上商店:意大利知名内衣品牌
2018/04/03 全球购物
周年庆典邀请函范文
2014/01/23 职场文书
运动会入场解说词300字
2014/01/25 职场文书
红旗团支部事迹材料
2014/01/27 职场文书
马云北大演讲完整版:真心话,什么才是阿里的核心竞争力?
2014/04/04 职场文书
成立公司计划书
2014/05/07 职场文书
2014年教师节寄语
2014/08/11 职场文书
2014年学校德育工作总结
2014/12/05 职场文书
课外活动实习计划
2015/01/19 职场文书
信访维稳承诺书
2015/05/04 职场文书
就业证明函
2015/06/17 职场文书
学生会工作感言
2015/08/07 职场文书
入党申请书怎么写?
2019/06/21 职场文书
原生JS中应该禁止出现的写法
2021/05/05 Javascript
python之django路由和视图案例教程
2021/07/26 Python