      1 //
      2 // NOTE : The original code is wrapped so that the defined functions don't collide with existing ones.
      3 // See http://michaux.ca/articles/javascript-namespacing.
      4 // See http://msdn.microsoft.com/en-us/library/259s7zc1%28v=vs.85%29.aspx
      5 //
      6
      7 /** @namespace */
      8 Crypto = typeof Crypto != 'undefined' ? Crypto : {};
      9 /** @namespace */
     10 Crypto.RSA = (function(/*window, undefined, $*/) {
     11
     12 //
     13 // START OF ORIGINAL CODE
     14 //
     15
     16 /* RSA public key encryption/decryption
     17  * The following functions are (c) 2000 by John M Hanna and are
     18  * released under the terms of the Gnu Public License.
     19  * You must freely redistribute them with their source -- see the
     20  * GPL for details.
     21  *  -- Latest version found at http://sourceforge.net/projects/shop-js
     22  *
     23  * GnuPG multi precision integer (mpi) conversion added
     24  * 2004 by Herbert Hanewinkel, www.haneWIN.de
     25  */
     26
     27 // --- Arbitrary Precision Math ---
     28 // badd(a,b), bsub(a,b), bmul(a,b)
     29 // bdiv(a,b), bmod(a,b), bmodexp(xx,y,m)
     30
     31 // set the base... 32bit cpu -> bs=16, 64bit -> bs=32
     32 // bs is the shift, bm is the mask
     33
     34 var bs=28;
     35 var bx2=1<<bs, bm=bx2-1, bx=bx2>>1, bd=bs>>1, bdm=(1<<bd)-1;
     36
     37 var log2=Math.log(2);
     38
     39 function badd(a,b) // binary add
     40 {
     41  var al=a.length, bl=b.length;
     42
     43  if(al < bl) return badd(b,a);
     44
     45  var r=new Array(al);
     46  var c=0, n=0;
     47
     48  for(; n<bl; n++)
     49  {
     50   c+=a[n]+b[n];
     51   r[n]=c & bm;
     52   c>>>=bs;
     53  }
     54  for(; n<al; n++)
     55  {
     56   c+=a[n];
     57   r[n]=c & bm;
     58   c>>>=bs;
     59  }
     60  if(c) r[n]=c;
     61  return r;
     62 }
     63
     64 function bsub(a,b) // binary subtract
     65 {
     66  var al=a.length, bl=b.length;
     67
     68  if(bl > al) return [];
     69  if(bl == al)
     70  {
     71   if(b[bl-1] > a[bl-1]) return [];
     72   if(bl==1) return [a[0]-b[0]];
     73  }
     74
     75  var r=new Array(al);
     76  var c=0;
     77
     78  for(var n=0; n<bl; n++)
     79  {
     80   c+=a[n]-b[n];
     81   r[n]=c & bm;
     82   c>>=bs;
     83  }
     84  for(;n<al; n++)
     85  {
     86   c+=a[n];
     87   r[n]=c & bm;
     88   c>>=bs;
     89  }
     90  if(c) return [];
     91
     92  if(r[n-1]) return r;
     93  while(n>1 && r[n-1]==0) n--;
     94  return r.slice(0,n);
     95 }
     96
     97 function zeros(n)
     98 {
     99  var r=new Array(n);
    100
    101  while(n-->0) r[n]=0;
    102  return r;
    103 }
    104
    105 function bmul(a,b) // binary multiply
    106 {
    107  b=b.concat([0]);
    108  var al=a.length, bl=b.length;
    109  var n,nn,aa,c,m, g,gg,h,hh,ghh,ghhb;
    110
    111  var r=zeros(al+bl+1);
    112
    113  for(n=0; n<al; n++)
    114  {
    115   aa=a[n];
    116   if(aa)
    117   {
    118    c=0;
    119    hh=aa>>bd; h=aa & bdm;
    120    m=n;
    121    for(nn=0; nn<bl; nn++, m++)
    122    {
    123     g = b[nn]; gg=g>>bd; g=g & bdm;
    124     // (gg*2^15 + g) * (hh*2^15 + h) = (gghh*2^30 + (ghh+hgg)*2^15 +hg)
    125     ghh = g * hh + h * gg;
    126     ghhb= ghh >> bd; ghh &= bdm;
    127     c += r[m] + h * g + (ghh << bd);
    128     r[m] = c & bm;
    129     c = (c >> bs) + gg * hh + ghhb;
    130    }
    131   }
    132  }
    133  n=r.length;
    134
    135  if(r[n-1]) return r;
    136  while(n>1 && r[n-1]==0) n--;
    137  return r.slice(0,n);
    138 }
    139
    140 function toppart(x,start,len)
    141 {
    142  var n=0;
    143  while(start >= 0 && len-->0) n=n*bx2+x[start--];
    144  return n;
    145 }
    146
    147 // ----------------------------------------------------
    148 // 14.20 Algorithm Multiple-precision division from HAC
    149
    150 function bdiv(x,y)
    151 {
    152  var n=x.length-1, t=y.length-1, nmt=n-t;
    153
    154  // trivial cases; x < y
    155  if(n < t || n==t && (x[n]<y[n] || n>0 && x[n]==y[n] && x[n-1]<y[n-1]))
    156  {
    157   this.q=[0]; this.mod=x;
    158   return this;
    159  }
    160
    161  // trivial cases; q < 4
    162  if(n==t && toppart(x,t,2)/toppart(y,t,2) <4)
    163  {
    164   var qq=0, xx;
    165   for(;;)
    166   {
    167    xx=bsub(x,y);
    168    if(xx.length==0) break;
    169    x=xx; qq++;
    170   }
    171   this.q=[qq]; this.mod=x;
    172   return this;
    173  }
    174
    175  var shift, shift2
    176  // normalize
    177  shift2=Math.floor(Math.log(y[t])/log2)+1;
    178  shift=bs-shift2;
    179  if(shift)
    180  {
    181   x=x.concat(); y=y.concat()
    182   for(i=t; i>0; i--) y[i]=((y[i]<<shift) & bm) | (y[i-1] >> shift2);
    183   y[0]=(y[0]<<shift) & bm;
    184   if(x[n] & ((bm <<shift2) & bm))
    185   {
    186    x[++n]=0; nmt++;
    187   }
    188   for(i=n; i>0; i--) x[i]=((x[i]<<shift) & bm) | (x[i-1] >> shift2);
    189   x[0]=(x[0]<<shift) & bm;
    190  }
    191
    192  var i, j, x2;
    193  var q=zeros(nmt+1);
    194  var y2=zeros(nmt).concat(y);
    195  for(;;)
    196  {
    197   x2=bsub(x,y2);
    198   if(x2.length==0) break;
    199   q[nmt]++;
    200   x=x2;
    201  }
    202
    203  var yt=y[t], top=toppart(y,t,2)
    204  for(i=n; i>t; i--)
    205  {
    206   var m=i-t-1;
    207   if(i >= x.length) q[m]=1;
    208   else if(x[i] == yt) q[m]=bm;
    209   else q[m]=Math.floor(toppart(x,i,2)/yt);
    210
    211   var topx=toppart(x,i,3);
    212   while(q[m] * top > topx) q[m]--;
    213
    214   //x-=q[m]*y*b^m
    215   y2=y2.slice(1);
    216   x2=bsub(x,bmul([q[m]],y2));
    217   if(x2.length==0)
    218   {
    219    q[m]--;
    220    x2=bsub(x,bmul([q[m]],y2));
    221   }
    222   x=x2;
    223  }
    224  // de-normalize
    225  if(shift)
    226  {
    227   for(i=0; i<x.length-1; i++) x[i]=(x[i]>>shift) | ((x[i+1] << shift2) & bm);
    228   x[x.length-1]>>=shift;
    229  }
    230  n = q.length;
    231  while(n > 1 && q[n-1]==0) n--;
    232  this.q=q.slice(0,n);
    233  n = x.length;
    234  while(n > 1 && x[n-1]==0) n--;
    235  this.mod=x.slice(0,n);
    236  return this;
    237 }
    238
    239 function simplemod(i,m) // returns the mod where m < 2^bd
    240 {
    241  var c=0, v;
    242  for(var n=i.length-1; n>=0; n--)
    243  {
    244   v=i[n];
    245   c=((v >> bd) + (c<<bd)) % m;
    246   c=((v & bdm) + (c<<bd)) % m;
    247  }
    248  return c;
    249 }
    250
    251 function bmod(p,m) // binary modulo
    252 {
    253  if(m.length==1)
    254  {
    255   if(p.length==1) return [p[0] % m[0]];
    256   if(m[0] < bdm) return [simplemod(p,m[0])];
    257  }
    258
    259  var r=new bdiv(p,m);
    260  return r.mod;
    261 }
    262
    263 // ------------------------------------------------------
    264 // Barrett's modular reduction from HAC, 14.42, CRC Press
    265
    266 function bmod2(x,m,mu)
    267 {
    268  var xl=x.length - (m.length << 1);
    269  if(xl > 0) return bmod2(x.slice(0,xl).concat(bmod2(x.slice(xl),m,mu)),m,mu);
    270
    271  var ml1=m.length+1, ml2=m.length-1,rr;
    272  //var q1=x.slice(ml2)
    273  //var q2=bmul(q1,mu)
    274  var q3=bmul(x.slice(ml2),mu).slice(ml1);
    275  var r1=x.slice(0,ml1);
    276  var r2=bmul(q3,m).slice(0,ml1);
    277  var r=bsub(r1,r2);
    278  //var s=('x='+x+'\nm='+m+'\nmu='+mu+'\nq1='+q1+'\nq2='+q2+'\nq3='+q3+'\nr1='+r1+'\nr2='+r2+'\nr='+r);
    279  if(r.length==0)
    280  {
    281   r1[ml1]=1;
    282   r=bsub(r1,r2);
    283  }
    284  for(var n=0;;n++)
    285  {
    286   rr=bsub(r,m);
    287   if(rr.length==0) break;
    288   r=rr;
    289   if(n>=3) return bmod2(r,m,mu);
    290  }
    291  return r;
    292 }
    293
    294 function bmodexp(xx,y,m) // binary modular exponentiation
    295 {
    296  var r=[1], an,a, x=xx.concat();
    297  var n=m.length*2;
    298  var mu=new Array(n+1);
    299
    300  mu[n--]=1;
    301  for(; n>=0; n--) mu[n]=0; mu=new bdiv(mu,m).q;
    302
    303  for(n=0; n<y.length; n++)
    304  {
    305   for(a=1, an=0; an<bs; an++, a<<=1)
    306   {
    307    if(y[n] & a) r=bmod2(bmul(r,x),m,mu);
    308    x=bmod2(bmul(x,x),m,mu);
    309   }
    310  }
    311  return r;
    312 }
    313
    314 // -----------------------------------------------------
    315 // Compute s**e mod m for RSA public key operation
    316
    317 function RSAencrypt(s, e, m) { return bmodexp(s,e,m); }
    318
    319 // Compute m**d mod p*q for RSA private key operations.
    320
    321 function RSAdecrypt(m, d, p, q, u)
    322 {
    323  var xp = bmodexp(bmod(m,p), bmod(d,bsub(p,[1])), p);
    324  var xq = bmodexp(bmod(m,q), bmod(d,bsub(q,[1])), q);
    325
    326  var t=bsub(xq,xp);
    327  if(t.length==0)
    328  {
    329   t=bsub(xp,xq);
    330   t=bmod(bmul(t, u), q);
    331   t=bsub(q,t);
    332  }
    333  else
    334  {
    335   t=bmod(bmul(t, u), q);
    336  }
    337  return badd(bmul(t,p), xp);
    338 }
    339
    340 // -----------------------------------------------------------------
    341 // conversion functions: num array <-> multi precision integer (mpi)
    342 // mpi: 2 octets with length in bits + octets in big endian order
    343
    344 function mpi2b(s)
    345 {
    346  var bn=1, r=[0], rn=0, sb=256;
    347  var c, sn=s.length;
    348  if(sn < 2)
    349  {
    350     alert('string too short, not a MPI');
    351     return 0;
    352  }
    353
    354  var len=(sn-2)*8;
    355  var bits=s.charCodeAt(0)*256+s.charCodeAt(1);
    356  if(bits > len || bits < len-8)
    357  {
    358     alert('not a MPI, bits='+bits+",len="+len);
    359     return 0;
    360  }
    361
    362  for(var n=0; n<len; n++)
    363  {
    364   if((sb<<=1) > 255)
    365   {
    366    sb=1; c=s.charCodeAt(--sn);
    367   }
    368   if(bn > bm)
    369   {
    370    bn=1;
    371    r[++rn]=0;
    372   }
    373   if(c & sb) r[rn]|=bn;
    374   bn<<=1;
    375  }
    376  return r;
    377 }
    378
    379 function b2mpi(b)
    380 {
    381  var bn=1, bc=0, r=[0], rb=1, rn=0;
    382  var bits=b.length*bs;
    383  var n, rr='';
    384
    385  for(n=0; n<bits; n++)
    386  {
    387   if(b[bc] & bn) r[rn]|=rb;
    388   if((rb<<=1) > 255)
    389   {
    390    rb=1; r[++rn]=0;
    391   }
    392   if((bn<<=1) > bm)
    393   {
    394    bn=1; bc++;
    395   }
    396  }
    397
    398  while(rn && r[rn]==0) rn--;
    399
    400  bn=256;
    401  for(bits=8; bits>0; bits--) if(r[rn] & (bn>>=1)) break;
    402  bits+=rn*8;
    403
    404  rr+=String.fromCharCode(bits/256)+String.fromCharCode(bits%256);
    405  if(bits) for(n=rn; n>=0; n--) rr+=String.fromCharCode(r[n]);
    406  return rr;
    407 }
    408
    409 //
    410 // END OF ORIGINAL CODE
    411 //
    412
    413 return {
    414     b2mpi: b2mpi,
    415     encrypt: RSAencrypt,
    416     decrypt: RSAdecrypt
    417 };
    418
    419 })(/*window, undefined, $*/);