Assembly Language Programming

August 4, 2011

Tiny Encryption Algorithm, MD4, MD5, Blowfish Encryption

Filed under: Cryptography, Encryption, JavaScript — Tags: , , , , , — programmer209 @ 7:26 pm

Some Javascript versions of encryption algorithms that I have also implemented in PDP-11 or x86 assembly language.

TEA – Tiny Encryption Algorithm

The following code implements the Tiny Encryption Algorithm (the original version). TEA uses a 128 bit key to encrypt or decrypt a 64 bit block of data. The program accepts the key as a hexadecimal number of up to 32 hex digits, and the input data as a hexadecimal number of up to 16 hex digits.

The output window shows y, z and sum for all 32 iterations of the encryption or decryption process.

<html>

<head>
<title>TEA</title>

<style type="text/css">

*
{
 font-family: Lucida Console;
 font-size: 11pt
}

</style>

</head>

<script type="text/javascript">

// +++++++++++++++++++++++++++++++++++++++++++++++++

function encode()
{
 var V = getInput();

 var K = getKey();

 var y = V[0];

 var z = V[1];

 var sum = 0;

 var delta = 0x9e3779b9;

 var i;

 var tmp;

 var out_str="ENCODE: (y, z, sum)\r\n\r\n";

 for(i=0;i<32;i++)
 {
  sum = Add_32(sum,delta);

  tmp = Add_32(z << 4,K[0]);

  tmp ^= Add_32(z,sum);

  tmp ^= Add_32(z >>> 5,K[1]);

  y = Add_32(y,tmp);

  tmp = Add_32(y << 4,K[2]);

  tmp ^= Add_32(y,sum);

  tmp ^= Add_32(y >>> 5,K[3]);

  z = Add_32(z,tmp);

  out_str += printWord(y) + " " + printWord(z) + "    " + printWord(sum) + "\r\n";
 }

 V[0] = y;

 V[1] = z;

 document.getElementById("txtOutput").value = out_str;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function decode()
{
 var V = getInput();

 var K = getKey();

 var y = V[0];

 var z = V[1];

 var sum = 0;

 var delta = 0x9e3779b9;

 sum = (delta << 5) & 0xffffffff;

 var i;

 var tmp;

 var out_str="DECODE: (y, z, sum)\r\n\r\n";

 for(i=0;i<32;i++)
 {
  tmp = Add_32(y << 4,K[2]);

  tmp ^= Add_32(y,sum);

  tmp ^= Add_32(y >>> 5,K[3]);

  z = Sub_32(z,tmp);

  tmp = Add_32(z << 4,K[0]);

  tmp ^= Add_32(z,sum);

  tmp ^= Add_32(z >>> 5,K[1]);

  y = Sub_32(y,tmp);

  sum = Sub_32(sum,delta);

  out_str += printWord(y) + " " + printWord(z) + "    " + printWord(sum) + "\r\n";
 }

 V[0] = y;

 V[1] = z;

 document.getElementById("txtOutput").value = out_str;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function Add_32(A,B)
{
 // add two 32 bit unsigned words:

 var result = (A>>>0) + (B>>>0);

 return result & 0xffffffff;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function Sub_32(A,B)
{
 // sub two 32 bit unsigned words:

 var result = ~(B>>>0) + 1;

 result += (A>>>0);

 return result & 0xffffffff;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function getInput()
{
 var input=document.getElementById("txtInput").value;

 var V = [];

 input = input.replace(/\s{1,}/g,"");

 if(input.length > 8)
 {
  var tmp = input.substr(input.length-8,8);

  V[1] = parseInt(tmp,16) & 0xffffffff;

  tmp = input.substr(0,input.length-8);

  V[0] = parseInt(tmp,16) & 0xffffffff;
 }
 else
 {
  V[1] = parseInt(input,16) & 0xffffffff;

  V[0] = 0;
 }

 return V;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function getKey()
{
 var input=document.getElementById("txtKey").value;

 var K = [];

 K[0] = K[1] = K[2] = K[3] = 0;

 input = input.replace(/\s{1,}/g,"");

 for(i=3;i>=0;i--)
 {
  K[i] = getLowerWord(input);

  if(input.length > 8)
  {
   input = input.substr(0,input.length-8);
  }
  else break;
 }

 return K;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function getLowerWord(str)
{
 var wd=0;

 if(str.length > 8)
 {
  var tmp = str.substr(str.length-8,8);

  wd = parseInt(tmp,16) & 0xffffffff;  
 }
 else
 {
  wd = parseInt(str,16) & 0xffffffff;  
 }

 return wd;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function printWord(val)
{
 var str = (val>>>0).toString(16);

 while(str.length < 8)
 {
  str = "0" + str;
 }

 return str;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

function Clear()
{
 document.getElementById("txtKey").value = "";
 document.getElementById("txtInput").value = "";
 document.getElementById("txtOutput").value = "";
}

// +++++++++++++++++++++++++++++++++++++++++++++++++

</script>

<body>

<input type="button" value="Encode" onClick="encode()">
<input type="button" value="Decode" onClick="decode()">
<input type="button" value="Clear" onClick="Clear()">

<br><br>

Key:<br><input type="text" id="txtKey" size="60">

<br><br>

Input:<br><input type="text" id="txtInput" size="60">

<br><br>

Output:<br>

<textarea id="txtOutput" rows="30" cols="60"></textarea>

</body>

</html>

MD4 and MD5 Message Digest Algorithms

The following code calculates both the MD4 and MD5 message digests for the input message.

The MD4 Message Digest Algorithm is specified in RFC 1320:

http://www.faqs.org/rfcs/rfc1320.html

The MD5 Message Digest Algorithm is specified in RFC 1321:

http://www.faqs.org/rfcs/rfc1321.html

These algorithms take an input message of arbitrary length and produces a 128 bit message digest. Once the input message has been padded, it is broken up into 512 bit blocks. Each block is further broken up into 16 words of 32 bits each. Within each 32 bit word, the bytes are considered to be in little endian byte order. So for example, the very first message byte will be the lowest byte within the first 32 bit word. Therefore, when writing C or Javascript code to process the message, the order of bytes within each word will need to be reversed to make a hexadecimal number that can be manipulated by the code.

The same applies to the output message digest. The parameters A, B, C and D store the message digest. The specifications (RFCs 1320 and 1321) require that these be printed in little endian byte order. Therefore, the C or Javascript code will need to reverse the byte order within each of A, B, C and D before printing them.

Note that this program requires a hexadecimal number as input. A text string can still be input, but the [To Hex] button must be pressed to convert it to a hexadecimal number before the [Calc MD] button is pressed to compute the message digest.

<html>

<head>

<title>MD4 MD5 Calculator</title>

<style type="text/css">

*
{
 font-family: Lucida Console;

 font-size: 11pt;
}

</style>

</head>

<script type="text/javascript">

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Calc_MD()
{
 var msg_arr = getMessage();

 var md4 = CalcMD4(msg_arr);

 var md5 = CalcMD5(msg_arr);

 var outstr = "MD4 Hash:\r\n\r\n";

 outstr += md4 + "\r\n\r\n";

 outstr += "MD5 Hash:\r\n\r\n";

 outstr += md5 + "\r\n\r\n";

 var i;

 outstr += "Message (padded):\r\n\r\n";

 var count=0;

 for(i=0;i<msg_arr.length;i++)
 {
  outstr += printWord(msg_arr[i]) + " ";

  count++;

  if(count==8)
  {
   count=0;

   outstr += "\r\n";
  }
 }

 document.getElementById("input").value = outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function CalcMD4(msg_arr)
{
 var i,j,k;

 var S=[3,7,11,19,3,5,9,13,3,9,11,15];

 var xr1=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

 var xr2=[0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15];

 var xr3=[0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15];

 var X=[];

 var A = 0x67452301;
 var B = 0xefcdab89;
 var C = 0x98badcfe;
 var D = 0x10325476;

 var AA,BB,CC,DD;

 for(i=0;i<msg_arr.length/16;i++)
 {
  for(j=0;j<16;j++)
  {
   // 32 bit words are in little endian:

   X[j] = reverseBytes(msg_arr[j+i*16]);
  }

  var x_index=0;
  var s_index=0;

  AA = A;
  BB = B;
  CC = C;
  DD = D;

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=0;

   A = FF_md4(A,B,C,D,X[xr1[x_index++]],S[s_index++]);
   D = FF_md4(D,A,B,C,X[xr1[x_index++]],S[s_index++]);
   C = FF_md4(C,D,A,B,X[xr1[x_index++]],S[s_index++]);
   B = FF_md4(B,C,D,A,X[xr1[x_index++]],S[s_index++]);
  }

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=4;

   A = GG_md4(A,B,C,D,X[xr2[x_index++]],S[s_index++]);
   D = GG_md4(D,A,B,C,X[xr2[x_index++]],S[s_index++]);
   C = GG_md4(C,D,A,B,X[xr2[x_index++]],S[s_index++]);
   B = GG_md4(B,C,D,A,X[xr2[x_index++]],S[s_index++]);
  }

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=8;

   A = HH_md4(A,B,C,D,X[xr3[x_index++]],S[s_index++]);
   D = HH_md4(D,A,B,C,X[xr3[x_index++]],S[s_index++]);
   C = HH_md4(C,D,A,B,X[xr3[x_index++]],S[s_index++]);
   B = HH_md4(B,C,D,A,X[xr3[x_index++]],S[s_index++]);
  }

  A = Add_32(A,AA);
  B = Add_32(B,BB);
  C = Add_32(C,CC);
  D = Add_32(D,DD);
 }

 // MD is in little endian:

 A = reverseBytes(A);
 B = reverseBytes(B);
 C = reverseBytes(C);
 D = reverseBytes(D);

 var md4 = "";

 md4 += printWord(A) + " ";

 md4 += printWord(B) + " ";

 md4 += printWord(C) + " ";

 md4 += printWord(D);

 return md4;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function F_md4(X,Y,Z)
{
 return (X & Y) | ((~X) & Z);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function G_md4(X,Y,Z)
{
 return (X & Y) | (X & Z) | (Y & Z);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function H_md4(X,Y,Z)
{
 return (X ^ Y ^ Z);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function FF_md4(A,B,C,D,X,s)
{
 var tmp = F_md4(B,C,D);

 tmp = Add_32(tmp,A);

 tmp = Add_32(tmp,X);

 tmp = RotLeft(tmp,s);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function GG_md4(A,B,C,D,X,s)
{
 var T=0x5a827999;

 var tmp = G_md4(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function HH_md4(A,B,C,D,X,s)
{
 var T=0x6ed9eba1;

 var tmp = H_md4(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function CalcMD5(msg_arr)
{
 var i,j,k;

 var S=[7,12,17,22,5,9,14,20,4,11,16,23,6,10,15,21];

 var xr1=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

 var xr2=[1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12];

 var xr3=[5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2];

 var xr4=[0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9];

 var X=[];

 var T = [];

 T[0]=0xd76aa478;
 T[1]=0xe8c7b756;
 T[2]=0x242070db;
 T[3]=0xc1bdceee;
 T[4]=0xf57c0faf;
 T[5]=0x4787c62a;
 T[6]=0xa8304613;
 T[7]=0xfd469501;
 T[8]=0x698098d8;
 T[9]=0x8b44f7af;
 T[10]=0xffff5bb1;
 T[11]=0x895cd7be;
 T[12]=0x6b901122;
 T[13]=0xfd987193;
 T[14]=0xa679438e;
 T[15]=0x49b40821;
 T[16]=0xf61e2562;
 T[17]=0xc040b340;
 T[18]=0x265e5a51;
 T[19]=0xe9b6c7aa;
 T[20]=0xd62f105d;
 T[21]=0x02441453;
 T[22]=0xd8a1e681;
 T[23]=0xe7d3fbc8;
 T[24]=0x21e1cde6;
 T[25]=0xc33707d6;
 T[26]=0xf4d50d87;
 T[27]=0x455a14ed;
 T[28]=0xa9e3e905;
 T[29]=0xfcefa3f8;
 T[30]=0x676f02d9;
 T[31]=0x8d2a4c8a;
 T[32]=0xfffa3942;
 T[33]=0x8771f681;
 T[34]=0x6d9d6122;
 T[35]=0xfde5380c;
 T[36]=0xa4beea44;
 T[37]=0x4bdecfa9;
 T[38]=0xf6bb4b60;
 T[39]=0xbebfbc70;
 T[40]=0x289b7ec6;
 T[41]=0xeaa127fa;
 T[42]=0xd4ef3085;
 T[43]=0x04881d05;
 T[44]=0xd9d4d039;
 T[45]=0xe6db99e5;
 T[46]=0x1fa27cf8;
 T[47]=0xc4ac5665;
 T[48]=0xf4292244;
 T[49]=0x432aff97;
 T[50]=0xab9423a7;
 T[51]=0xfc93a039;
 T[52]=0x655b59c3;
 T[53]=0x8f0ccc92;
 T[54]=0xffeff47d;
 T[55]=0x85845dd1;
 T[56]=0x6fa87e4f;
 T[57]=0xfe2ce6e0;
 T[58]=0xa3014314;
 T[59]=0x4e0811a1;
 T[60]=0xf7537e82;
 T[61]=0xbd3af235;
 T[62]=0x2ad7d2bb;
 T[63]=0xeb86d391;

 var A = 0x67452301;
 var B = 0xefcdab89;
 var C = 0x98badcfe;
 var D = 0x10325476;

 for(i=0;i<msg_arr.length/16;i++)
 {
  for(j=0;j<16;j++)
  {
   X[j] = reverseBytes(msg_arr[j+i*16]);
  }

  var x_index=0;
  var s_index=0;
  var t_index=0;

  var AA = A;
  var BB = B;
  var CC = C;
  var DD = D;

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=0;

   A = FF_md5(A,B,C,D,X[xr1[x_index++]],S[s_index++],T[t_index++]);
   D = FF_md5(D,A,B,C,X[xr1[x_index++]],S[s_index++],T[t_index++]);
   C = FF_md5(C,D,A,B,X[xr1[x_index++]],S[s_index++],T[t_index++]);
   B = FF_md5(B,C,D,A,X[xr1[x_index++]],S[s_index++],T[t_index++]);
  }

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=4;

   A = GG_md5(A,B,C,D,X[xr2[x_index++]],S[s_index++],T[t_index++]);
   D = GG_md5(D,A,B,C,X[xr2[x_index++]],S[s_index++],T[t_index++]);
   C = GG_md5(C,D,A,B,X[xr2[x_index++]],S[s_index++],T[t_index++]);
   B = GG_md5(B,C,D,A,X[xr2[x_index++]],S[s_index++],T[t_index++]);
  }

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=8;

   A = HH_md5(A,B,C,D,X[xr3[x_index++]],S[s_index++],T[t_index++]);
   D = HH_md5(D,A,B,C,X[xr3[x_index++]],S[s_index++],T[t_index++]);
   C = HH_md5(C,D,A,B,X[xr3[x_index++]],S[s_index++],T[t_index++]);
   B = HH_md5(B,C,D,A,X[xr3[x_index++]],S[s_index++],T[t_index++]);
  }

  x_index=0;

  for(k=0;k<4;k++)
  {
   s_index=12;

   A = II_md5(A,B,C,D,X[xr4[x_index++]],S[s_index++],T[t_index++]);
   D = II_md5(D,A,B,C,X[xr4[x_index++]],S[s_index++],T[t_index++]);
   C = II_md5(C,D,A,B,X[xr4[x_index++]],S[s_index++],T[t_index++]);
   B = II_md5(B,C,D,A,X[xr4[x_index++]],S[s_index++],T[t_index++]);
  }

  A = Add_32(A,AA);
  B = Add_32(B,BB);
  C = Add_32(C,CC);
  D = Add_32(D,DD);
 }

 // MD is in little endian:

 A = reverseBytes(A);
 B = reverseBytes(B);
 C = reverseBytes(C);
 D = reverseBytes(D);

 var md5="";

 md5 += printWord(A) + " ";

 md5 += printWord(B) + " ";

 md5 += printWord(C) + " ";

 md5 += printWord(D);

 return md5;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function F_md5(X,Y,Z)
{
 return (X & Y) | ((~X) & Z);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function G_md5(X,Y,Z)
{
 return (X & Z) | (Y & (~Z));
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function H_md5(X,Y,Z)
{
 return (X ^ Y ^ Z);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function I_md5(X,Y,Z)
{
 return Y ^ (X | (~Z));
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function FF_md5(A,B,C,D,X,s,T)
{
 var tmp = F_md5(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 tmp = Add_32(tmp,B);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function GG_md5(A,B,C,D,X,s,T)
{
 var tmp = G_md5(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 tmp = Add_32(tmp,B);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function HH_md5(A,B,C,D,X,s,T)
{
 var tmp = H_md5(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 tmp = Add_32(tmp,B);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function II_md5(A,B,C,D,X,s,T)
{
 var tmp = I_md5(B,C,D);

 tmp = Add_32(tmp,A);
 tmp = Add_32(tmp,X);
 tmp = Add_32(tmp,T);

 tmp = RotLeft(tmp,s);

 tmp = Add_32(tmp,B);

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function RotLeft(word,rot)
{
 var tmp = (word << rot) | (word >>> (32-rot));

 tmp &= 0xffffffff;

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Add_32(x,y)
{
 // add x and y as 32 bit unsigned values:

 var tmp = (x>>>0) + (y>>>0);

 tmp &= 0xffffffff;

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function reverseBytes(word)
{
 // reverse the bytes in a 32 bit word:

 var tmp = word & 0xffff;

 tmp <<= 16;

 tmp += word >>> 16;

 word = tmp;

 tmp = (tmp >>> 8) & 0x00ff00ff;

 tmp += (word << 8) & 0xff00ff00;

 tmp &= 0xffffffff;

 return tmp;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function getMessage()
{
 var m_str = document.getElementById("input").value;

 m_str = m_str.replace(/\s{1,}/g,"");

 m_str = m_str.replace(/[\r\n]{1,}/g,"");

 // message length in nibbles:

 var m_len = m_str.length; 

 // 512 bits = 128 nibbles

 // pad the message:

 var new_len = m_len - (m_len % 128) + 128;

 if((new_len - m_len) <= 8) new_len += 128;

 var i;

 m_str += "8";

 for(i=0;i<new_len-m_len-1;i++)
 {
  m_str += "0";
 }

 // convert the string to an array of 32 bit words:

 var msg_arr = [];

 for(i=0;i<m_str.length/8;i++)
 {
  var tstr = m_str.substr(8*i,8);
 
  msg_arr[i]=parseInt(tstr,16);
 }

 // insert the bit length in little endian:

 // message is not likely to be greater than 2^32 bits:

 msg_arr[msg_arr.length-2] = reverseBytes(4*m_len);

 return msg_arr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function ToHex()
{
 var tmpstr=document.getElementById("input").value;

 // convert a text string to a hexadecimal number string:

 if(tmpstr.length == 0)
 {
  document.getElementById("input").value = "Error - NULL input.";
 
  return;
 }

 var outstr = "";

 var i;

 for(i=0;i<tmpstr.length;i++)
 {
  var asc = tmpstr.charCodeAt(i);

  // no need to worry about leading zeros, hex values for
  // printable characters are >= 0x20:

  if(asc >= 32) outstr += asc.toString(16);
 }

 document.getElementById("input").value=outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Clear()
{
 document.getElementById("input").value="";
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function printWord(val)
{
 var str = (val>>>0).toString(16);

 while(str.length < 8)
 {
  str = "0" + str;
 }

 return str;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

</script>

<body>

<pre>
<strong>
MD4 MD5 Calculator:

Input a hex number, or input a text string and press ToHex
to convert to a hex number.
</strong>
</pre>

<input type="button" value="Calc MD" onClick="Calc_MD()">
<input type="button" value="To Hex" onClick="ToHex()">
<input type="button" value="Clear" onClick="Clear()">

<br><br>

<textarea id="input" rows="30" cols="80"></textarea>

</body>

</html>

Blowfish Encryption

An outline of the blowfish encryption algorithm is given in the post for the x86 assembly language version:

FASM – x86 Blowfish Implementation.

<html>

<head>

<title>Blowfish</title>

<style type="text/css">

*
{
 font-family: Lucida Console;

 font-size: 11pt;
}

</style>

</head>

<script type="text/javascript">

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 var g_PI_Arr = [];

 var g_Key_Arr = [];

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function StrToHexStr(str)
{
 // remove all characters that are not hex digits:

 var ptn_not_hex = /[^0-9a-fA-F]{1,}/g; 

 str = str.replace(ptn_not_hex,"");

 return str;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function PadMesssageStr(str)
{
 // pad the message string:

 // new length is a multiple of 16

 if(str.length % 16 == 0) return str;

 var len = str.length;

 var new_len = len - (len % 16) + 16;

 var i;

 for(i=0;i<new_len-len;i++)
 {
  str += "0";
 }

 return str;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function FillKeyBits(str)
{
 // key length in hex digits:

 if(str.length > 112)
 {
  // max length of key is 56 bytes:

  str = str.slice(0,112);
 }

 // copy up the hex digits until there are 72 bytes of key bits

 while(str.length < 144)
 {
  str += str;
 }

 if(str.length > 144)
 {
  str = str.slice(0,144);
 }

 return str;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function HexStrToArray(str)
{
 // convert the string to an array of 32 bit words:

 var hex_arr = [];

 for(var i=0;i<str.length/8;i++)
 {
  var tstr = str.substr(8*i,8);

  var tmp = parseInt(tstr,16);
 
  hex_arr[i] = tmp & 0xffffffff;
 }

 return hex_arr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function getMessage()
{
 // get the input string and convert to hex data in memory

 var str = document.getElementById("input").value;

 if(str.length <= 0)
 {
  str = "0";
 }

 str = StrToHexStr(str);

 str = PadMesssageStr(str);

 // store as an array of 32 bit words:

 var hex_arr = [];

 hex_arr = HexStrToArray(str);

 return hex_arr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function getKey()
{
 // get the input key

 var str = document.getElementById("input").value;

 if(str.length <= 0)
 {
  str = "0";
 }

 str = StrToHexStr(str);

 // expand the key bits to 72 bytes:

 str = FillKeyBits(str);

 // convert the string to an array of 32 bit words:

 var hex_arr = [];

 hex_arr = HexStrToArray(str);

 return hex_arr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function HexArrToStr(hex_arr)
{
 // print a hex array to a string

 var count = 0;

 var outstr = "";

 var len = hex_arr.length;

 // print each 32 bit word:

 // include spaces and CRLF

 for(var i=0;i<len;i++)
 {
  outstr += printWord(hex_arr[i]) + " ";

  count++;

  if(count==8)
  {
   count=0;

   outstr += "\r\n";
  }  
 } 

 return outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function PrintKey()
{
 var outstr = "Current Key Bits:\r\n\r\n"; 

 outstr += HexArrToStr(g_Key_Arr);

 document.getElementById("key_msg").innerHTML = outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Print_PI_Arr()
{
 document.getElementById("input").value = HexArrToStr(g_PI_Arr);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Init_PI_Arr()
{
 // initialise the sub key array with the digits of PI:

 var P1 = "243f6a8885a308d313198a2e03707344a4093822299f31d0";
 var P2 = "082efa98ec4e6c89452821e638d01377be5466cf34e90c6c";
 var P3 = "c0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1b";

 var S1= "d1310ba698dfb5ac2ffd72dbd01adfb7b8e1afed6a267e96ba7c9045f12c7f99";
 var S2= "24a19947b3916cf70801f2e2858efc16636920d871574e69a458fea3f4933d7e";
 var S3= "0d95748f728eb658718bcd5882154aee7b54a41dc25a59b59c30d5392af26013";
 var S4= "c5d1b023286085f0ca417918b8db38ef8e79dcb0603a180e6c9e0e8bb01e8a3e";
 var S5= "d71577c1bd314b2778af2fda55605c60e65525f3aa55ab945748986263e81440";
 var S6= "55ca396a2aab10b6b4cc5c341141e8cea15486af7c72e993b3ee1411636fbc2a";
 var S7= "2ba9c55d741831f6ce5c3e169b87931eafd6ba336c24cf5c7a32538128958677";
 var S8= "3b8f48986b4bb9afc4bfe81b6628219361d809ccfb21a991487cac605dec8032";
 var S9= "ef845d5de98575b1dc262302eb651b8823893e81d396acc50f6d6ff383f44239";
 var S10= "2e0b4482a484200469c8f04a9e1f9b5e21c66842f6e96c9a670c9c61abd388f0";
 var S11= "6a51a0d2d8542f68960fa728ab5133a36eef0b6c137a3be4ba3bf0507efb2a98";
 var S12= "a1f1651d39af017666ca593e82430e888cee8619456f9fb47d84a5c33b8b5ebe";
 var S13= "e06f75d885c12073401a449f56c16aa64ed3aa62363f77061bfedf72429b023d";
 var S14= "37d0d724d00a1248db0fead349f1c09b075372c980991b7b25d479d8f6e8def7";
 var S15= "e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a2463";
 var S16= "68fb6faf3e6c53b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09";
 var S17= "bee3d004de334afd660f2807192e4bb3c0cba85745c8740fd20b5f39b9d3fbdb";
 var S18= "5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3cc8ea5e9f8db3222f8";
 var S19= "3c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df82";
 var S20= "9e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573";
 var S21= "695b27b0bbca58c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b";
 var S22= "9a53e479b6f84565d28e49bc4bfb9790e1ddf2daa4cb7e3362fb1341cee4c6e8";
 var S23= "ef20cada36774c01d07e9efe2bf11fb495dbda4dae909198eaad8e716b93d5a0";
 var S24= "d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df01c";
 var S25= "4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1";
 var S26= "e5a0cc0fb56f74e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9";
 var S27= "165fa2668095770593cc7314211a1477e6ad206577b5fa86c75442f5fb9d35cf";
 var S28= "ebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b35e226800bb57b8e0af";
 var S29= "2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9c5";
 var S30= "832603766295cfa911c819684e734a41b3472dca7b14a94a1b5100529a532915";
 var S31= "d60f573fbc9bc6e42b60a47681e6740008ba6fb5571be91ff296ec6b2a0dd915";
 var S32= "b6636521e7b9f9b6ff34052ec585566453b02d5da99f8fa108ba47996e85076a";
 var S33= "4b7a70e9b5b32944db75092ec4192623ad6ea6b049a7df7d9cee60b88fedb266";
 var S34= "ecaa8c71699a17ff5664526cc2b19ee1193602a575094c29a0591340e4183a3e";
 var S35= "3f54989a5b429d656b8fe4d699f73fd6a1d29c07efe830f54d2d38e6f0255dc1";
 var S36= "4cdd20868470eb266382e9c6021ecc5e09686b3f3ebaefc93c9718146b6a70a1";
 var S37= "687f358452a0e286b79c5305aa5007373e07841c7fdeae5c8e7d44ec5716f2b8";
 var S38= "b03ada37f0500c0df01c1f040200b3ffae0cf51a3cb574b225837a58dc0921bd";
 var S39= "d19113f97ca92ff69432477322f547013ae5e58137c2dadcc8b576349af3dda7";
 var S40= "a94461460fd0030eecc8c73ea4751e41e238cd993bea0e2f3280bba1183eb331";
 var S41= "4e548b384f6db9086f420d03f60a04bf2cb8129024977c795679b072bcaf89af";
 var S42= "de9a771fd9930810b38bae12dccf3f2e5512721f2e6b7124501adde69f84cd87";
 var S43= "7a5847187408da17bc9f9abce94b7d8cec7aec3adb851dfa63094366c464c3d2";
 var S44= "ef1c18473215d908dd433b3724c2ba1612a14d432a65c45150940002133ae4dd";
 var S45= "71dff89e10314e5581ac77d65f11199b043556f1d7a3c76b3c11183b5924a509";
 var S46= "f28fe6ed97f1fbfa9ebabf2c1e153c6e86e34570eae96fb1860e5e0a5a3e2ab3";
 var S47= "771fe71c4e3d06fa2965dcb999e71d0f803e89d65266c8252e4cc9789c10b36a";
 var S48= "c6150eba94e2ea78a5fc3c531e0a2df4f2f74ea7361d2b3d1939260f19c27960";
 var S49= "5223a708f71312b6ebadfe6eeac31f66e3bc4595a67bc883b17f37d1018cff28";
 var S50= "c332ddefbe6c5aa56558218568ab9802eecea50fdb2f953b2aef7dad5b6e2f84";
 var S51= "1521b62829076170ecdd4775619f151013cca830eb61bd960334fe1eaa0363cf";
 var S52= "b5735c904c70a239d59e9e0bcbaade14eecc86bc60622ca79cab5cabb2f3846e";
 var S53= "648b1eaf19bdf0caa02369b9655abb5040685a323c2ab4b3319ee9d5c021b8f7";
 var S54= "9b540b19875fa09995f7997e623d7da8f837889a97e32d7711ed935f16681281";
 var S55= "0e358829c7e61fd696dedfa17858ba9957f584a51b2272639b83c3ff1ac24696";
 var S56= "cdb30aeb532e30548fd948e46dbc312858ebf2ef34c6ffeafe28ed61ee7c3c73";
 var S57= "5d4a14d9e864b7e342105d14203e13e045eee2b6a3aaabeadb6c4f15facb4fd0";
 var S58= "c742f442ef6abbb5654f3b1d41cd2105d81e799e86854dc7e44b476a3d816250";
 var S59= "cf62a1f25b8d2646fc8883a0c1c7b6a37f1524c369cb749247848a0b5692b285";
 var S60= "095bbf00ad19489d1462b17423820e0058428d2a0c55f5ea1dadf43e233f7061";
 var S61= "3372f0928d937e41d65fecf16c223bdb7cde3759cbee74604085f2a7ce77326e";
 var S62= "a607808419f8509ee8efd85561d99735a969a7aac50c06c25a04abfc800bcadc";
 var S63= "9e447a2ec3453484fdd567050e1e9ec9db73dbd3105588cd675fda79e3674340";
 var S64= "c5c43465713e38d83d28f89ef16dff20153e21e78fb03d4ae6e39f2bdb83adf7";
 var S65= "e93d5a68948140f7f64c261c94692934411520f77602d4f7bcf46b2ed4a20068";
 var S66= "d40824713320f46a43b7d4b7500061af1e39f62e9724454614214f74bf8b8840";
 var S67= "4d95fc1d96b591af70f4ddd366a02f45bfbc09ec03bd97857fac6dd031cb8504";
 var S68= "96eb27b355fd3941da2547e6abca0a9a28507825530429f40a2c86dae9b66dfb";
 var S69= "68dc1462d7486900680ec0a427a18dee4f3ffea2e887ad8cb58ce0067af4d6b6";
 var S70= "aace1e7cd3375fecce78a399406b2a4220fe9e35d9f385b9ee39d7ab3b124e8b";
 var S71= "1dc9faf74b6d185626a36631eae397b23a6efa74dd5b43326841e7f7ca7820fb";
 var S72= "fb0af54ed8feb397454056acba48952755533a3a20838d87fe6ba9b7d096954b";
 var S73= "55a867bca1159a58cca9296399e1db33a62a4a563f3125f95ef47e1c9029317c";
 var S74= "fdf8e80204272f7080bb155c05282ce395c11548e4c66d2248c1133fc70f86dc";
 var S75= "07f9c9ee41041f0f404779a45d886e17325f51ebd59bc0d1f2bcc18f41113564";
 var S76= "257b7834602a9c60dff8e8a31f636c1b0e12b4c202e1329eaf664fd1cad18115";
 var S77= "6b2395e0333e92e13b240b62eebeb92285b2a20ee6ba0d99de720c8c2da2f728";
 var S78= "d012784595b794fd647d0862e7ccf5f05449a36f877d48fac39dfd27f33e8d1e";
 var S79= "0a476341992eff743a6f6eabf4f8fd37a812dc60a1ebddf8991be14cdb6e6b0d";
 var S80= "c67b55106d672c372765d43bdcd0e804f1290dc7cc00ffa3b5390f92690fed0b";
 var S81= "667b9ffbcedb7d9ca091cf0bd9155ea3bb132f88515bad247b9479bf763bd6eb";
 var S82= "37392eb3cc1159798026e297f42e312d6842ada7c66a2b3b12754ccc782ef11c";
 var S83= "6a124237b79251e706a1bbe64bfb63501a6b101811caedfa3d25bdd8e2e1c3c9";
 var S84= "444216590a121386d90cec6ed5abea2a64af674eda86a85fbebfe98864e4c3fe";
 var S85= "9dbc8057f0f7c08660787bf86003604dd1fd8346f6381fb07745ae04d736fccc";
 var S86= "83426b33f01eab71b08041873c005e5f77a057bebde8ae2455464299bf582e61";
 var S87= "4e58f48ff2ddfda2f474ef388789bdc25366f9c3c8b38e74b475f25546fcd9b9";
 var S88= "7aeb26618b1ddf84846a0e79915f95e2466e598e20b457708cd55591c902de4c";
 var S89= "b90bace1bb8205d011a862487574a99eb77f19b6e0a9dc09662d09a1c4324633";
 var S90= "e85a1f0209f0be8c4a99a0251d6efe101ab93d1d0ba5a4dfa186f20f2868f169";
 var S91= "dcb7da83573906fea1e2ce9b4fcd7f5250115e01a70683faa002b5c40de6d027";
 var S92= "9af88c27773f8641c3604c0661a806b5f0177a28c0f586e0006058aa30dc7d62";
 var S93= "11e69ed72338ea6353c2dd94c2c21634bbcbee5690bcb6deebfc7da1ce591d76";
 var S94= "6f05e4094b7c018839720a3d7c927c2486e3725f724d9db91ac15bb4d39eb8fc";
 var S95= "ed54557808fca5b5d83d7cd34dad0fc41e50ef5eb161e6f8a28514d96c51133c";
 var S96= "6fd5c7e756e14ec4362abfceddc6c837d79a323492638212670efa8e406000e0";
 var S97= "3a39ce37d3faf5cfabc277375ac52d1b5cb0679e4fa33742d382274099bc9bbe";
 var S98= "d5118e9dbf0f7315d62d1c7ec700c47bb78c1b6b21a19045b26eb1be6a366eb4";
 var S99= "5748ab2fbc946e79c6a376d26549c2c8530ff8ee468dde7dd5730a1d4cd04dc6";
 var S100= "2939bbdba9ba4650ac9526e8be5ee304a1fad5f06a2d519a63ef8ce29a86ee22";
 var S101= "c089c2b843242ef6a51e03aa9cf2d0a483c061ba9be96a4d8fe51550ba645bd6";
 var S102= "2826a2f9a73a3ae14ba99586ef5562e9c72fefd3f752f7da3f046f6977fa0a59";
 var S103= "80e4a91587b086019b09e6ad3b3ee593e990fd5a9e34d7972cf0b7d9022b8b51";
 var S104= "96d5ac3a017da67dd1cf3ed67c7d2d281f9f25cfadf2b89b5ad6b4725a88f54c";
 var S105= "e029ac71e019a5e647b0acfded93fa9be8d3c48d283b57ccf8d5662979132e28";
 var S106= "785f0191ed756055f7960e44e3d35e8c15056dd488f46dba03a161250564f0bd";
 var S107= "c3eb9e153c9057a297271aeca93a072a1b3f6d9b1e6321f5f59c66fb26dcf319";
 var S108= "7533d928b155fdf5035634828aba3cbb28517711c20ad9f8abcc5167ccad925f";
 var S109= "4de817513830dc8e379d58629320f991ea7a90c2fb3e7bce5121ce64774fbe32";
 var S110= "a8b6e37ec3293d4648de53696413e680a2ae0810dd6db22469852dfd09072166";
 var S111= "b39a460a6445c0dd586cdecf1c20c8ae5bbef7dd1b588d40ccd2017f6bb4e3bb";
 var S112= "dda26a7e3a59ff453e350a44bcb4cdd572eacea8fa6484bb8d6612aebf3c6f47";
 var S113= "d29be463542f5d9eaec2771bf64e6370740e0d8de75b1357f8721671af537d5d";
 var S114= "4040cb084eb4e2cc34d2466a0115af84e1b0042895983a1d06b89fb4ce6ea048";
 var S115= "6f3f3b823520ab82011a1d4b277227f8611560b1e7933fdcbb3a792b344525bd";
 var S116= "a08839e151ce794b2f32c9b7a01fbac9e01cc87ebcc7d1f6cf0111c3a1e8aac7";
 var S117= "1a908749d44fbd9ad0dadecbd50ada380339c32ac69136678df9317ce0b12b4f";
 var S118= "f79e59b743f5bb3af2d519ff27d9459cbf97222c15e6fc2a0f91fc719b941525";
 var S119= "fae59361ceb69cebc2a8645912baa8d1b6c1075ee3056a0c10d25065cb03a442";
 var S120= "e0ec6e0e1698db3b4c98a0be3278e9649f1f9532e0d392dfd3a0342b8971f21e";
 var S121= "1b0a74414ba3348cc5be7120c37632d8df359f8d9b992f2ee60b6f470fe3f11d";
 var S122= "e54cda541edad891ce6279cfcd3e7e6f1618b166fd2c1d05848fd2c5f6fb2299";
 var S123= "f523f357a632762393a8353156cccd02acf081625a75ebb56e16369788d273cc";
 var S124= "de96629281b949d04c50901b71c65614e6c6c7bd327a140a45e1d006c3f27b9a";
 var S125= "c9aa53fd62a80f00bb25bfe235bdd2f671126905b2040222b6cbcf7ccd769c2b";
 var S126= "53113ec01640e3d338abbd602547adf0ba38209cf746ce7677afa1c520756060";
 var S127= "85cbfe4e8ae88dd87aaaf9b04cf9aa7e1948c25c02fb8a8c01c36ae4d6ebe1f9";
 var S128= "90d4f869a65cdea03f09252dc208e69fb74e6132ce77e25b578fdfe33ac372e6";

 // load the array:

 g_PI_Arr = [];

 Str_To_PI_Arr(P1,0);
 Str_To_PI_Arr(P2,6);
 Str_To_PI_Arr(P3,12);

 Str_To_PI_Arr(S1,18);
 Str_To_PI_Arr(S2,26);
 Str_To_PI_Arr(S3,34);
 Str_To_PI_Arr(S4,42);
 Str_To_PI_Arr(S5,50);
 Str_To_PI_Arr(S6,58);
 Str_To_PI_Arr(S7,66);
 Str_To_PI_Arr(S8,74);
 Str_To_PI_Arr(S9,82);
 Str_To_PI_Arr(S10,90);
 Str_To_PI_Arr(S11,98);
 Str_To_PI_Arr(S12,106);

 Str_To_PI_Arr(S13,114);
 Str_To_PI_Arr(S14,122);
 Str_To_PI_Arr(S15,130);
 Str_To_PI_Arr(S16,138);
 Str_To_PI_Arr(S17,146);
 Str_To_PI_Arr(S18,154);
 Str_To_PI_Arr(S19,162);
 Str_To_PI_Arr(S20,170);
 Str_To_PI_Arr(S21,178);
 Str_To_PI_Arr(S22,186);
 Str_To_PI_Arr(S23,194);
 Str_To_PI_Arr(S24,202);

 Str_To_PI_Arr(S25,210);
 Str_To_PI_Arr(S26,218);
 Str_To_PI_Arr(S27,226);
 Str_To_PI_Arr(S28,234);
 Str_To_PI_Arr(S29,242);
 Str_To_PI_Arr(S30,250);
 Str_To_PI_Arr(S31,258);
 Str_To_PI_Arr(S32,266);
 Str_To_PI_Arr(S33,274);
 Str_To_PI_Arr(S34,282);
 Str_To_PI_Arr(S35,290);
 Str_To_PI_Arr(S36,298);

 Str_To_PI_Arr(S37,306);
 Str_To_PI_Arr(S38,314);
 Str_To_PI_Arr(S39,322);
 Str_To_PI_Arr(S40,330);
 Str_To_PI_Arr(S41,338);
 Str_To_PI_Arr(S42,346);
 Str_To_PI_Arr(S43,354);
 Str_To_PI_Arr(S44,362);
 Str_To_PI_Arr(S45,370);
 Str_To_PI_Arr(S46,378);
 Str_To_PI_Arr(S47,386);
 Str_To_PI_Arr(S48,394);

 Str_To_PI_Arr(S49,402);
 Str_To_PI_Arr(S50,410);
 Str_To_PI_Arr(S51,418);
 Str_To_PI_Arr(S52,426);
 Str_To_PI_Arr(S53,434);
 Str_To_PI_Arr(S54,442);
 Str_To_PI_Arr(S55,450);
 Str_To_PI_Arr(S56,458);
 Str_To_PI_Arr(S57,466);
 Str_To_PI_Arr(S58,474);
 Str_To_PI_Arr(S59,482);
 Str_To_PI_Arr(S60,490);

 Str_To_PI_Arr(S61,498);
 Str_To_PI_Arr(S62,506);
 Str_To_PI_Arr(S63,514);
 Str_To_PI_Arr(S64,522);
 Str_To_PI_Arr(S65,530);
 Str_To_PI_Arr(S66,538);
 Str_To_PI_Arr(S67,546);
 Str_To_PI_Arr(S68,554);
 Str_To_PI_Arr(S69,562);
 Str_To_PI_Arr(S70,570);
 Str_To_PI_Arr(S71,578);
 Str_To_PI_Arr(S72,586);

 Str_To_PI_Arr(S73,594);
 Str_To_PI_Arr(S74,602);
 Str_To_PI_Arr(S75,610);
 Str_To_PI_Arr(S76,618);
 Str_To_PI_Arr(S77,626);
 Str_To_PI_Arr(S78,634);
 Str_To_PI_Arr(S79,642);
 Str_To_PI_Arr(S80,650);
 Str_To_PI_Arr(S81,658);
 Str_To_PI_Arr(S82,666);
 Str_To_PI_Arr(S83,674);
 Str_To_PI_Arr(S84,682);

 Str_To_PI_Arr(S85,690);
 Str_To_PI_Arr(S86,698);
 Str_To_PI_Arr(S87,706);
 Str_To_PI_Arr(S88,714);
 Str_To_PI_Arr(S89,722);
 Str_To_PI_Arr(S90,730);
 Str_To_PI_Arr(S91,738);
 Str_To_PI_Arr(S92,746);
 Str_To_PI_Arr(S93,754);
 Str_To_PI_Arr(S94,762);
 Str_To_PI_Arr(S95,770);
 Str_To_PI_Arr(S96,778);

 Str_To_PI_Arr(S97,786);
 Str_To_PI_Arr(S98,794);
 Str_To_PI_Arr(S99,802);
 Str_To_PI_Arr(S100,810);
 Str_To_PI_Arr(S101,818);
 Str_To_PI_Arr(S102,826);
 Str_To_PI_Arr(S103,834);
 Str_To_PI_Arr(S104,842);
 Str_To_PI_Arr(S105,850);
 Str_To_PI_Arr(S106,858);
 Str_To_PI_Arr(S107,866);
 Str_To_PI_Arr(S108,874);

 Str_To_PI_Arr(S109,882);
 Str_To_PI_Arr(S110,890);
 Str_To_PI_Arr(S111,898);
 Str_To_PI_Arr(S112,906);
 Str_To_PI_Arr(S113,914);
 Str_To_PI_Arr(S114,922);
 Str_To_PI_Arr(S115,930);
 Str_To_PI_Arr(S116,938);
 Str_To_PI_Arr(S117,946);
 Str_To_PI_Arr(S118,954);
 Str_To_PI_Arr(S119,962);
 Str_To_PI_Arr(S120,970);

 Str_To_PI_Arr(S121,978);
 Str_To_PI_Arr(S122,986);
 Str_To_PI_Arr(S123,994);
 Str_To_PI_Arr(S124,1002);
 Str_To_PI_Arr(S125,1010);
 Str_To_PI_Arr(S126,1018);
 Str_To_PI_Arr(S127,1026);
 Str_To_PI_Arr(S128,1034);
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Str_To_PI_Arr(str,start_index)
{
 for(var i=0;i<str.length/8;i++)
 {
  var tstr = str.substr(8*i,8);
 
  g_PI_Arr[start_index] = parseInt(tstr,16) & 0xffffffff;

  start_index++;
 }
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function GenerateSubKeys()
{
 // init to PI

 Init_PI_Arr();

 // xor the key into the P array

 var i;

 for(i=0;i<18;i++)
 {
  g_PI_Arr[i] ^= g_Key_Arr[i];

  g_PI_Arr[i] &= 0xffffffff;
 }

 var data = [];

 data[0] = 0;
 data[1] = 0;

 // encrypt and replace:

 for(i=0;i<1042;i+=2)
 {
  data = Encrypt(data);
 
  g_PI_Arr[i] = data[0] & 0xffffffff;
  g_PI_Arr[i+1] = data[1] & 0xffffffff;
 }
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Encrypt(data)
{
 var xL = data[0];
 var xR = data[1];

 var tmp;

 for(var i=0;i<16;i++)
 {
  // xL = xL xor Pi

  xL ^= g_PI_Arr[i];

  // xR = F(xL) xor xR

  tmp = F_xL(xL);

  tmp ^= xR;

  xR = tmp;

  if(i==15) break;

  // swap xL and xR 

  tmp = xL;

  xL = xR;  

  xR = tmp;
 }

 // xR = xR xor P[17] 

 xR ^= g_PI_Arr[16];

 // xL = xL xor P[18]

 xL ^= g_PI_Arr[17];

 // return

 var tmp64 = [];

 tmp64[0] = (xL & 0xffffffff);

 tmp64[1] = (xR & 0xffffffff);

 return tmp64;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function F_xL(xL)
{
 // F(xL) = ((S1[a] + S2[b]) xor S3[c]) + S4[d]

 var a = (xL >>> 24) & 0xff;
 var b = (xL >>> 16) & 0xff;
 var c = (xL >>> 8) & 0xff;
 var d = xL & 0xff;

 var S1 = g_PI_Arr[18 + a];
 var S2 = g_PI_Arr[274 + b];
 var S3 = g_PI_Arr[530 + c];
 var S4 = g_PI_Arr[786 + d];

 var F = Add_32(S1,S2);

 F ^= S3;

 F = Add_32(F,S4);

 return F;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Hex_Encrypt()
{
 var input_arr = getMessage();

 var output_arr = [];

 var data = [];

 data[0] = 0;
 data[1] = 0;
 
 for(var i=0;i<input_arr.length;i+=2)
 {
  data[0] = input_arr[i];
  data[1] = input_arr[i+1];

  data = Encrypt(data);

  output_arr[i] = data[0];
  output_arr[i+1] = data[1];
 }

 var outstr = "Plain Text:\r\n\r\n";

 outstr += HexArrToStr(input_arr);

 outstr += "\r\n\r\nCipher Text:\r\n\r\n";

 outstr += HexArrToStr(output_arr);

 document.getElementById("input").value = outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function SetKey()
{ 
 // set the key and use it to generate the sub key array

 g_Key_Arr = [];

 g_Key_Arr = getKey();

 GenerateSubKeys();

 PrintKey();
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function ToHex()
{
 var tmpstr=document.getElementById("input").value;

 // convert a text string to a hexadecimal number string:

 if(tmpstr.length == 0)
 {
  document.getElementById("input").value = "Error - NULL input.";
 
  return;
 }

 var outstr = "";

 var i;

 for(i=0;i<tmpstr.length;i++)
 {
  var asc = tmpstr.charCodeAt(i);

  // no need to worry about leading zeros, hex values for
  // printable characters are >= 0x20:

  if(asc >= 32) outstr += asc.toString(16);
 }

 document.getElementById("input").value=outstr;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Add_32(x,y)
{
 // add x and y as 32 bit unsigned values:

 var tmp = (x>>>0) + (y>>>0);

 tmp &= 0xffffffff;

 return tmp;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function printWord(val)
{
 // print a 32 bit word (integer)

 // include leading zeros (if needed)

 var str = (val>>>0).toString(16);

 while(str.length < 8)
 {
  str = "0" + str;
 }

 return str;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function Clear()
{
 document.getElementById("input").value="";
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

function ShowInstructions()
{
 var msg = "Blowfish (Encrypt Only):\r\n\r\n";

 msg += "(1) Enter the key as a hex number and press [Set Key].\r\n";

 msg += "(2) Enter the message as a hex number and press [Encrypt].\r\n\r\n";

 msg += "To encrypt a text string, first press [ToHex] to convert to a hex number.\r\n\r\n";

 msg += "Press [SubKeys] to view the P array and S-Box arrays.\r\n";

 document.getElementById("input").value = msg;
}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

</script>

<body onload = "Init_PI_Arr()">

<input type="button" value="Encrypt" onClick="Hex_Encrypt()">
<input type="button" value="Set Key" onClick="SetKey()">
<input type="button" value="Sub Keys" onClick="Print_PI_Arr()">
<input type="button" value="To Hex" onClick="ToHex()">
<input type="button" value="Instructions" onClick="ShowInstructions()">
<input type="button" value="Clear" onClick="Clear()">

<br><br>

<textarea id="input" rows="24" cols="80" spellcheck="false"></textarea>

<pre>
<strong>
<span id="key_msg">Current Key Bits : None</span>
</strong>
</pre>

</body>

</html>
Advertisements

Create a free website or blog at WordPress.com.

%d bloggers like this: