Encryption vs Hashing

In hashing, a code is computed from data in such a way that it is exceedingly difficult for anyone to find data that produces the same code. Agents exchange the code for verification over an unreliable network (such as internet). For instance, in a user authentication situation the server may issue a challenge (a random number). The client obtains the password and transmits the hash of the challenge and the password, which the server compares to its hash of that data. Well known algorithms are SHA1, MD4 and MD5.

Background information and JavaScript implementations of SHA1, MD4, MD5 and RSA can be found in Paul Johnston's excellent website on cryptography. Modern PHP implementations (as of 4.3) have SHA1 and MD5 algorithms built-in.

In encryption, a code is computed from data using a key in such a way that it is difficult for anyone to find the data without having the key. If one has the key, the original data can be easily obtained from the code. Agents exchange data over an unreliable network by encrypting it. In asymmetric encryption different keys are used for en/de-cryption. For example, PGP uses a public encryption key with a private decryption key, based on the RSA algorithm. In symmetric encryption the same key is used either way, so the agents must share a secret. A fast encryption algorithm with a footprint suitable for web programming is the Tiny Encryption Algorithm (TEA) by Wheeler & Needham.

Simon Shepherd maintains an <a href="http://www.simonshepherd.supanet.com/tea.htm">extensive website on TEA with a number of implementations in C and various assemblers. Unfortunately the JavaScript implementations shown there (October 15, 2006) are flawed. An explanation is here. Note that the algorithms below are most likely suboptimal; they are adaptations of an algorithgm suitable for 32-bit arithmetic.

Two encryption/decryption algorithms based on TEA

Function cryptN en/decrypts a string of characters (of which the lower 8 bits are used) using a 16-character key. Argument 3 is true for encryption, false for the reverse. Argument 4 defines the number of iterations, which define a level of security (32: tight, 16: reasonable and 8: superficial). Functions hexify and dehexify convert a string of characters, using 8 significant bits, to and from hexadecimal representation, for instance for embedding in XML, in a HTTP request. This code is distributed under the Mozilla Public License Version 1.1, which (briefly) grants right to use and distribute this code royalty-free.

JavaScript

/*********************************************************************\
Based on TEA (2nd variant),http://www.simonshepherd.supanet.com/tea.htm

crypt en-/de-crypts a string (1st arg) using a key (2nd arg) of
length 16 with 16 iterations (a 4th argument may be given to use
another number of iterations (8 is superficial, 16 is often adequate,
32 is hard)). Arg 3 is true for encryption, false for decryption. Key
is taken to contain byte characters (0x01-0xFF); subject sstring may
contain wider characters but only each lower byte is used.

The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http:#www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Bloom, a rule-based development framework for
web applications. The Initial Developer of the Original Code is
Babelfish, Hilversum, The Netherlands.
All Rights Reserved.
\*********************************************************************/

    function cryptN(str,key,encrypt,itr) {
       res="";
       while (str.length>8) {
          res += crypt8(str.substr(0,8),key,encrypt,itr);
          str = str.substr(8);
       }
       if (str.length>0) {
          while (str.length<8) {
         str += ' ';
          }
          res += crypt8(str,key,encrypt,itr);
       }
       while (res.substring(res.length-1,res.length) == ' ') {
          res = res.substring(0,res.length-1);
       }
       return res;
    }

    //Four-byte truncate
    function fbt(x) {
       x = x&0x0FFFFFFFF;
       return x<0?0x0100000000+x:x;
    }

    //crypt8 en/decrypts a string of length 8
    function crypt8(oct,key,encrypt,itr) {
       var y=new Number(0); var z=0; var k=[]; k[0]=k[1]=k[2]=k[3]=0;
       var d=0x9E3779B9; var sum=encrypt?0:d*itr;
       var res="";
       for (var i=0; i<8; ) {
          y=fbt((y<<8)+(oct.charCodeAt(i)&0xFF));
          k[i&3]=fbt((k[i&3]<<8)+key.charCodeAt(i));
          k[i&3]=fbt((k[i&3]<<8)+key.charCodeAt(i+8));
          i++;
          z=fbt((z<<8)+(oct.charCodeAt(i)&0xFF));
          k[i&3]=fbt((k[i&3]<<8)+key.charCodeAt(i));
          k[i&3]=fbt((k[i&3]<<8)+key.charCodeAt(i+8));
          i++;
       }
       if (encrypt) {
          while (itr-->0) {
         y = fbt(y+fbt((z*16)^Math.floor(z/32))+fbt(z^sum)+k[sum&3]);
         sum += d;
         z = fbt(z+fbt((y*16)^Math.floor(y/32))+fbt(y^sum)+k[(sum>>11)&3]);
          }
       } else {
          while (itr-->0) {
         z = fbt(z-fbt(fbt((y*16)^Math.floor(y/32))+fbt(y^sum)+k[(sum>>11)&3]));
         sum -= d;
         y = fbt(y-fbt(fbt((z*16)^Math.floor(z/32))+fbt(z^sum)+k[sum&3]));
          }
       }
       for (var i=4; i-->0; ) {
          res += String.fromCharCode(fbt((y&0xFF000000)>>24));
          y = y<<8;
          res += String.fromCharCode(fbt((z&0xFF000000)>>24));
          z=z<<8;
       }
       return res;
    }

    function hexify(oct) {
       var res="";
       for (var i=0; i<oct.length; ) {
          var b = oct.charCodeAt(i++);
          res+='0123456789ABCDEF'.charAt(b>>4&0xF);
          res+='0123456789ABCDEF'.charAt(b&0xF);
       }
       return res;
    }

    function dehexify(hex) {//assumes even number of hex digits
       var res="";
       for (var i=0; i<hex.length; ) {
          var b = hex.charCodeAt(i++);
          var c = hex.charCodeAt(i++);
          res += String.fromCharCode(((b-(b>64?55:48))<<4)+c-(c>64?55:48));
       }
       return res;
    }

PHP

/*********************************************************************\
Based on TEA (2nd variant),http://www.simonshepherd.supanet.com/tea.htm

crypt en- and decrypts a string (1st arg) using a key (2nd arg) of
length 16 with 16 iterations (a 4th argument may be given to use
another number of iterations (8 is superficial, 16 is often adequate,
32 is hard)). Arg 3 is true for encryption, false for decryption. Key
is taken to contain byte characters (0x01-0xFF); subject sstring may
contain wider characters but only each lower byte is used.

The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http:#www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Bloom, a rule-based development framework for
web applications. The Initial Developer of the Original Code is
Babelfish, Hilversum, The Netherlands.
All Rights Reserved.

Syntax coloring by dreamprojections.com/SyntaxHighlighter/
\*********************************************************************/

function cryptN($str,$key,$encrypt,$itr) {
   $res="";
   while (strlen($str)>8) {
      $res .= crypt8(substr($str,0,8),$key,$encrypt,$itr);
      $str = substr($str,8);
   }
   if (strlen($str)>0) {
      while (strlen($str)<8) {
     $str .= ' ';
      }
      $res .= crypt8($str,$key,$encrypt,$itr);
   }
   return rtrim($res,' ');
}
function crypt8($oct,$key,$encrypt,$itr) {
   $y=0; $z=0; $k=array(); $k[0]=$k[1]=$k[2]=$k[3]=0;
   $d=0x9E3779B9; $sum=$encrypt?0:($d*$itr)&0x0ffffffff;
   $res="";
   for ($i=0; $i<8; ) {
      $y=($y<<8)+(ord($oct{$i})&0xFF);
      $k[$i&3]=($k[$i&3]<<8)+ord($key{$i});
      $k[$i&3]=($k[$i&3]<<8)+ord($key{$i+8});
      $i++;
      $z=($z<<8)+(ord($oct{$i})&0xFF);
      $k[$i&3]=($k[$i&3]<<8)+ord($key{$i});
      $k[$i&3]=($k[$i&3]<<8)+ord($key{$i+8});
      $i++;
   }
   if ($encrypt) {
      while ($itr-->0) {
     $y = ($y+(($z<<4)^($z>>5))+($z^$sum)+$k[$sum&3])&0x0ffffffff;
     $sum=$sum+$d;
     $z = ($z+(($y<<4)^($y>>5))+($y^$sum)+$k[($sum>>11)&3])&0x0ffffffff;
      }
   } else {
      while ($itr-->0) {
     $z = ($z+0x0100000000-(((($y<<4)^($y>>5))+($y^$sum)+$k[($sum>>11)&3])&0x0ffffffff))&0x0ffffffff;
     $sum=($sum+0x0100000000-$d)&0x0ffffffff;
     $y = ($y+0x0100000000-(((($z<<4)^($z>>5))+($z^$sum)+$k[$sum&3])&0x0ffffffff))&0x0ffffffff;
      }
   }
   for ($i=4; $i-->0; ) {
      $res .= chr(($y&0xFF000000)>>24);
      $y = $y<<8;
      $res .= chr(($z&0xFF000000)>>24);
      $z=$z<<8;
   }
   return $res;
}

function hexify($oct) {
   $res="";
   $hexDig = "0123456789ABCDEF";
   for ($i=0; $i<strlen($oct);) {
      $b = ord($oct{$i++});
      $c = $b&0x0F;
      $b = $b>>4;
      $res .= $hexDig{$b} . $hexDig{$c} ;
   }
   return $res;
}

function dehexify($hex) {//assumes even number of hex digits
   $res="";
   for ($i=0; $i<strlen($hex); ) {
      $b = hexdec($hex{$i++}.$hex{$i++});
      $res .= chr($b);
   }
   return $res;
}

Next Post Previous Post