PHP+JS+rsaÊý¾Ý¼ÓÃÜ´«ÊäʵÏÖ´úÂë

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

¡¡¡¡}

¡¡¡¡ÕûÌ×¼ÓÃܼ°½âÃܵķ½·¨¶¼ÔÚÉÏÃæÁË,±¾È˵IJâÊÔ»·¾³Îªphp5.3+WIN7

¡¡¡¡ÉÏÃæËùÓÐÎļþÏÂÔØ:RSAFILE