Advertisement

Creating a Crypter Class with PHP

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

In this article I will explain how to create a PHP Class that will encrypt and decrypt any data with a given password. It is object programmed and uses existing PHP algorithms.


Introduction

Think about what we might need a class like this for? We want to encrypt important data with a password for security reasons. We also want, as already mentioned, to be able to decrypt that data when necessary. Why should you use symmetric algorithms? It's easy; when you're offering a password sent via email or something like that, you need the password to be sent in plaintext. The hash algorithms are not reversible. Once you have hashed a string you can't decipher the original text from the hash.

Maybe you have already heard of MD5? It's not really the best option anymore because it tends to be unsafe. There are databases around the web - that I don't want to mention - that can be used to retrieve the plaintext from a hash simply by typing in the hash into a search box. So you should use something like SHA which was developed by the NSA (National Security Agency). SHA is the abbreviation for Secure Hash Algorithm and is one of the most secure hash algorithms. There are some others as well, such as WHIRLPOOL, PANAMA and RIPEMD, but SHA is currently the secure standard for hashes and is used in numerous applications.


Step 1: Preparation

I think it is important to create an interface. This is because we can always use the methods which are defined in the interface without thinking, when instancing an object of a class, which implements that interface.

When a class implements an interface it has to implement the methods given in that interface, otherwise there will be an error! So here is an example:

  
		interface ICrypter{
			public function Encrypt($data);
			public function Decrypt($data);
		}
	
		class Crypter implements ICrypter{
			public function Encrypt($data){ ... }
			public function Decrypt($data){ ... }
		}

As you can see, the interface instructs the classes which implement ICrypter to have the public function Encrypt with one parameter $data. The public function Decrypt also has the parameter $data. You can try it out; if the class lacks one of the given methods in the interface, you get a fatal error. Here's an example:

Fatal error: Class Crypter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ICrypter::Decrypt) in C:\www\Nettuts\Crypter\crypter.php on line 32.

Nice error right? So you can be sure that the classes really have the methods!


Step 2: Password for Encryption and Decryption

As I said before, we want to be able to use a specific password for encryption and decryption. This password has to be accessible for the encrypt- and decrypt-function so we will define an instance variable, called key, which is passed to the constructor. The definition of $Key is only needed in the Crypter Class:

 
		private $Key;

However, the definition of the constructor has to be in the interface. Therefore, it is also needed in the class, because we have to implement everything we have defined in the interface. The interface will contain:

 
		public function __construct($Key);

and the class:

 
		public function __construct($Key){ ... }

Now that we know we get a key, we can use it to encrypt and decrypt!


Step 3: Constructor

In the constructor we have to set the key and choose an algorithm. We will use the Blowfish algorithm for this example and use it as a standard value. I will explain a bit more about the symmetric algorithms later in the text, but for simplicity we will use Blowfish. You can change this later if you want to. So we need another instance variable called Algo:

 
		private $Algo;

and the constructor...

 
		public function __construct($Key, $Algo = MCRYPT_BLOWFISH){
			$this->Key = substr($Key, 0, mcrypt_get_key_size($Algo, MCRYPT_MODE_ECB));
			$this->Algo = $Algo;
		}

The length of the key depends on the algorithm and the encryption mode. In this example we will use the ECB mode. You can make this variable like we have already done with the algorithm. We use the substring of the given key with the maximum allowed length. You can get this length with the mcrypt_get_key_size function which requires the algorithm and the encryption mode as parameters.

Now we give our instance variable Key the correct key for the algorithm and assign our instance variable Algo.

So now we have the constructor. As I said previously, you can change the standard value of Algo to any other algorithm that is supported by MCrypt.

List of supported algorithms from php.net:

  • MCRYPT_3DES
  • MCRYPT_ARCFOUR_IV (libmcrypt > 2.4.x only)
  • MCRYPT_ARCFOUR (libmcrypt > 2.4.x only)
  • MCRYPT_BLOWFISH
  • MCRYPT_CAST_128
  • MCRYPT_CAST_256
  • MCRYPT_CRYPT
  • MCRYPT_DES
  • MCRYPT_DES_COMPAT (libmcrypt 2.2.x only)
  • MCRYPT_ENIGMA (libmcrypt > 2.4.x only, alias for MCRYPT_CRYPT)
  • MCRYPT_GOST
  • MCRYPT_IDEA (non-free)
  • MCRYPT_LOKI97 (libmcrypt > 2.4.x only)
  • MCRYPT_MARS (libmcrypt > 2.4.x only, non-free)
  • MCRYPT_PANAMA (libmcrypt > 2.4.x only)
  • MCRYPT_RIJNDAEL_128 (libmcrypt > 2.4.x only)
  • MCRYPT_RIJNDAEL_192 (libmcrypt > 2.4.x only)
  • MCRYPT_RIJNDAEL_256 (libmcrypt > 2.4.x only)
  • MCRYPT_RC2
  • MCRYPT_RC4 (libmcrypt 2.2.x only)
  • MCRYPT_RC6 (libmcrypt > 2.4.x only)
  • MCRYPT_RC6_128 (libmcrypt 2.2.x only)
  • MCRYPT_RC6_192 (libmcrypt 2.2.x only)
  • MCRYPT_RC6_256 (libmcrypt 2.2.x only)
  • MCRYPT_SAFER64
  • MCRYPT_SAFER128
  • MCRYPT_SAFERPLUS (libmcrypt > 2.4.x only)
  • MCRYPT_SERPENT(libmcrypt > 2.4.x only)
  • MCRYPT_SERPENT_128 (libmcrypt 2.2.x only)
  • MCRYPT_SERPENT_192 (libmcrypt 2.2.x only)
  • MCRYPT_SERPENT_256 (libmcrypt 2.2.x only)
  • MCRYPT_SKIPJACK (libmcrypt > 2.4.x only)
  • MCRYPT_TEAN (libmcrypt 2.2.x only)
  • MCRYPT_THREEWAY
  • MCRYPT_TRIPLEDES (libmcrypt > 2.4.x only)
  • MCRYPT_TWOFISH (for older mcrypt 2.x versions, or mcrypt > 2.4.x )
  • MCRYPT_TWOFISH128 (TWOFISHxxx are available in newer 2.x versions, but not in the 2.4.x versions)
  • MCRYPT_TWOFISH192
  • MCRYPT_TWOFISH256
  • MCRYPT_WAKE (libmcrypt > 2.4.x only)
  • MCRYPT_XTEA (libmcrypt > 2.4.x only)

So which one should we use when we want to use the Crypter Class in our products? At the moment AES is the standard of the symmetric algorithms. It is used in many applications, but where is AES? AES was originally published as Rijndael which is listed. It is a really fast, but secure, algorithm and is even fast with 256-Bit key size. My advice is to use MCRYPT_RIJNDAEL_256 for your applications. Just as an example, AES is used in WPA2 which is a security standard for WLAN.


Step 4: Now to the Encryption

First thing to check: is there any data to encrypt? If not, you can go ahead and break the encryption. If you want to use any other encryption modes then you have to add the following code.

 
		$iv_size = mcrypt_get_iv_size($this->Algo, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

This $iv is used for example in CBC, CFB, OFB and in some algorithms in STREAM encryption mode. If the parameter is not passed in these modes, the $iv will be set to '\0'. The next step is to encrypt the data with the simple function mcrypt_encrypt. Here we need our algorithm, the key, the data and an encryption mode. $iv is optional.

 
		$crypt = mcrypt_encrypt($this->Algo, $this->Key, $data, MCRYPT_MODE_ECB, $iv);

Finally encode the encrypted data with base64_encode and trim it before you return it.

 
		return trim(base64_encode($crypt));

We have to base64 encode the encrypted data to get URL-Safe data. This is needed because, if you want to use the encrypted data, for example in a URL, you will have problems with '&' as it is a reserved character specified in the RFC. So you need something like alphanumeric characters - in other words, character that are safe. The base64 encode supplies these safe characters, which is why we're using it. We do not know what will be done with the data after encryption.


Step 5: Decryption is Reversed Encryption

Again we ask the same first question. Is there data? If there is, you have to base64_decode the data as we have previously encoded it with base64_encode.

 
	$crypt = base64_decode($data);

Then the optional part with $iv.

 
			$iv_size = mcrypt_get_iv_size($this->Algo, MCRYPT_MODE_ECB);
			$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

Decryption with the simple function mcrypt_decrypt. Here we need - nearly - the same parameters. The difference is that the decrypt-function needs to access the crypted data rather than the original data. So here again we use, the algorithm, the key, the crypted data, the encryption mode, and the optional iv.

 
		$decrypt = mcrypt_decrypt($this->Algo, $this->Key, $crypt, MCRYPT_MODE_ECB, $iv);

Finally return the trimmed and decrypted data.

 
		return trim($decrypt);


Examples

Define a global Crypter. In this example we will use RIJNDAEL_256 (AES) with the password "Any password". After instancing you call your functions or methods to test it. Here we call the function foo and the method foo1.

 
		$crypter = new Crypter("Any password", MCRYPT_RIJNDAEL_256);

		foo();
		
		$foo = new Foo();
		$foo->foo1();

You can get your crypter from the Superglobal variable called $GLOBALS. This is an associative array, so you can call all your global variables by the name you defined them with. You can retrieve the $crypter which is defined outside of the foo or foo1 block with $GLOBALS["crypter"]...

 
		function foo(){
			...
			$encrypted = $GLOBALS["crypter"]->Encrypt($data);
			$decrypted = $GLOBALS["crypter"]->Decrypt($encrypted);
			...
		}
		
		class Foo{
			public function foo1(){
				...
				$encrypted = $GLOBALS["crypter"]->Encrypt($data);
				$decrypted = $GLOBALS["crypter"]->Decrypt($encrypted);
				...
			}
		}

Conclusion

Now you have a complete Crypter class and you can crypt and decrypt as many times as you wish! Download the complete source code with a nice example if you do not want to type it in yourself. I hope that you have enjoyed this article.

Advertisement