Encryption class

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
User avatar
neel_basu
Forum Contributor
Posts: 454
Joined: Wed Dec 06, 2006 9:33 am
Location: Picnic Garden, Kolkata, India

Encryption class

Post by neel_basu »

Hi! all if you dont have mCrypt you can use this Encryption class
(based on XOR Encryption)
Plese post if you find any bugs.

Code: Select all

class crytpo{
/*
Encryptor Class without mcrypt
Author Neel basu
This is a Pre release beta of Zogmoyd's next version's Level 1 Encryption Class
Made on july 15 2007. Its Under GPL Licence
Please see GNU GPL before using it. 
you can Use it Untill the above message is intact.
*/
private $val;
public function __construct(){
	if(!defined('BLOCK_SIZE')){define('BLOCK_SIZE', 4);}
	if(!defined('BLOCK_JUNK')){define('BLOCK_JUNK', 5);}
	if(!defined('ENC_BIN')){define('ENC_BIN', true);}
	if(!defined('ENC_DEC')){define('ENC_DEC', false);}
	$this->val = array(' ', '+', '_', '*', '&', ':', '-', '@', '=', '%');
}
private function blockise($str){
	if(strlen($str) >= BLOCK_SIZE*2){return $str;}
	while(strlen($str) < BLOCK_SIZE*2){
		$str .= chr(BLOCK_JUNK);
	}
	return $str;
}
private function dblockise($str){
	for($i=strlen($str)-1;$i>=strlen($str)-1-8;$i--){
		if($str[$i] != chr(BLOCK_JUNK)){break;}
		$str = substr($str, 0, $i);
	}
	return $str;
}
private function psubstr($str, $start, $len){
	if($start < 0){$tmp = "";return $tmp;};
	return substr($str, $start, $len);
}
private function get_block($str, $i){return $this->psubstr($str, $i, BLOCK_SIZE);}
private function x_enc($string, $key){
  for($i=0; $i<=strlen($string)-1; $i++){
    for($j=0; $j<=strlen($key)-1; $j++){
      $string[$i] = $string[$i]^$key[$j];
    }
		if($i != 0 && $i != strlen($string)-1){
			$string[$i] = $string[$i]^$string[$i-1]^$string[$i+1];
		}
  }
 return $string;
}
private function x_dcd($string, $key){
	  for($i=strlen($string)-1; $i>=0; $i--){
		  if($i == 0 || $i == strlen($string)-1){
		    for($j=0; $j<=strlen($key)-1; $j++){
		      $string[$i] = $string[$i]^$key[$j];
		    }
		  }else{
		  	$string[$i] = $this->x_enc($string[$i], $key)^$string[$i-1]^$string[$i+1];
		  }
	 }
	return $string;
}
private function enc($str, $key){
	$str = base64_encode($this->blockise($str));
	for($i=0;$i<=strlen($str)-1;$i+=BLOCK_SIZE){
		if($i == 0 || $i == (strlen($str)-BLOCK_SIZE)){
			$repl = $this->x_enc($this->psubstr($str, $i, BLOCK_SIZE), $key);
			$str = substr_replace($str, $repl, $i, BLOCK_SIZE);
		}else{
			if($i == BLOCK_SIZE){
				$b = $this->x_enc($this->get_block($str, $i), $key);
			}
			$repl = $this->x_enc($this->get_block($str, $i+BLOCK_SIZE), $this->get_block($str, $i-BLOCK_SIZE));
			$str = substr_replace($str, $repl, $i, BLOCK_SIZE);
		}
	}
	$str .= $b;
	return $str;
}
private function dcd($str, $key){
	$b = $this->x_dcd($this->get_block($str, strlen($str)-BLOCK_SIZE), $key);
	$str = substr($str, 0, strlen($str)-BLOCK_SIZE);
	for($i=strlen($str)-BLOCK_SIZE;$i>=0;$i-=BLOCK_SIZE){
		if($i == 0 || $i == (strlen($str)-BLOCK_SIZE)){
			$repl = $this->x_dcd($this->psubstr($str, $i, BLOCK_SIZE), $key);
			$str = substr_replace($str, $repl, $i, BLOCK_SIZE);
		}else{
			if($i == BLOCK_SIZE){
				$str = substr_replace($str, $b, $i, BLOCK_SIZE);
			}else{
				$repl = $this->x_dcd($this->psubstr($str, $i-BLOCK_SIZE, BLOCK_SIZE), $this->psubstr($str, $i-(BLOCK_SIZE*2), BLOCK_SIZE));
				$str = substr_replace($str, $repl, $i, BLOCK_SIZE);
			}
		}
	}
	return $this->dblockise(base64_decode($str));
}
public function encode($str, $key, $mode = ENC_BIN){
	if($mode == ENC_BIN){
		return $this->enc($this->enc($str, $key), md5($key));
	}elseif($mode == ENC_DEC){
		return $this->dec_encode($this->enc($this->enc($str, $key), md5($key)));
	}
	trigger_error("Invalid MODE SPecified", E_ERROR);
	return false;
}
public function decode($str, $key, $mode = ENC_BIN){
	if($mode == ENC_BIN){
		return $this->dcd($this->dcd($str, md5($key)), $key);
	}elseif($mode == ENC_DEC){
		return $this->dcd($this->dcd($this->dec_decode($str), md5($key)),$key);
	}
	trigger_error("Invalid MODE SPecified", E_ERROR);
	return false;
}
private function dec_decode($salted){
		$key = array(0,1,2,3,4,5,6,7,8,9);$ret = '';
    $val = $this->val;
    $str = str_replace($val, $key, $salted);
    for($i=0;$i<=strlen($str)-1;$i+=3){
  		$current_group = $str[$i].$str[$i+1].$str[$i+2];
  		$tmp_int = (int)($current_group);
  		$ret .= chr($tmp_int);
  	}
    return base64_decode($ret);
	}
private function dec_encode($salt){
		$str = base64_encode($salt);$tmp = '';
	  for($i=0;$i<=strlen($str)-1;$i++){
      if(ord($str[$i]) < 100){
        if(ord($str[$i]) > 0 && ord($str[$i]) < 10){
          $num = "00".ord($str[$i]);
        }
        elseif(ord($str[$i]) >= 10 && ord($str[$i]) < 100){
          $num = "0".ord($str[$i]);
        }
      }
      else{
        $num = ord($str[$i]);
      }
      $tmp .= $num;
    }
   $key = array(0,1,2,3,4,5,6,7,8,9);
   $val = $this->val;
   $ret = str_replace($key, $val, $tmp);
   return $ret;
	}
}
------------------------- USAGE ----------------------------------

Code: Select all

<?php
$str = "1111111111111111111111111111111";
$key = "neel";
$crypto = new crytpo();
$e = $crypto->encode($str, $key);
echo "Encrypted \t[".$e."] Length \t".strlen($e)."\n\n";
$d = $crypto->decode($e, $key);
flush();//This is not needed at all.
echo "Decrypted \t[".$d."] Length ".strlen($d)."\n";
?>
Output wrote:Encrypted [
P5q#Qqn_<1gvOkqno4QrjztwFeQ
*T)
bQQvi:j2<] Length 68

Decrypted [1111111111111111111111111111111] Length 31

Code: Select all

<?php
$str = "1111111111111111111111111111111";
$key = "neel";
$crypto = new crytpo();
$e = $crypto->encode($str, $key, ENC_DEC);
echo "Encrypted \t[".$e."] Length \t".strlen($e)."\n\n";
$d = $crypto->decode($e, $key, ENC_DEC);
flush();//This is not needed at all.
echo "Decrypted \t[".$d."] Length ".strlen($d)."\n";
?>
Output wrote:Encrypted [ -@+_ &% =+ @= =_ @* =% %% =* @@ -: =: == @ ++@ @_ --++-+ _ = -: %%+_ -=++%+ ++ @++ &+_ : =& : ++-+_ %=+ % :-+ @= @ @ +_+ %@++ ++_ &=+ +_ + * =: =_+ % =- =_ @ -:++- :* %=++ @& % %%+ @ =%++* =- -: @@ @: @: =_++_+ : =: =_ @@ @@ -- &% @ : %@ =&++_++* @@+ -++% -+] Length 276

Decrypted [1111111111111111111111111111111] Length 31
ENC_DEC is an optional argument that again encrypts the encrypted string with 10 characters

Code: Select all

$this->val = array(' ', '+', '_', '*', '&', ':', '-', '@', '=', '%');
near line 15 . You can change these characters to customize it.
------------------------------ SECURITY --------------------------------------
See here we are encrypting 1111111111111111111111111111 a repetative character string
But see the encrypted String there is no repetation
If you use ENC_DEC the hacker will need to know 11 things
the keyword and that 10 Characters
Thats hardly possible.
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Post by Mordred »

You broke the first rule for writing home-brew encryption code: Don't.

Encryption is a serious matter, which should be studied long before starting to design and implement algorythms. I haven't studied it even remotely as long as required, but even so can spot problems with your encryption scheme. Moreover your code is written badly, is grossly inefficient and is severely undocumented (which is quite important if you want other people to understand and follow and check your code).

I won't discuss the PHP errors, you're not new to PHP and I'm sure you can read the docs for yourself. The "encryption" though is bad.
First, it has key strength of about 14 bits (theoretical maximum, would be less in real situations) - ~6 bits for the md5 of the key and 8 bits from the key itself, which means bruteforcing is possible in less than 16384 tries. Also, actually only the first and the last chars in a block are encrypted with the key. Which leads to the third problem that if we have a known plaintext in the beginning or the end of a block (quite possible having in mind the low size of the blocks) we can probably recover the unknown bits and decrypt right away.

I'm sorry for the harsh words, but I think you should throw this away, read some books on the subject and start again from scratch, preferably by implementing a known and proven algorythm.
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

Code: Select all

return $this->enc($this->enc($str, $key), md5($key));
Read the article on security [viewtopic.php?t=62782] and why double hashing things is bad practice.
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Post by Mordred »

@TheMoose: He's not double-hashing, he's double encrypting. Since his algorythm is flawed and uses only 8 bits from the provided key, double encrypting using the MD5 of the key actually "improves" the security, as it also adds ~6 bits for the MD5(key).
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

Mordred wrote:@TheMoose: He's not double-hashing, he's double encrypting. Since his algorythm is flawed and uses only 8 bits from the provided key, double encrypting using the MD5 of the key actually "improves" the security, as it also adds ~6 bits for the MD5(key).
Yeah I just skimmed to see what I could find quickly, I didn't look at the formula behind the encryption portion itself.
User avatar
neel_basu
Forum Contributor
Posts: 454
Joined: Wed Dec 06, 2006 9:33 am
Location: Picnic Garden, Kolkata, India

Post by neel_basu »

Mordred wrote:which means bruteforcing is possible in less than 16384 tries
No You left out this line

Code: Select all

$this->enc($this->enc($str, $key), md5($key));
in your calculation.
Mordred wrote:@TheMoose: He's not double-hashing, he's double encrypting. Since his algorythm is flawed and uses only 8 bits from the provided key, double encrypting using the MD5 of the key actually "improves" the security, as it also adds ~6 bits for the MD5(key).
I've no intension to compeat mcrypt. I was just goping to Implement 3DES but due to lack of time . I made this. I had only 2.5 hrs then. Is it possible to do more than this in 2.5 hrs ??
I think you have understood Its a Chaining encryption algo
and to Its number of brute force is more than 16384 and
Mordred wrote:Also, actually only the first and the last chars in a block are encrypted with the key. Which leads to the third problem that if we have a known plaintext in the beginning or the end of a block (quite possible having in mind the low size of the blocks) we can probably recover the unknown bits and decrypt right away.
Ya I know that and thats why its double encrypted.
Z3RO21
Forum Contributor
Posts: 130
Joined: Thu Aug 17, 2006 8:59 am

Post by Z3RO21 »

neel_basu wrote:
Mordred wrote:which means bruteforcing is possible in less than 16384 tries
No You left out this line

Code: Select all

$this->enc($this->enc($str, $key), md5($key));
in your calculation.
Mordred wrote:@TheMoose: He's not double-hashing, he's double encrypting. Since his algorythm is flawed and uses only 8 bits from the provided key, double encrypting using the MD5 of the key actually "improves" the security, as it also adds ~6 bits for the MD5(key).
I've no intension to compeat mcrypt. I was just goping to Implement 3DES but due to lack of time . I made this. I had only 2.5 hrs then. Is it possible to do more than this in 2.5 hrs ??
I think you have understood Its a Chaining encryption algo
and to Its number of brute force is more than 16384 and
Mordred wrote:Also, actually only the first and the last chars in a block are encrypted with the key. Which leads to the third problem that if we have a known plaintext in the beginning or the end of a block (quite possible having in mind the low size of the blocks) we can probably recover the unknown bits and decrypt right away.
Ya I know that and thats why its double encrypted.
I am learning about cryptography and after learning and understanding the math behind the algorithms it was not hard to implement. I got a blowfish implementation done in under an hour.

And as Mordred said that algorithm not only could be brute force attacked with very few attempts but it is as he said not operating on all the bytes and leaving an open invitation to be decrypted. Start with blowfish it is a very good algorithm to learn it deals with key management, and xor / swap encoding
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Post by Mordred »

neel_basu wrote:
Mordred wrote:which means bruteforcing is possible in less than 16384 tries
No You left out this line

Code: Select all

$this->enc($this->enc($str, $key), md5($key));
in your calculation.
On the contrary, I didn't leave it out. Without this line, it's less than 256 tries. You need to understand what you wrote, as you obviously don't see it. So, please write down (with words) what the x_enc() function does.
neel_basu wrote:
Mordred wrote:Also, actually only the first and the last chars in a block are encrypted with the key. Which leads to the third problem that if we have a known plaintext in the beginning or the end of a block (quite possible having in mind the low size of the blocks) we can probably recover the unknown bits and decrypt right away.
Ya I know that and thats why its double encrypted.
I find it quite astonishing that you understand the problem with the first and last chars, and yet insist that double encryption would help. Again, explain the x_enc() function with words and hopefully you'll see it.

I understand that you didn't invest much time in this class, but encryption (and security in general) doesn't care about time spent, it cares only about being thorough. That's why homebrew encryption sucks by definition (unless you're called Bruce Schneier I suppose ;))
Z3RO21
Forum Contributor
Posts: 130
Joined: Thu Aug 17, 2006 8:59 am

Post by Z3RO21 »

Mordred wrote:That's why homebrew encryption sucks by definition (unless you're called Bruce Schneier I suppose ;))
:lol:
Post Reply