RC5 block cipher implement in PHP and Javascript


In cryptography, RC5 is a symmetric-key block cipher notable for its simplicity. Designed by Ronald Rivest in 1994.

RC5 encryption and decryption both expand the random key into 2(r+1) words that will be used sequentially (and only once each) during the encryption and decryption processes. All of the below comes from Rivest’s revised paper on RC5.

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

We provide some function in PHP and Javascript.

PHP

The implementation is designed to work with w = 32, r = 12, and b = 16. It means that block size is 8 bytes ( 2×32 bits ) and key size is 16 bytes ( 128 bits ).

<?php

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

class RC5{
    public static $S = array();
    public static $r = 12;
    public static $w = 32;
    
    private static function cyclicShiftLeft($array, $positions)
    {
        $temp = array_slice($array, 0, $positions);
        $temp = array_merge(array_slice($array, $positions), $temp);
        return $temp;
    }
    
    private static function ROTL($v,$n,$m=32) {
        $y = sprintf("%0".$m."b",$v);
        $r = str_split($y);
        $r = self::cyclicShiftLeft($r,$n);
        return bindec(implode("",$r)) ;
    }
    
    private static function ROTR($v,$n,$m=32){
        return self::ROTL($v,$m-$n,$m);
    } 
    
    /* Key scheduling */
    public static function rc5_init($K)
    {
       $b = 16;
       $u = self::$w/8;
       $c = max(1, ceil($b/$u));
       $t = 2 * (self::$r+1);
       $L = array();
       $P = 0xb7e15163;
       $Q = 0x9e3779b9;
       
       for($i = 0; $i < $b; $i++)
          $L[$i] = 0;
       
       for($i = $b-1, $L[$c-1] = 0; $i != -1; $i--)
          $L[$i/$u] = ($L[$i/$u] << 8) + $K[$i];
       
       for(self::$S[0] = $P, $i = 1; $i < $t; $i++)
          self::$S[$i] = self::$S[$i-1] + $Q;
         
       $n = max($t,$c);
       
       for($A = $B = $i = $j = $k = 0; $k < 3 * $n; $k++, $i = ($i+1) % $t, $j = ($j+1) % $c)
       {   
          $A = self::$S[$i] = self::ROTL(self::$S[$i] + ($A + $B), 3, self::$w);
          $B = $L[$j] = self::ROTL($L[$j] + ($A + $B), ($A + $B)&(self::$w-1), self::$w);
       }
       
    }
    public static function rc5_encrypt($pt)
    {
       $A = $pt[0] + self::$S[0]; $B = $pt[1] + self::$S[1];
       
       for($i = 1; $i <= self::$r; $i++)
       {
          $A = self::ROTL($A ^ $B, $B&(self::$w-1), self::$w) + self::$S[2*$i];
          $B = self::ROTL($B ^ $A, $A&(self::$w-1), self::$w) + self::$S[2*$i + 1];           
       }
       return array($A & (pow(2,self::$w)-1), $B & (pow(2,self::$w)-1));
    }
    
    public static function rc5_decrypt($ct)
    {
       $B=$ct[1]; $A=$ct[0];
       
       for($i = self::$r; $i > 0; $i--)
       {
          $B = self::ROTR($B - self::$S[2*$i + 1], $A&(self::$w-1), self::$w) ^ $A;
          $A = self::ROTR($A - self::$S[2*$i], $B&(self::$w-1), self::$w) ^ $B;           
       }
       
       return array(($A - self::$S[0]) & (pow(2,self::$w)-1), ($B - self::$S[1]) & (pow(2,self::$w)-1));
    }
}

?>

Example:

        RC5::rc5_init(array(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15));
        $enc = (RC5::rc5_encrypt( array(65,65) )); 
        $dec = (RC5::rc5_decrypt( $enc )); 
        var_dump($enc,$dec);

Result:

array(2) {
  [0]=>
  int(1927580246)
  [1]=>
  int(-516086777)
}
array(2) {
  [0]=>
  int(65)
  [1]=>
  int(65)
}

Javascript

var RC5={
    S : [],
    r : 12,
    w : 32,
    cyclicShiftLeft: function (array, positions)
    { 
        var temp = array.slice(0, positions);
        temp = array.slice(positions).concat(temp);
        return temp;
    },     
    ROTL: function (v,n,m) { 
        y = (v>=0?v:-1-v).toString(2); 
        z = y.length;
        if(z < m) y = ("0".repeat(m-z))+y;
        r = y.split("");
        if(r.length>m) r = r.slice(r.length-m);
        if(v<0) r = r.map(function(h){return h=="1"?"0":"1"})
        r = this.cyclicShiftLeft(r,n);  
        return parseInt(r.join(""),2) ;         
    },     
    ROTR: function (v,n,m){
        return this.ROTL(v,m-n,m);
    } ,     
    /* Key scheduling */
    rc5_init: function (K)
    {
       var b = 16,
       u = this.w/8,
       c = Math.max(1, Math.ceil(b/u)),
       t = 2 * (this.r+1),
       L = [],
       P = 0xb7e15163,
       Q = 0x9e3779b9,i,j,k;
        
       for(i = 0; i < b; i++)
          L[i] = 0;
        
       for(i = b-1, L[c-1] = 0; i != -1; i--)
          L[Math.floor(i/u)] = (L[Math.floor(i/u)] << 8) + K[i];
          
       for(this.S[0] = P, i = 1; i < t; i++)
          this.S[i] = this.S[i-1] + Q;
          
       var n = Math.max(t,c);
       
       for(A = B = i = j = k = 0; k < 3 * n; k++, i = (i+1) % t, j = (j+1) % c)
       {    
          A = this.S[i] = this.ROTL(this.S[i] + (A + B), 3, this.w);  
          B = L[j] = this.ROTL(L[j] + (A + B), (A + B)&(this.w-1), this.w); 
       }
    },
    rc5_encrypt: function (pt)
    {
    	 var A,B,i;
       A = pt[0] + this.S[0]; B = pt[1] + this.S[1];
       for(i = 1; i <= this.r; i++)
       {
          A = this.ROTL(A ^ B, B&(this.w-1), this.w) + this.S[2*i];
          B = this.ROTL(B ^ A, A&(this.w-1), this.w) + this.S[2*i + 1];                   
       }
       return [A & (Math.pow(2,this.w)-1), B & (Math.pow(2,this.w)-1)];
    },
     
    rc5_decrypt: function (ct)
    {
       var A,B,i;
       B=ct[1]; A=ct[0];        
       for(i = this.r; i > 0; i--)
       {
          B = this.ROTR(B - this.S[2*i + 1], A&(this.w-1), this.w) ^ A;          
          A = this.ROTR(A - this.S[2*i], B&(this.w-1), this.w) ^ B; 
       }        
       return [(A - this.S[0]) & (Math.pow(2,this.w)-1), (B - this.S[1]) & (Math.pow(2,this.w)-1)];
    }
}

Example:

        RC5.rc5_init([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
        enc = (RC5.rc5_encrypt( [65,65] )); 
        dec = (RC5.rc5_decrypt( enc )); 
        console.log(enc,dec);

Result:

[1927580246, -516086777] [65, 65]

Try it yourself

Part 2: RC5 block cipher implement in PHP and Javascript – part 2

1 Comment

Leave a Reply