TEA block cipher implement in PHP and Javascript


In cryptography, the Tiny Encryption Algorithm (TEA) is a block cipher notable for its simplicity of description and implementation, typically a few lines of code. It was designed by David Wheeler and Roger Needham of the Cambridge Computer Laboratory; it was first presented at the Fast Software Encryption workshop in Leuven in 1994, and first published in the proceedings of that workshop.

TEA operates on two 32-bit unsigned integers (could be derived from a 64-bit data block) and uses a 128-bit key. It has a Feistel structure with a suggested 64 rounds, typically implemented in pairs termed cycles.

Source: https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm

We provide some function in PHP and Javascript

PHP

<?php

/**
 * @author www.Tutorialspots.com
 * @copyright 2017
 */

class TEA{
    /**
     * TEA encrypt
     * @param $v 64bits
     * @param $k 128bits
     */
    public static function TEAencrypt ($v, $k) {
        $v0=$v[0]; $v1=$v[1]; $sum=0;           /* set up */
        $delta=0x9e3779b9;                     /* a key schedule constant */
        $k0=$k[0]; $k1=$k[1]; $k2=$k[2]; $k3=$k[3];   /* cache key */
        for ($i=0; $i < 32; $i++) {                       /* basic cycle start */
            $sum += $delta;
            $v0 += (($v1<<4) + $k0) ^ ($v1 + $sum) ^ (($v1>>5) + $k1);
            $v1 += (($v0<<4) + $k2) ^ ($v0 + $sum) ^ (($v0>>5) + $k3);
        }                                              /* end cycle */
        $v[0]=$v0; $v[1]=$v1;
        return $v;
    }
    
    /**
     * TEA decrypt
     * @param $v 64bits
     * @param $k 128bits
     */
    public static function TEAdecrypt ($v, $k) {
        $v0=$v[0]; $v1=$v[1]; $sum=0xC6EF3720;  /* set up */
        $delta=0x9e3779b9;                     /* a key schedule constant */
        $k0=$k[0]; $k1=$k[1]; $k2=$k[2]; $k3=$k[3];   /* cache key */
        for ($i=0; $i<32; $i++) {                         /* basic cycle start */
            $v1 -= (($v0<<4) + $k2) ^ ($v0 + $sum) ^ (($v0>>5) + $k3);
            $v0 -= (($v1<<4) + $k0) ^ ($v1 + $sum) ^ (($v1>>5) + $k1);
            $sum -= $delta;
        }                                              /* end cycle */
        $v[0]=$v0; $v[1]=$v1;
        return $v;
    }
}

?>

Javascript:

var TEA = {};
   /**
     * TEA encrypt
     * @param v 64bits
     * @param k 128bits
     */
TEA.TEAencrypt = function (v, k) {
  var v0=v[0], v1=v[1], sum=0,           /* set up */
  delta=0x9e3779b9,                     /* a key schedule constant */
  k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
  for (var i=0; i < 32; i++) {                       /* basic cycle start */
    sum += delta;
    v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
    v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
  }                                              /* end cycle */
  v[0]=v0; v[1]=v1;
  return v;
}

   /**
     * TEA decrypt
     * @param v 64bits
     * @param k 128bits
     */
TEA.TEAdecrypt = function (v, k) {
  var v0=v[0], v1=v[1], sum=0xC6EF3720,  /* set up */
  delta=0x9e3779b9,                     /* a key schedule constant */
  k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
  for (var i=0; i<32; i++) {                         /* basic cycle start */
    v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
    v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
    sum -= delta;
  }                                              /* end cycle */
  v[0]=v0; v[1]=v1;
  return v;
}
var x=TEA.TEAencrypt([65,65],[65,65,65,65]);
console.log(x);//[-3257293243,6661612959]
alert(TEA.TEAdecrypt(x,[65,65,65,65]));

Example:

var x=TEA.TEAencrypt([65,65],[65,65,65,65]);
console.log(x);
alert(TEA.TEAdecrypt(x,[65,65,65,65]));

Result:

[-3257293243,6661612959]
[65,65]

Try it yourself

Application of this block cipher method for stream cipher:
There are many methods, but we can provide the method below:
Split your string into many block with 64 bits (8 characters), then use this block cipher method. We can use the method Null-padding for the case the string length is odd.
The key must have 16 characters (128 bits), so, we must use one Key-scheduling algorithm (KSA) to convert the key to the new key 128 bits.

PHP:

    //TEA NULL padding
    private static function _nullpadding($str){
        if(strlen($str)%8 != 0){
            $str .= str_repeat(chr(0),8-strlen($str)%8);
        }
        return $str;
    }
    
    //TEA Key-scheduling algorithm (KSA)
    private static function TEAKSA($key){
        for ($s = array(), $i = 0; $i < 256; $i++)
            $s[$i] = $i;
        for ($j = 0, $i = 0; $i < 256; $i++)
        {
            $j = ($j + $s[$i] + ord($key[$i % strlen($key)])) % 256;
            $x = $s[$i];
            $s[$i] = $s[$j];
            $s[$j] = $x;
        }
        //return array_slice($s,0,16);
        $expanded = array();
        $i = 0;
        while ($i < 64)
        {
            $expanded[$i] = $s[4 * $i];
            for($j=1;$j<4;$j++)
                $expanded[$i] = $expanded[$i] | $s[4 * $i + $j] << (8*$j);
            $i++;
        }
        return $expanded;
    }
    
    // convert 32bits interger to 4characters string
    private static function _32bits2str($block){
        return pack('N',$block & 0xffffffff);
    }
    // convert 4characters string to 32bits interger
    private static function _str232bits($block){
        return unpack('N*',$block)[1];
    }
    
    //Stream cipher encrypt use TEA
    public static function TEAenc($str,$key,$mode='ECB'){
        $str = self::_nullpadding($str);//var_dump($str);die();
        $enc = '';
        $k = self::TEAKSA($key); //var_dump($k);die();
        for($i=0;$i<strlen($str)/8;$i++){
            $block = substr($str,$i*8,8);
            $chr = array(self::_str232bits(substr($block,0,4)),self::_str232bits(substr($block,4,4)));  
            $e = self::TEAencrypt($chr,$k);
            $enc .= self::_32bits2str($e[0]).self::_32bits2str($e[1]);
        }
        return $enc;
    }
    
    //Stream cipher decrypt use TEA
    public static function TEAdec($str,$key,$mode='ECB'){
        $enc = '';
        $k = self::TEAKSA($key);//var_dump($k);die();
        for($i=0;$i<strlen($str)/8;$i++){
            $block = substr($str,$i*8,8);
            $chr = array(self::_str232bits(substr($block,0,4)),self::_str232bits(substr($block,4,4))); 
            $e = self::TEAdecrypt($chr,$k);
            $enc .= self::_32bits2str($e[0]).self::_32bits2str($e[1]);
        }
        return rtrim($enc,chr(0));
    }

Here, we use ECB mode, you can use CBC, PCBC, CFB, OFB, CTR mode.

Javascript:

//TEA NULL padding
    _nullpadding: function(str){
        if(str.length % 8 != 0){
            str += "\x00".repeat(8-str.length%8);
        }
        return str;
    },
    
    //TEA Key-scheduling algorithm (KSA)
    TEAKSA: function (key){
        var s=[],i,j,x,expanded = [];
        for (i = 0; i < 256; i++)
            s[i] = i;
        for (j = 0, i = 0; i < 256; i++)
        {
            j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
            x = s[i];
            s[i] = s[j];
            s[j] = x;
        }
        i = 0;
        while (i < 64)
        {
            expanded[i] = s[4* i];
            for(j=1;j<4;j++)
                expanded[i] = expanded[i] | s[4* i + j] << (8*j);
            i++;
        }
        return expanded;
    },
    
    // convert 32bits interger to 4characters string
    _32bits2str: function (block){
        return String.fromCharCode(block >> 24) +
        	     String.fromCharCode(block >> 16 & 255) +
               String.fromCharCode(block >> 8 & 255) +
               String.fromCharCode(block & 255);
    },
    // convert 4characters string to 32bits interger
    _str232bits: function (block){
        return block.charCodeAt(3) | block.charCodeAt(2) << 8 | block.charCodeAt(1) << 16 | block.charCodeAt(0) << 24;
    },
    
    //Stream cipher encrypt use TEA
    TEAenc: function (str,key,mode='ECB'){
        var block,e;
        str = this._nullpadding(str); 
        enc = '';
        k = this.TEAKSA(key);  
        for(i=0;i<str.length/8;i++){
            block = str.substr(i*8,8);
            chr = [this._str232bits(block.substr(0,4)),this._str232bits(block.substr(4,4))];  
            e = this.TEAencrypt(chr,k);
            enc += this._32bits2str(e[0])+this._32bits2str(e[1]);
        }
        return enc;
    },
    
    //Stream cipher decrypt use TEA
    TEAdec: function (str,key,mode='ECB'){
        var block,e;
        enc = '';
        k = this.TEAKSA(key); 
        for(i=0;i<str.length/8;i++){
            block = str.substr(i*8,8);
            chr = [this._str232bits(block.substr(0,4)),this._str232bits(block.substr(4,4))];
            e = this.TEAdecrypt(chr,k);
            enc += this._32bits2str(e[0])+this._32bits2str(e[1]);
        }
        return enc.replace(/(\\x00)+$/,"");
    }

Example:

console.log(TEA.TEAenc("abc","abc"));
console.log(TEA.TEAdec(TEA.TEAenc("abc","abc"),"abc"));

Try it yourself

Read more:
Test vectors TEA
XTEA block cipher implement in PHP and Javascript
XXTEA block cipher implement in PHP and Javascript

3 Comments

Leave a Reply