diff -r de56132c008d -r bdac73ed481e includes/clientside/static/crypto.js --- a/includes/clientside/static/crypto.js Sun Mar 28 21:49:26 2010 -0400 +++ b/includes/clientside/static/crypto.js Sun Mar 28 23:10:46 2010 -0400 @@ -188,471 +188,471 @@ md_q1=t; md_q2=t; md_q3=t; md_r=t; md_r1=t; md_r2=t; md_tt=t; //used in mod_() primes=t; pows=t; s_i=t; s_i2=t; s_R=t; s_rm=t; s_q=t; s_n1=t; - s_a=t; s_r2=t; s_n=t; s_b=t; s_d=t; s_x1=t; s_x2=t, s_aa=t; //used in randTruePrime_() + s_a=t; s_r2=t; s_n=t; s_b=t; s_d=t; s_x1=t; s_x2=t, s_aa=t; //used in randTruePrime_() //////////////////////////////////////////////////////////////////////////////////////// //return array of all primes less than integer n function findPrimes(n) { - var i,s,p,ans; - s=new Array(n); - for (i=0;i0); j--); - for (z=0,w=x[j]; w; (w>>=1),z++); - z+=bpe*j; - return z; + var j,z,w; + for (j=x.length-1; (x[j]==0) && (j>0); j--); + for (z=0,w=x[j]; w; (w>>=1),z++); + z+=bpe*j; + return z; } //return a copy of x with at least n elements, adding leading zeros if needed function expand(x,n) { - var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0); - copy_(ans,x); - return ans; + var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0); + copy_(ans,x); + return ans; } //return a k-bit true random prime using Maurer's algorithm. function randTruePrime(k) { - var ans=int2bigInt(0,k,0); - randTruePrime_(ans,k); - return bigint_trim(ans,1); + var ans=int2bigInt(0,k,0); + randTruePrime_(ans,k); + return bigint_trim(ans,1); } //return a new bigInt equal to (x mod n) for bigInts x and n. function mod(x,n) { - var ans=dup(x); - mod_(ans,n); - return bigint_trim(ans,1); + var ans=dup(x); + mod_(ans,n); + return bigint_trim(ans,1); } //return (x+n) where x is a bigInt and n is an integer. function addInt(x,n) { - var ans=expand(x,x.length+1); - addInt_(ans,n); - return bigint_trim(ans,1); + var ans=expand(x,x.length+1); + addInt_(ans,n); + return bigint_trim(ans,1); } //return x*y for bigInts x and y. This is faster when yy.length ? x.length+1 : y.length+1)); - sub_(ans,y); - return bigint_trim(ans,1); + var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); + sub_(ans,y); + return bigint_trim(ans,1); } //return (x+y) for bigInts x and y. function add(x,y) { - var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); - add_(ans,y); - return bigint_trim(ans,1); + var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1)); + add_(ans,y); + return bigint_trim(ans,1); } //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null function inverseMod(x,n) { - var ans=expand(x,n.length); - var s; - s=inverseMod_(ans,n); - return s ? bigint_trim(ans,1) : null; + var ans=expand(x,n.length); + var s; + s=inverseMod_(ans,n); + return s ? bigint_trim(ans,1) : null; } //return (x*y mod n) for bigInts x,y,n. For greater speed, let y= 2 + //c and m should be tuned for a particular machine and value of k, to maximize speed + c=0.1; //c=0.1 in HAC + m=20; //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits + recLimit=20; //stop recursion when k <=recLimit. Must have recLimit >= 2 - if (s_i2.length!=ans.length) { - s_i2=dup(ans); - s_R =dup(ans); - s_n1=dup(ans); - s_r2=dup(ans); - s_d =dup(ans); - s_x1=dup(ans); - s_x2=dup(ans); - s_b =dup(ans); - s_n =dup(ans); - s_i =dup(ans); - s_rm=dup(ans); - s_q =dup(ans); - s_a =dup(ans); - s_aa=dup(ans); - } + if (s_i2.length!=ans.length) { + s_i2=dup(ans); + s_R =dup(ans); + s_n1=dup(ans); + s_r2=dup(ans); + s_d =dup(ans); + s_x1=dup(ans); + s_x2=dup(ans); + s_b =dup(ans); + s_n =dup(ans); + s_i =dup(ans); + s_rm=dup(ans); + s_q =dup(ans); + s_a =dup(ans); + s_aa=dup(ans); + } - if (k <= recLimit) { //generate small random primes by trial division up to its square root - pm=(1<<((k+2)>>1))-1; //pm is binary number with all ones, just over sqrt(2^k) - copyInt_(ans,0); - for (dd=1;dd;) { - dd=0; - ans[0]= 1 | (1<<(k-1)) | Math.floor(Math.random()*(1<>1))-1; //pm is binary number with all ones, just over sqrt(2^k) + copyInt_(ans,0); + for (dd=1;dd;) { + dd=0; + ans[0]= 1 | (1<<(k-1)) | Math.floor(Math.random()*(1<2*m) //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits - for (r=1; k-k*r<=m; ) - r=pows[Math.floor(Math.random()*512)]; //r=Math.pow(2,Math.random()-1); - else - r=.5; + B=c*k*k; //try small primes up to B (or all the primes[] array if the largest is less than B). + if (k>2*m) //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits + for (r=1; k-k*r<=m; ) + r=pows[Math.floor(Math.random()*512)]; //r=Math.pow(2,Math.random()-1); + else + r=.5; - //simulation suggests the more complex algorithm using r=.333 is only slightly faster. + //simulation suggests the more complex algorithm using r=.333 is only slightly faster. - recSize=Math.floor(r*k)+1; + recSize=Math.floor(r*k)+1; - randTruePrime_(s_q,recSize); - copyInt_(s_i2,0); - s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe)); //s_i2=2^(k-2) - divide_(s_i2,s_q,s_i,s_rm); //s_i=floor((2^(k-1))/(2q)) + randTruePrime_(s_q,recSize); + copyInt_(s_i2,0); + s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe)); //s_i2=2^(k-2) + divide_(s_i2,s_q,s_i,s_rm); //s_i=floor((2^(k-1))/(2q)) - z=bitSize(s_i); + z=bitSize(s_i); - for (;;) { - for (;;) { //generate z-bit numbers until one falls in the range [0,s_i-1] - randBigInt_(s_R,z,0); - if (greater(s_i,s_R)) - break; - } //now s_R is in the range [0,s_i-1] - addInt_(s_R,1); //now s_R is in the range [1,s_i] - add_(s_R,s_i); //now s_R is in the range [s_i+1,2*s_i] + for (;;) { + for (;;) { //generate z-bit numbers until one falls in the range [0,s_i-1] + randBigInt_(s_R,z,0); + if (greater(s_i,s_R)) + break; + } //now s_R is in the range [0,s_i-1] + addInt_(s_R,1); //now s_R is in the range [1,s_i] + add_(s_R,s_i); //now s_R is in the range [s_i+1,2*s_i] - copy_(s_n,s_q); - mult_(s_n,s_R); - multInt_(s_n,2); - addInt_(s_n,1); //s_n=2*s_R*s_q+1 - - copy_(s_r2,s_R); - multInt_(s_r2,2); //s_r2=2*s_R + copy_(s_n,s_q); + mult_(s_n,s_R); + multInt_(s_n,2); + addInt_(s_n,1); //s_n=2*s_R*s_q+1 + + copy_(s_r2,s_R); + multInt_(s_r2,2); //s_r2=2*s_R - //check s_n for divisibility by small primes up to B - for (divisible=0,j=0; (j0); j--); //strip leading zeros - for (zz=0,w=s_n[j]; w; (w>>=1),zz++); - zz+=bpe*j; //zz=number of bits in s_n, ignoring leading zeros - for (;;) { //generate z-bit numbers until one falls in the range [0,s_n-1] - randBigInt_(s_a,zz,0); - if (greater(s_n,s_a)) - break; - } //now s_a is in the range [0,s_n-1] - addInt_(s_n,3); //now s_a is in the range [0,s_n-4] - addInt_(s_a,2); //now s_a is in the range [2,s_n-2] - copy_(s_b,s_a); - copy_(s_n1,s_n); - addInt_(s_n1,-1); - powMod_(s_b,s_n1,s_n); //s_b=s_a^(s_n-1) modulo s_n - addInt_(s_b,-1); - if (isZero(s_b)) { - copy_(s_b,s_a); - powMod_(s_b,s_r2,s_n); - addInt_(s_b,-1); - copy_(s_aa,s_n); - copy_(s_d,s_b); - GCD_(s_d,s_n); //if s_b and s_n are relatively prime, then s_n is a prime - if (equalsInt(s_d,1)) { - copy_(ans,s_aa); - return; //if we've made it this far, then s_n is absolutely guaranteed to be prime - } - } - } - } + if (!divisible) { //if it passes that test, continue checking s_n + addInt_(s_n,-3); + for (j=s_n.length-1;(s_n[j]==0) && (j>0); j--); //strip leading zeros + for (zz=0,w=s_n[j]; w; (w>>=1),zz++); + zz+=bpe*j; //zz=number of bits in s_n, ignoring leading zeros + for (;;) { //generate z-bit numbers until one falls in the range [0,s_n-1] + randBigInt_(s_a,zz,0); + if (greater(s_n,s_a)) + break; + } //now s_a is in the range [0,s_n-1] + addInt_(s_n,3); //now s_a is in the range [0,s_n-4] + addInt_(s_a,2); //now s_a is in the range [2,s_n-2] + copy_(s_b,s_a); + copy_(s_n1,s_n); + addInt_(s_n1,-1); + powMod_(s_b,s_n1,s_n); //s_b=s_a^(s_n-1) modulo s_n + addInt_(s_b,-1); + if (isZero(s_b)) { + copy_(s_b,s_a); + powMod_(s_b,s_r2,s_n); + addInt_(s_b,-1); + copy_(s_aa,s_n); + copy_(s_d,s_b); + GCD_(s_d,s_n); //if s_b and s_n are relatively prime, then s_n is a prime + if (equalsInt(s_d,1)) { + copy_(ans,s_aa); + return; //if we've made it this far, then s_n is absolutely guaranteed to be prime + } + } + } + } } //Return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1. function randBigInt(n,s) { - var a,b; - a=Math.floor((n-1)/bpe)+2; //# array elements to hold the BigInt with a leading 0 element - b=int2bigInt(0,0,a); - randBigInt_(b,n,s); - return b; + var a,b; + a=Math.floor((n-1)/bpe)+2; //# array elements to hold the BigInt with a leading 0 element + b=int2bigInt(0,0,a); + randBigInt_(b,n,s); + return b; } //Set b to an n-bit random BigInt. If s=1, then the most significant of those n bits is set to 1. //Array b must be big enough to hold the result. Must have n>=1 function randBigInt_(b,n,s) { - var i,a; - for (i=0;i=0;i--); //find most significant element of x - xp=x[i]; - yp=y[i]; - A=1; B=0; C=0; D=1; - while ((yp+C) && (yp+D)) { - q =Math.floor((xp+A)/(yp+C)); - qp=Math.floor((xp+B)/(yp+D)); - if (q!=qp) - break; - t= A-q*C; A=C; C=t; // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp) - t= B-q*D; B=D; D=t; - t=xp-q*yp; xp=yp; yp=t; - } - if (B) { - copy_(T,x); - linComb_(x,y,A,B); //x=A*x+B*y - linComb_(y,T,D,C); //y=D*y+C*T - } else { - mod_(x,y); - copy_(T,x); - copy_(x,y); - copy_(y,T); - } - } - if (y[0]==0) - return; - t=modInt(x,y[0]); - copyInt_(x,y[0]); - y[0]=t; - while (y[0]) { - x[0]%=y[0]; - t=x[0]; x[0]=y[0]; y[0]=t; - } + for (i=x.length;!x[i] && i>=0;i--); //find most significant element of x + xp=x[i]; + yp=y[i]; + A=1; B=0; C=0; D=1; + while ((yp+C) && (yp+D)) { + q =Math.floor((xp+A)/(yp+C)); + qp=Math.floor((xp+B)/(yp+D)); + if (q!=qp) + break; + t= A-q*C; A=C; C=t; // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp) + t= B-q*D; B=D; D=t; + t=xp-q*yp; xp=yp; yp=t; + } + if (B) { + copy_(T,x); + linComb_(x,y,A,B); //x=A*x+B*y + linComb_(y,T,D,C); //y=D*y+C*T + } else { + mod_(x,y); + copy_(T,x); + copy_(x,y); + copy_(y,T); + } + } + if (y[0]==0) + return; + t=modInt(x,y[0]); + copyInt_(x,y[0]); + y[0]=t; + while (y[0]) { + x[0]%=y[0]; + t=x[0]; x[0]=y[0]; y[0]=t; + } } //do x=x**(-1) mod n, for bigInts x and n. //If no inverse exists, it sets x to zero and returns 0, else it returns 1. //The x array must be at least as large as the n array. function inverseMod_(x,n) { - var k=1+2*Math.max(x.length,n.length); + var k=1+2*Math.max(x.length,n.length); - if(!(x[0]&1) && !(n[0]&1)) { //if both inputs are even, then inverse doesn't exist - copyInt_(x,0); - return 0; - } + if(!(x[0]&1) && !(n[0]&1)) { //if both inputs are even, then inverse doesn't exist + copyInt_(x,0); + return 0; + } - if (eg_u.length!=k) { - eg_u=new Array(k); - eg_v=new Array(k); - eg_A=new Array(k); - eg_B=new Array(k); - eg_C=new Array(k); - eg_D=new Array(k); - } + if (eg_u.length!=k) { + eg_u=new Array(k); + eg_v=new Array(k); + eg_A=new Array(k); + eg_B=new Array(k); + eg_C=new Array(k); + eg_D=new Array(k); + } - copy_(eg_u,x); - copy_(eg_v,n); - copyInt_(eg_A,1); - copyInt_(eg_B,0); - copyInt_(eg_C,0); - copyInt_(eg_D,1); - for (;;) { - while(!(eg_u[0]&1)) { //while eg_u is even - halve_(eg_u); - if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2 - halve_(eg_A); - halve_(eg_B); - } else { - add_(eg_A,n); halve_(eg_A); - sub_(eg_B,x); halve_(eg_B); - } - } + copy_(eg_u,x); + copy_(eg_v,n); + copyInt_(eg_A,1); + copyInt_(eg_B,0); + copyInt_(eg_C,0); + copyInt_(eg_D,1); + for (;;) { + while(!(eg_u[0]&1)) { //while eg_u is even + halve_(eg_u); + if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2 + halve_(eg_A); + halve_(eg_B); + } else { + add_(eg_A,n); halve_(eg_A); + sub_(eg_B,x); halve_(eg_B); + } + } - while (!(eg_v[0]&1)) { //while eg_v is even - halve_(eg_v); - if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2 - halve_(eg_C); - halve_(eg_D); - } else { - add_(eg_C,n); halve_(eg_C); - sub_(eg_D,x); halve_(eg_D); - } - } + while (!(eg_v[0]&1)) { //while eg_v is even + halve_(eg_v); + if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2 + halve_(eg_C); + halve_(eg_D); + } else { + add_(eg_C,n); halve_(eg_C); + sub_(eg_D,x); halve_(eg_D); + } + } - if (!greater(eg_v,eg_u)) { //eg_v <= eg_u - sub_(eg_u,eg_v); - sub_(eg_A,eg_C); - sub_(eg_B,eg_D); - } else { //eg_v > eg_u - sub_(eg_v,eg_u); - sub_(eg_C,eg_A); - sub_(eg_D,eg_B); - } - - if (equalsInt(eg_u,0)) { - if (negative(eg_C)) //make sure answer is nonnegative - add_(eg_C,n); - copy_(x,eg_C); + if (!greater(eg_v,eg_u)) { //eg_v <= eg_u + sub_(eg_u,eg_v); + sub_(eg_A,eg_C); + sub_(eg_B,eg_D); + } else { //eg_v > eg_u + sub_(eg_v,eg_u); + sub_(eg_C,eg_A); + sub_(eg_D,eg_B); + } + + if (equalsInt(eg_u,0)) { + if (negative(eg_C)) //make sure answer is nonnegative + add_(eg_C,n); + copy_(x,eg_C); - if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse - copyInt_(x,0); - return 0; - } - return 1; - } - } + if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse + copyInt_(x,0); + return 0; + } + return 1; + } + } } //return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse function inverseModInt(x,n) { - var a=1,b=0,t; - for (;;) { - if (x==1) return a; - if (x==0) return 0; - b-=a*Math.floor(n/x); - n%=x; + var a=1,b=0,t; + for (;;) { + if (x==1) return a; + if (x==0) return 0; + b-=a*Math.floor(n/x); + n%=x; - if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to += - if (n==0) return 0; - a-=b*Math.floor(x/n); - x%=n; - } + if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to += + if (n==0) return 0; + a-=b*Math.floor(x/n); + x%=n; + } } //this deprecated function is for backward compatibility only. function inverseModInt_(x,n) { - return inverseModInt(x,n); + return inverseModInt(x,n); } @@ -660,76 +660,76 @@ // v = GCD_(x,y) = a*x-b*y //The bigInts v, a, b, must have exactly as many elements as the larger of x and y. function eGCD_(x,y,v,a,b) { - var g=0; - var k=Math.max(x.length,y.length); - if (eg_u.length!=k) { - eg_u=new Array(k); - eg_A=new Array(k); - eg_B=new Array(k); - eg_C=new Array(k); - eg_D=new Array(k); - } - while(!(x[0]&1) && !(y[0]&1)) { //while x and y both even - halve_(x); - halve_(y); - g++; - } - copy_(eg_u,x); - copy_(v,y); - copyInt_(eg_A,1); - copyInt_(eg_B,0); - copyInt_(eg_C,0); - copyInt_(eg_D,1); - for (;;) { - while(!(eg_u[0]&1)) { //while u is even - halve_(eg_u); - if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2 - halve_(eg_A); - halve_(eg_B); - } else { - add_(eg_A,y); halve_(eg_A); - sub_(eg_B,x); halve_(eg_B); - } - } + var g=0; + var k=Math.max(x.length,y.length); + if (eg_u.length!=k) { + eg_u=new Array(k); + eg_A=new Array(k); + eg_B=new Array(k); + eg_C=new Array(k); + eg_D=new Array(k); + } + while(!(x[0]&1) && !(y[0]&1)) { //while x and y both even + halve_(x); + halve_(y); + g++; + } + copy_(eg_u,x); + copy_(v,y); + copyInt_(eg_A,1); + copyInt_(eg_B,0); + copyInt_(eg_C,0); + copyInt_(eg_D,1); + for (;;) { + while(!(eg_u[0]&1)) { //while u is even + halve_(eg_u); + if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2 + halve_(eg_A); + halve_(eg_B); + } else { + add_(eg_A,y); halve_(eg_A); + sub_(eg_B,x); halve_(eg_B); + } + } - while (!(v[0]&1)) { //while v is even - halve_(v); - if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2 - halve_(eg_C); - halve_(eg_D); - } else { - add_(eg_C,y); halve_(eg_C); - sub_(eg_D,x); halve_(eg_D); - } - } + while (!(v[0]&1)) { //while v is even + halve_(v); + if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2 + halve_(eg_C); + halve_(eg_D); + } else { + add_(eg_C,y); halve_(eg_C); + sub_(eg_D,x); halve_(eg_D); + } + } - if (!greater(v,eg_u)) { //v<=u - sub_(eg_u,v); - sub_(eg_A,eg_C); - sub_(eg_B,eg_D); - } else { //v>u - sub_(v,eg_u); - sub_(eg_C,eg_A); - sub_(eg_D,eg_B); - } - if (equalsInt(eg_u,0)) { - if (negative(eg_C)) { //make sure a (C)is nonnegative - add_(eg_C,y); - sub_(eg_D,x); - } - multInt_(eg_D,-1); ///make sure b (D) is nonnegative - copy_(a,eg_C); - copy_(b,eg_D); - leftShift_(v,g); - return; - } - } + if (!greater(v,eg_u)) { //v<=u + sub_(eg_u,v); + sub_(eg_A,eg_C); + sub_(eg_B,eg_D); + } else { //v>u + sub_(v,eg_u); + sub_(eg_C,eg_A); + sub_(eg_D,eg_B); + } + if (equalsInt(eg_u,0)) { + if (negative(eg_C)) { //make sure a (C)is nonnegative + add_(eg_C,y); + sub_(eg_D,x); + } + multInt_(eg_D,-1); ///make sure b (D) is nonnegative + copy_(a,eg_C); + copy_(b,eg_D); + leftShift_(v,g); + return; + } + } } //is bigInt x negative? function negative(x) { - return ((x[x.length-1]>>(bpe-1))&1); + return ((x[x.length-1]>>(bpe-1))&1); } @@ -737,39 +737,39 @@ //x and y are nonnegative bigInts //shift is a nonnegative integer function greaterShift(x,y,shift) { - var kx=x.length, ky=y.length; - k=((kx+shift)=0; i++) - if (x[i]>0) - return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger - for (i=kx-1+shift; i0) - return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger - for (i=k-1; i>=shift; i--) - if (x[i-shift]>y[i]) return 1; - else if (x[i-shift]=0; i++) + if (x[i]>0) + return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger + for (i=kx-1+shift; i0) + return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger + for (i=k-1; i>=shift; i--) + if (x[i-shift]>y[i]) return 1; + else if (x[i-shift] y? (x and y both nonnegative) function greater(x,y) { - var i; - var k=(x.length=0;i--) - if (x[i]>y[i]) - return 1; - else if (x[i]=0;i--) + if (x[i]>y[i]) + return 1; + else if (x[i]= y.length >= 2. function divide_(x,y,q,r) { - var kx, ky; - var i,j,y1,y2,c,a,b; - copy_(r,x); - for (ky=y.length;y[ky-1]==0;ky--); //ky is number of elements in y, not including leading zeros + var kx, ky; + var i,j,y1,y2,c,a,b; + copy_(r,x); + for (ky=y.length;y[ky-1]==0;ky--); //ky is number of elements in y, not including leading zeros - //normalize: ensure the most significant element of y has its highest bit set - b=y[ky-1]; - for (a=0; b; a++) - b>>=1; - a=bpe-a; //a is how many bits to shift so that the high order bit of y is leftmost in its array element - leftShift_(y,a); //multiply both by 1<>=1; + a=bpe-a; //a is how many bits to shift so that the high order bit of y is leftmost in its array element + leftShift_(y,a); //multiply both by 1<ky;kx--); //kx is number of elements in normalized x, not including leading zeros + //Rob Visser discovered a bug: the following line was originally just before the normalization. + for (kx=r.length;r[kx-1]==0 && kx>ky;kx--); //kx is number of elements in normalized x, not including leading zeros - copyInt_(q,0); // q=0 - while (!greaterShift(y,r,kx-ky)) { // while (leftShift_(y,kx-ky) <= r) { - subShift_(r,y,kx-ky); // r=r-leftShift_(y,kx-ky) - q[kx-ky]++; // q[kx-ky]++; - } // } + copyInt_(q,0); // q=0 + while (!greaterShift(y,r,kx-ky)) { // while (leftShift_(y,kx-ky) <= r) { + subShift_(r,y,kx-ky); // r=r-leftShift_(y,kx-ky) + q[kx-ky]++; // q[kx-ky]++; + } // } - for (i=kx-1; i>=ky; i--) { - if (r[i]==y[ky-1]) - q[i-ky]=mask; - else - q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]); + for (i=kx-1; i>=ky; i--) { + if (r[i]==y[ky-1]) + q[i-ky]=mask; + else + q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]); - //The following for(;;) loop is equivalent to the commented while loop, - //except that the uncommented version avoids overflow. - //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0 - // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2]) - // q[i-ky]--; - for (;;) { - y2=(ky>1 ? y[ky-2] : 0)*q[i-ky]; - c=y2>>bpe; - y2=y2 & mask; - y1=c+q[i-ky]*y[ky-1]; - c=y1>>bpe; - y1=y1 & mask; + //The following for(;;) loop is equivalent to the commented while loop, + //except that the uncommented version avoids overflow. + //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0 + // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2]) + // q[i-ky]--; + for (;;) { + y2=(ky>1 ? y[ky-2] : 0)*q[i-ky]; + c=y2>>bpe; + y2=y2 & mask; + y1=c+q[i-ky]*y[ky-1]; + c=y1>>bpe; + y1=y1 & mask; - if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i]) - q[i-ky]--; - else - break; - } + if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i]) + q[i-ky]--; + else + break; + } - linCombShift_(r,y,-q[i-ky],i-ky); //r=r-q[i-ky]*leftShift_(y,i-ky) - if (negative(r)) { - addShift_(r,y,i-ky); //r=r+leftShift_(y,i-ky) - q[i-ky]--; - } - } + linCombShift_(r,y,-q[i-ky],i-ky); //r=r-q[i-ky]*leftShift_(y,i-ky) + if (negative(r)) { + addShift_(r,y,i-ky); //r=r+leftShift_(y,i-ky) + q[i-ky]--; + } + } - rightShift_(y,a); //undo the normalization step - rightShift_(r,a); //undo the normalization step + rightShift_(y,a); //undo the normalization step + rightShift_(r,a); //undo the normalization step } //do carries and borrows so each element of the bigInt x fits in bpe bits. function carry_(x) { - var i,k,c,b; - k=x.length; - c=0; - for (i=0;i>bpe); - c+=b*radix; - } - x[i]=c & mask; - c=(c>>bpe)-b; - } + var i,k,c,b; + k=x.length; + c=0; + for (i=0;i>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + } } //return x mod n for bigInt x and integer n. function modInt(x,n) { - var i,c=0; - for (i=x.length-1; i>=0; i--) - c=(c*radix+x[i])%n; - return c; + var i,c=0; + for (i=x.length-1; i>=0; i--) + c=(c*radix+x[i])%n; + return c; } //convert the integer t into a bigInt with at least the given number of bits. @@ -866,12 +866,12 @@ //Pad the array with leading zeros so that it has at least minSize elements. //There will always be at least one leading 0 element. function int2bigInt(t,bits,minSize) { - var i,k; - k=Math.ceil(bits/bpe)+1; - k=minSize>k ? minSize : k; - buff=new Array(k); - copyInt_(buff,t); - return buff; + var i,k; + k=Math.ceil(bits/bpe)+1; + k=minSize>k ? minSize : k; + buff=new Array(k); + copyInt_(buff,t); + return buff; } //return the bigInt given a string representation in a given base. @@ -879,472 +879,472 @@ //If base=-1, then it reads in a space-separated list of array elements in decimal. //The array will always have at least one leading zero, unless base=-1. function str2bigInt(s,base,minSize) { - var d, i, j, x, y, kk; - var k=s.length; - if (base==-1) { //comma-separated list of array elements in decimal - x=new Array(0); - for (;;) { - y=new Array(x.length+1); - for (i=0;i=36) //convert lowercase to uppercase if base<=36 - d-=26; - if (d=0) { //ignore illegal characters - multInt_(x,base); - addInt_(x,d); - } - } + x=int2bigInt(0,base*k,0); + for (i=0;i=36) //convert lowercase to uppercase if base<=36 + d-=26; + if (d=0) { //ignore illegal characters + multInt_(x,base); + addInt_(x,d); + } + } - for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros - k=minSize>k+1 ? minSize : k+1; - y=new Array(k); - kk=k0 && !x[k-1];k--); //strip off leading zeros + k=minSize>k+1 ? minSize : k+1; + y=new Array(k); + kk=ky.length) { - for (;iy.length) { + for (;i0;i--) - s+=x[i]+','; - s+=x[0]; - } - else { //return it in the given base - while (!isZero(s6)) { - t=divInt_(s6,base); //t=s6 % base; s6=floor(s6/base); - s=digitsStr.substring(t,t+1)+s; - } - } - if (s.length==0) - s="0"; - return s; + if (base==-1) { //return the list of array contents + for (i=x.length-1;i>0;i--) + s+=x[i]+','; + s+=x[0]; + } + else { //return it in the given base + while (!isZero(s6)) { + t=divInt_(s6,base); //t=s6 % base; s6=floor(s6/base); + s=digitsStr.substring(t,t+1)+s; + } + } + if (s.length==0) + s="0"; + return s; } //returns a duplicate of bigInt x function dup(x) { - var i; - buff=new Array(x.length); - copy_(buff,x); - return buff; + var i; + buff=new Array(x.length); + copy_(buff,x); + return buff; } //do x=y on bigInts x and y. x must be an array at least as big as y (not counting the leading zeros in y). function copy_(x,y) { - var i; - var k=x.length>=bpe; - } + var i,c; + for (c=n,i=0;i>=bpe; + } } //do x=x+n where x is a bigInt and n is an integer. //x must be large enough to hold the result. function addInt_(x,n) { - var i,k,c,b; - x[0]+=n; - k=x.length; - c=0; - for (i=0;i>bpe); - c+=b*radix; - } - x[i]=c & mask; - c=(c>>bpe)-b; - if (!c) return; //stop carrying as soon as the carry_ is zero - } + var i,k,c,b; + x[0]+=n; + k=x.length; + c=0; + for (i=0;i>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + if (!c) return; //stop carrying as soon as the carry_ is zero + } } //right shift bigInt x by n bits. 0 <= n < bpe. function rightShift_(x,n) { - var i; - var k=Math.floor(n/bpe); - if (k) { - for (i=0;i>n)); - } - x[i]>>=n; + var i; + var k=Math.floor(n/bpe); + if (k) { + for (i=0;i>n)); + } + x[i]>>=n; } //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement function halve_(x) { - var i; - for (i=0;i>1)); - } - x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same + var i; + for (i=0;i>1)); + } + x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same } //left shift bigInt x by n bits. function leftShift_(x,n) { - var i; - var k=Math.floor(n/bpe); - if (k) { - for (i=x.length; i>=k; i--) //left shift x by k elements - x[i]=x[i-k]; - for (;i>=0;i--) - x[i]=0; - n%=bpe; - } - if (!n) - return; - for (i=x.length-1;i>0;i--) { - x[i]=mask & ((x[i]<>(bpe-n))); - } - x[i]=mask & (x[i]<=k; i--) //left shift x by k elements + x[i]=x[i-k]; + for (;i>=0;i--) + x[i]=0; + n%=bpe; + } + if (!n) + return; + for (i=x.length-1;i>0;i--) { + x[i]=mask & ((x[i]<>(bpe-n))); + } + x[i]=mask & (x[i]<>bpe); - c+=b*radix; - } - x[i]=c & mask; - c=(c>>bpe)-b; - } + var i,k,c,b; + if (!n) + return; + k=x.length; + c=0; + for (i=0;i>bpe); + c+=b*radix; + } + x[i]=c & mask; + c=(c>>bpe)-b; + } } //do x=floor(x/n) for bigInt x and integer n, and return the remainder function divInt_(x,n) { - var i,r=0,s; - for (i=x.length-1;i>=0;i--) { - s=r*radix+x[i]; - x[i]=Math.floor(s/n); - r=s%n; - } - return r; + var i,r=0,s; + for (i=x.length-1;i>=0;i--) { + s=r*radix+x[i]; + x[i]=Math.floor(s/n); + r=s%n; + } + return r; } //do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b. //x must be large enough to hold the answer. function linComb_(x,y,a,b) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;i>=bpe; + } } //do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys. //x must be large enough to hold the answer. function linCombShift_(x,y,b,ys) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;c && i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } } //do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys. //x must be large enough to hold the answer. function addShift_(x,y,ys) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;c && i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } } //do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys. //x must be large enough to hold the answer. function subShift_(x,y,ys) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;c && i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } } //do x=x-y for bigInts x and y. //x must be large enough to hold the answer. //negative answers will be 2s complement function sub_(x,y) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;c && i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } } //do x=x+y for bigInts x and y. //x must be large enough to hold the answer. function add_(x,y) { - var i,c,k,kk; - k=x.length>=bpe; - } - for (i=k;c && i>=bpe; - } + var i,c,k,kk; + k=x.length>=bpe; + } + for (i=k;c && i>=bpe; + } } //do x=x*y for bigInts x and y. This is faster when y0 && !x[kx-1]; kx--); //ignore leading zeros in x - k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n - if (s0.length!=k) - s0=new Array(k); - copyInt_(s0,0); - for (i=0;i>=bpe; - for (j=i+1;j>=bpe; - } - s0[i+kx]=c; - } - mod_(s0,n); - copy_(x,s0); + var i,j,d,c,kx,kn,k; + for (kx=x.length; kx>0 && !x[kx-1]; kx--); //ignore leading zeros in x + k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n + if (s0.length!=k) + s0=new Array(k); + copyInt_(s0,0); + for (i=0;i>=bpe; + for (j=i+1;j>=bpe; + } + s0[i+kx]=c; + } + mod_(s0,n); + copy_(x,s0); } //return x with exactly k leading zero elements function bigint_trim(x,k) { - var i,y; - for (i=x.length; i>0 && !x[i-1]; i--); - y=new Array(i+k); - copy_(y,x); - return y; + var i,y; + for (i=x.length; i>0 && !x[i-1]; i--); + y=new Array(i+k); + copy_(y,x); + return y; } //do x=x**y mod n, where x,y,n are bigInts and ** is exponentiation. 0**0=1. //this is faster when n is odd. x usually needs to have as many elements as n. function powMod_(x,y,n) { - var k1,k2,kn,np; - if(s7.length!=n.length) - s7=dup(n); + var k1,k2,kn,np; + if(s7.length!=n.length) + s7=dup(n); - //for even modulus, use a simple square-and-multiply algorithm, - //rather than using the more complex Montgomery algorithm. - if ((n[0]&1)==0) { - copy_(s7,x); - copyInt_(x,1); - while(!equalsInt(y,0)) { - if (y[0]&1) - multMod_(x,s7,n); - divInt_(y,2); - squareMod_(s7,n); - } - return; - } + //for even modulus, use a simple square-and-multiply algorithm, + //rather than using the more complex Montgomery algorithm. + if ((n[0]&1)==0) { + copy_(s7,x); + copyInt_(x,1); + while(!equalsInt(y,0)) { + if (y[0]&1) + multMod_(x,s7,n); + divInt_(y,2); + squareMod_(s7,n); + } + return; + } - //calculate np from n for the Montgomery multiplications - copyInt_(s7,0); - for (kn=n.length;kn>0 && !n[kn-1];kn--); - np=radix-inverseModInt(modInt(n,radix),radix); - s7[kn]=1; - multMod_(x ,s7,n); // x = x * 2**(kn*bp) mod n + //calculate np from n for the Montgomery multiplications + copyInt_(s7,0); + for (kn=n.length;kn>0 && !n[kn-1];kn--); + np=radix-inverseModInt(modInt(n,radix),radix); + s7[kn]=1; + multMod_(x ,s7,n); // x = x * 2**(kn*bp) mod n - if (s3.length!=x.length) - s3=dup(x); - else - copy_(s3,x); + if (s3.length!=x.length) + s3=dup(x); + else + copy_(s3,x); - for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y - if (y[k1]==0) { //anything to the 0th power is 1 - copyInt_(x,1); - return; - } - for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1] - for (;;) { - if (!(k2>>=1)) { //look at next bit of y - k1--; - if (k1<0) { - mont_(x,one,n,np); - return; - } - k2=1<<(bpe-1); - } - mont_(x,x,n,np); + for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y + if (y[k1]==0) { //anything to the 0th power is 1 + copyInt_(x,1); + return; + } + for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1] + for (;;) { + if (!(k2>>=1)) { //look at next bit of y + k1--; + if (k1<0) { + mont_(x,one,n,np); + return; + } + k2=1<<(bpe-1); + } + mont_(x,x,n,np); - if (k2 & y[k1]) //if next bit is a 1 - mont_(x,s3,n,np); - } + if (k2 & y[k1]) //if next bit is a 1 + mont_(x,s3,n,np); + } } //do x=x*y*Ri mod n for bigInts x,y,n, @@ -1358,48 +1358,48 @@ // n is odd // np = -(n^(-1)) mod radix function mont_(x,y,n,np) { - var i,j,c,ui,t; - var kn=n.length; - var ky=y.length; + var i,j,c,ui,t; + var kn=n.length; + var ky=y.length; - if (sa.length!=kn) - sa=new Array(kn); + if (sa.length!=kn) + sa=new Array(kn); - for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n - //this function sometimes gives wrong answers when the next line is uncommented - //for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y + for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n + //this function sometimes gives wrong answers when the next line is uncommented + //for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y - copyInt_(sa,0); + copyInt_(sa,0); - //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large keys - for (i=0; i> bpe; - t=x[i]; + //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large keys + for (i=0; i> bpe; + t=x[i]; - //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe - for (j=1;j>=bpe; - } - for (;j>=bpe; - } - sa[j-1]=c & mask; - } + //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe + for (j=1;j>=bpe; + } + for (;j>=bpe; + } + sa[j-1]=c & mask; + } - if (!greater(n,sa)) - sub_(sa,n); - copy_(x,sa); + if (!greater(n,sa)) + sub_(sa,n); + copy_(x,sa); } /* rijndael.js Rijndael Reference Implementation - Copyright (c) 2001 Fritz Schneider + Copyright (c) 2001 Fritz Schneider This software is provided as-is, without express or implied warranty. Permission to use, copy, modify, distribute or sell this software, with or @@ -1410,38 +1410,38 @@ provided with the application or distribution. - As the above disclaimer notes, you are free to use this code however you - want. However, I would request that you send me an email - (fritz /at/ cs /dot/ ucsd /dot/ edu) to say hi if you find this code useful - or instructional. Seeing that people are using the code acts as - encouragement for me to continue development. If you *really* want to thank - me you can buy the book I wrote with Thomas Powell, _JavaScript: - _The_Complete_Reference_ :) + As the above disclaimer notes, you are free to use this code however you + want. However, I would request that you send me an email + (fritz /at/ cs /dot/ ucsd /dot/ edu) to say hi if you find this code useful + or instructional. Seeing that people are using the code acts as + encouragement for me to continue development. If you *really* want to thank + me you can buy the book I wrote with Thomas Powell, _JavaScript: + _The_Complete_Reference_ :) - This code is an UNOPTIMIZED REFERENCE implementation of Rijndael. - If there is sufficient interest I can write an optimized (word-based, - table-driven) version, although you might want to consider using a - compiled language if speed is critical to your application. As it stands, - one run of the monte carlo test (10,000 encryptions) can take up to - several minutes, depending upon your processor. You shouldn't expect more - than a few kilobytes per second in throughput. + This code is an UNOPTIMIZED REFERENCE implementation of Rijndael. + If there is sufficient interest I can write an optimized (word-based, + table-driven) version, although you might want to consider using a + compiled language if speed is critical to your application. As it stands, + one run of the monte carlo test (10,000 encryptions) can take up to + several minutes, depending upon your processor. You shouldn't expect more + than a few kilobytes per second in throughput. - Also note that there is very little error checking in these functions. - Doing proper error checking is always a good idea, but the ideal - implementation (using the instanceof operator and exceptions) requires - IE5+/NS6+, and I've chosen to implement this code so that it is compatible - with IE4/NS4. + Also note that there is very little error checking in these functions. + Doing proper error checking is always a good idea, but the ideal + implementation (using the instanceof operator and exceptions) requires + IE5+/NS6+, and I've chosen to implement this code so that it is compatible + with IE4/NS4. - And finally, because JavaScript doesn't have an explicit byte/char data - type (although JavaScript 2.0 most likely will), when I refer to "byte" - in this code I generally mean "32 bit integer with value in the interval - [0,255]" which I treat as a byte. + And finally, because JavaScript doesn't have an explicit byte/char data + type (although JavaScript 2.0 most likely will), when I refer to "byte" + in this code I generally mean "32 bit integer with value in the interval + [0,255]" which I treat as a byte. - See http://www-cse.ucsd.edu/~fritz/rijndael.html for more documentation - of the (very simple) API provided by this code. + See http://www-cse.ucsd.edu/~fritz/rijndael.html for more documentation + of the (very simple) API provided by this code. - Fritz Schneider - fritz at cs.ucsd.edu + Fritz Schneider + fritz at cs.ucsd.edu */ @@ -1460,8 +1460,8 @@ // The number of rounds for the cipher, indexed by [Nk][Nb] var roundsArray = [ ,,,,[,,,,10,, 12,, 14],, - [,,,,12,, 12,, 14],, - [,,,,14,, 14,, 14] ]; + [,,,,12,, 12,, 14],, + [,,,,14,, 14,, 14] ]; // The number of bytes to shift by in shiftRow, indexed by [Nb][row] var shiftOffsets = [ ,,,,[,1, 2, 3],,[,1, 2, 3],,[,1, 3, 4] ]; @@ -1487,7 +1487,7 @@ 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, - 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, + 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, @@ -1518,13 +1518,13 @@ function str_split(string, chunklen) { - if(!chunklen) chunklen = 1; - ret = new Array(); - for ( i = 0; i < string.length; i+=chunklen ) - { - ret[ret.length] = string.slice(i, i+chunklen); - } - return ret; + if(!chunklen) chunklen = 1; + ret = new Array(); + for ( i = 0; i < string.length; i+=chunklen ) + { + ret[ret.length] = string.slice(i, i+chunklen); + } + return ret; } // This method circularly shifts the array left by the number of elements @@ -1533,9 +1533,9 @@ // elegant solution, but they require IE5.5+, so I chose to do it manually. function cyclicShiftLeft(theArray, positions) { - var temp = theArray.slice(0, positions); - theArray = theArray.slice(positions).concat(temp); - return theArray; + var temp = theArray.slice(0, positions); + theArray = theArray.slice(positions).concat(temp); + return theArray; } // Cipher parameters ... do not change these @@ -1546,8 +1546,8 @@ // Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec. function xtime(poly) { - poly <<= 1; - return ((poly & 0x100) ? (poly ^ 0x11B) : (poly)); + poly <<= 1; + return ((poly & 0x100) ? (poly ^ 0x11B) : (poly)); } // Multiplies the two elements of GF(2^8) together and returns the result. @@ -1556,13 +1556,13 @@ // to the result. x and y should be bytes representing elements of GF(2^8) function mult_GF256(x, y) { - var bit, result = 0; - - for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) { - if (x & bit) - result ^= y; - } - return result; + var bit, result = 0; + + for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) { + if (x & bit) + result ^= y; + } + return result; } // Performs the substitution step of the cipher. State is the 2d array of @@ -1571,24 +1571,24 @@ // substitution (anything else) function byteSub(state, direction) { - var S; - if (direction == "encrypt") // Point S to the SBox we're using - S = SBox; - else - S = SBoxInverse; - for (var i = 0; i < 4; i++) // Substitute for every byte in state - for (var j = 0; j < Nb; j++) - state[i][j] = S[state[i][j]]; + var S; + if (direction == "encrypt") // Point S to the SBox we're using + S = SBox; + else + S = SBoxInverse; + for (var i = 0; i < 4; i++) // Substitute for every byte in state + for (var j = 0; j < Nb; j++) + state[i][j] = S[state[i][j]]; } // Performs the row shifting step of the cipher. function shiftRow(state, direction) { - for (var i=1; i<4; i++) // Row 0 never shifts - if (direction == "encrypt") - state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]); - else - state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]); + for (var i=1; i<4; i++) // Row 0 never shifts + if (direction == "encrypt") + state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]); + else + state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]); } @@ -1597,34 +1597,34 @@ // to greatly increase the speed. function mixColumn(state, direction) { - var b = []; // Result of matrix multiplications - for (var j = 0; j < Nb; j++) { // Go through each column... - for (var i = 0; i < 4; i++) { // and for each row in the column... - if (direction == "encrypt") - b[i] = mult_GF256(state[i][j], 2) ^ // perform mixing - mult_GF256(state[(i+1)%4][j], 3) ^ - state[(i+2)%4][j] ^ - state[(i+3)%4][j]; - else - b[i] = mult_GF256(state[i][j], 0xE) ^ - mult_GF256(state[(i+1)%4][j], 0xB) ^ - mult_GF256(state[(i+2)%4][j], 0xD) ^ - mult_GF256(state[(i+3)%4][j], 9); - } - for (var i = 0; i < 4; i++) // Place result back into column - state[i][j] = b[i]; - } + var b = []; // Result of matrix multiplications + for (var j = 0; j < Nb; j++) { // Go through each column... + for (var i = 0; i < 4; i++) { // and for each row in the column... + if (direction == "encrypt") + b[i] = mult_GF256(state[i][j], 2) ^ // perform mixing + mult_GF256(state[(i+1)%4][j], 3) ^ + state[(i+2)%4][j] ^ + state[(i+3)%4][j]; + else + b[i] = mult_GF256(state[i][j], 0xE) ^ + mult_GF256(state[(i+1)%4][j], 0xB) ^ + mult_GF256(state[(i+2)%4][j], 0xD) ^ + mult_GF256(state[(i+3)%4][j], 9); + } + for (var i = 0; i < 4; i++) // Place result back into column + state[i][j] = b[i]; + } } // Adds the current round key to the state information. Straightforward. function addRoundKey(state, roundKey) { - for (var j = 0; j < Nb; j++) { // Step through columns... - state[0][j] ^= (roundKey[j] & 0xFF); // and XOR - state[1][j] ^= ((roundKey[j]>>8) & 0xFF); - state[2][j] ^= ((roundKey[j]>>16) & 0xFF); - state[3][j] ^= ((roundKey[j]>>24) & 0xFF); - } + for (var j = 0; j < Nb; j++) { // Step through columns... + state[0][j] ^= (roundKey[j] & 0xFF); // and XOR + state[1][j] ^= ((roundKey[j]>>8) & 0xFF); + state[2][j] ^= ((roundKey[j]>>16) & 0xFF); + state[3][j] ^= ((roundKey[j]>>24) & 0xFF); + } } // This function creates the expanded key from the input (128/192/256-bit) @@ -1633,63 +1633,63 @@ // make up the expanded key. function keyExpansion(key) { - var expandedKey = new Array(); - var temp; + var expandedKey = new Array(); + var temp; - // in case the key size or parameters were changed... - Nk = keySizeInBits / 32; - Nb = blockSizeInBits / 32; - Nr = roundsArray[Nk][Nb]; + // in case the key size or parameters were changed... + Nk = keySizeInBits / 32; + Nb = blockSizeInBits / 32; + Nr = roundsArray[Nk][Nb]; - for (var j=0; j < Nk; j++) // Fill in input key first - expandedKey[j] = - (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24); + for (var j=0; j < Nk; j++) // Fill in input key first + expandedKey[j] = + (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24); - // Now walk down the rest of the array filling in expanded key bytes as - // per Rijndael's spec - for (j = Nk; j < Nb * (Nr + 1); j++) { // For each word of expanded key - temp = expandedKey[j - 1]; - if (j % Nk == 0) - temp = ( (SBox[(temp>>8) & 0xFF]) | - (SBox[(temp>>16) & 0xFF]<<8) | - (SBox[(temp>>24) & 0xFF]<<16) | - (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1]; - else if (Nk > 6 && j % Nk == 4) - temp = (SBox[(temp>>24) & 0xFF]<<24) | - (SBox[(temp>>16) & 0xFF]<<16) | - (SBox[(temp>>8) & 0xFF]<<8) | - (SBox[temp & 0xFF]); - expandedKey[j] = expandedKey[j-Nk] ^ temp; - } - return expandedKey; + // Now walk down the rest of the array filling in expanded key bytes as + // per Rijndael's spec + for (j = Nk; j < Nb * (Nr + 1); j++) { // For each word of expanded key + temp = expandedKey[j - 1]; + if (j % Nk == 0) + temp = ( (SBox[(temp>>8) & 0xFF]) | + (SBox[(temp>>16) & 0xFF]<<8) | + (SBox[(temp>>24) & 0xFF]<<16) | + (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1]; + else if (Nk > 6 && j % Nk == 4) + temp = (SBox[(temp>>24) & 0xFF]<<24) | + (SBox[(temp>>16) & 0xFF]<<16) | + (SBox[(temp>>8) & 0xFF]<<8) | + (SBox[temp & 0xFF]); + expandedKey[j] = expandedKey[j-Nk] ^ temp; + } + return expandedKey; } // Rijndael's round functions... function Round(state, roundKey) { - byteSub(state, "encrypt"); - shiftRow(state, "encrypt"); - mixColumn(state, "encrypt"); - addRoundKey(state, roundKey); + byteSub(state, "encrypt"); + shiftRow(state, "encrypt"); + mixColumn(state, "encrypt"); + addRoundKey(state, roundKey); } function InverseRound(state, roundKey) { - addRoundKey(state, roundKey); - mixColumn(state, "decrypt"); - shiftRow(state, "decrypt"); - byteSub(state, "decrypt"); + addRoundKey(state, roundKey); + mixColumn(state, "decrypt"); + shiftRow(state, "decrypt"); + byteSub(state, "decrypt"); } function FinalRound(state, roundKey) { - byteSub(state, "encrypt"); - shiftRow(state, "encrypt"); - addRoundKey(state, roundKey); + byteSub(state, "encrypt"); + shiftRow(state, "encrypt"); + addRoundKey(state, roundKey); } function InverseFinalRound(state, roundKey){ - addRoundKey(state, roundKey); - shiftRow(state, "decrypt"); - byteSub(state, "decrypt"); + addRoundKey(state, roundKey); + shiftRow(state, "decrypt"); + byteSub(state, "decrypt"); } // encrypt is the basic encryption function. It takes parameters @@ -1698,18 +1698,18 @@ // keyExpansion(). The ciphertext block is returned as an array of bytes. function encrypt(block, expandedKey) { - var i; - if (!block || block.length*8 != blockSizeInBits) - return; - if (!expandedKey) - return; + var i; + if (!block || block.length*8 != blockSizeInBits) + return; + if (!expandedKey) + return; - block = packBytes(block); - addRoundKey(block, expandedKey); - for (i=1; i0; i--) - InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1))); - addRoundKey(block, expandedKey); - return unpackBytes(block); + block = packBytes(block); + InverseFinalRound(block, expandedKey.slice(Nb*Nr)); + for (i = Nr - 1; i>0; i--) + InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1))); + addRoundKey(block, expandedKey); + return unpackBytes(block); } // This function packs an array of bytes into the four row form defined by @@ -1738,19 +1738,19 @@ // column 0, row 0 to 3). This function returns a 2d array. function packBytes(octets) { - var state = new Array(); - if (!octets || octets.length % 4) - return; + var state = new Array(); + if (!octets || octets.length % 4) + return; - state[0] = new Array(); state[1] = new Array(); - state[2] = new Array(); state[3] = new Array(); - for (var j=0; j 0 && i < bpb; i--) - plaintext[plaintext.length] = 0; - - return plaintext; + for (i = bpb - (plaintext.length % bpb); i > 0 && i < bpb; i--) + plaintext[plaintext.length] = 0; + + return plaintext; } // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS @@ -1801,11 +1801,11 @@ // APPLICATION. function getRandomBytes(howMany) { - var i; - var bytes = new Array(); - for (i=0; i0; block--) { - aBlock = - decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey); - if (mode == "CBC") - for (var i=0; i0; block--) { + aBlock = + decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey); + if (mode == "CBC") + for (var i=0; i nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. + be used to endorse or promote products derived from this software without + specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -2132,9 +2132,9 @@ */ var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ function safe_add (x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); } function S (X, n) {return ( X >>> n ) | (X << (32 - n));} function R (X, n) {return ( X >>> n );} @@ -2145,42 +2145,42 @@ function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));} function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));} function core_sha256 (m, l) { - var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2); - var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19); - var W = new Array(64); - var a, b, c, d, e, f, g, h, i, j; - var T1, T2; - /* append padding */ - m[l >> 5] |= 0x80 << (24 - l % 32); - m[((l + 64 >> 9) << 4) + 15] = l; - for ( var i = 0; i> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; + for ( var i = 0; i>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32); - return bin; + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32); + return bin; } function binb2hex (binarray) { - var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ - var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - var str = ""; - for (var i = 0; i < binarray.length * 4; i++) { - str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); - } - return str; + var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for (var i = 0; i < binarray.length * 4; i++) { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; } function hex_sha256(s){return binb2hex(core_sha256(str2binb(s),s.length * chrsz));} @@ -2196,13 +2196,13 @@ function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } function md5_vm_test() { return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; } function core_md5(x, len) { x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i+10], 17, -42063);b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); - a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); } + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i+10], 17, -42063);b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); } function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); } function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); } function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }