jump to navigation

A Guide to Cryptography in PHP October 27, 2010

Posted by Tournas Dimitrios in PHP.
trackback

This comprehensive guide discusses where to get, how to install, and how to use the various cryptography packages available to enhance the security of your PHP applications.

In an ideal world, words like cryptography and security wouldn’t even exist, but the real world is far from perfect, so software developers have to spend a good deal of time building security into applications. Cryptography is just one piece of the security puzzle, along with SSL/TLS, certificates, digital signatures, and so on. This article explains how to use PHP to implement the most common cryptographic algorithms. In addition to describing PHP’s default encryption functions, you’ll see how to use a wide variety of cryptographic libraries and packages.
The code examples in this article use the contents of a short text file, textfile.txt, which contains the following plain-text content:

For every difficult and complicated 
   question there is an answer 
   that is simple, easily understood, 
   and wrong. H.L. Mencken

Default PHP Encryption Functions :PHP ships with three built-in encryption functions:

  • md5(),
  • crypt(), and
  • sha1().
  1. The md5() function prototype is:
    string md5(string $str [, bool $raw_output ])
    The function calculates the MD5 hash of a supplied string using the MD5 Message-Digest algorithm. The $str argument represents the string to be encrypted. If you pass FALSE in the $raw_output argument (the default), the function returns the hash as a 32-character hexadecimal number. If you pass TRUE then the function returns a 16-byte raw binary value.
  2. The PHP crypt() function is a one-way encryption function that lets you confirm that an entered password matches a stored encrypted one—without having to decrypt anything. The crypt() function prototype is:
    string crypt (string $str [, string $salt ])
    It returns an encrypted string using the standard Unix DES-based encryption algorithm (or alternative algorithms that may be available on the system). The $str argument is the string to be encrypted and the optional $salt argument is a string on which to base the encryption. If you don’t provide the salt string, PHP will randomly generate one each time you call this function.
  3. The PHP sha1() function calculates the SHA-1 hash of a string. The sha1() function prototype is:
    string sha1 (string $str [, bool $raw_output ])
    The function returns the SHA-1 hash as a string. Again, the $str argument represents the input string. If you set the optional $raw_output argument to TRUE, the function returns the sha1 hash in raw binary format with a length of 20 characters; if you set it to FALSE, it returns a 40-character hexadecimal number.

As an example, the following code shows how to use the PHP default encryption functions to encrypt the contents of texfile.txt file and write the encrypted result in the file encrypted.txt….

  <?php
    
   $file = 'textfile.txt';
   $initial_contents = file_get_contents($file);  
   
   if($initial_contents){
   
      $password = 'OctaviaAnghel';
   
      //Calculates the md5 hash 
      $md5_data = md5($password);
   
      //This function encrypts data
      $crypt = crypt($password);
   
      //Calculate the sha1 hash
      $sha1 = sha1($password);
   
      $encrypted_file = @fopen('encrypted.txt','w');
      $ok_encrypt = @fwrite($encrypted_file,'md5: '. $md5_data."\r\n".'crypt: 
          '.$crypt."\r\n".'sha1: '.$sha1);
   
      if($ok_encrypt){
         echo 'The encrypted code was succesfully created'.
         ' in encrypted_file.txt!!!'.'
';
      }
      else{
         echo ("The write of this file failed!");
      }
      
      @fclose($encrypted_file);
   } 
   ?> 

In addition to the built-in functions, PHP supports encryption via external libraries and packages. Table 1 shows the libraries and packages described in the rest of this article.

Table 1. Cryptography in PHP: The table contains a list of packages and libraries described in this article that work with PHP to perform various types of encryption and decryption.
Package/Library Description
MCrypt Use MCrypt to encrypt large files or data streams using any of a wide range of encryption functions. You can find more information at http://mcrypt.sourceforge.net/.
MHash Use the MHash library to obtain hashes. MHash supports the most popular algorithms and implementations, such as SHA, MD5, and CRC. You can use these algorithms to compute checksums, message digests, and create other signatures. MHash is often used to obtain password hashes for passwords entered into HTML password fields. You can find more information at http://mhash.sourceforge.net/.
Crypt_Blowfish Use Crypt_Blowfish for quick two-way encryption both with or without a secret key. You don’t need the MCrypt PHP extension to use Crypt_Blowfish; however, the package can use MCrypt if it’s installed. More details at: http://pear.php.net/package/Crypt_Blowfish.
Crypt_RSA Crypt_RSA provides RSA-like key generation, encryption/decryption, signing and signature checking. More details here: http://pear.php.net/package/Crypt_RSA.
Crypt_ HMAC This class calculates RFC 2104-compliant hashes. You’ll find complete information at: http://pear.php.net/package/Crypt_HMAC.
Crypt_DiffieHellman This package is a PHP5 implementation of the Diffie-Hellman Key Exchange cryptographic protocol. You can find more information at http://pear.php.net/package/Crypt_DiffieHellman.

Encrypting Large Data with MCrypt
MCrypt allows developers to encrypt files or data streams using any of a large number of encryption functions without having to be cryptographers. MCrypt supports a wide variety of block algorithms such as Blowfish, DES, TripleDES, SAFER-SK128, TWOFISH, TEA, RC2, 3-WAY, SAFER-SK64, and several “modes of operation.” Normally a block chipper such as MCrypt operates on data blocks of fixed length, often 64 or 128 bits. But because messages may be of any length, and because encrypting the same plaintext using the same key always produces the same output, several solutions have been invented that allow block ciphers to provide confidentiality for messages of arbitrary length. These solutions are known as modes of operation. The modes supported by MCrypt include: CBC, CFB, CTR, ECB, OFB, and NCFB.

The companion library for MCrypt is Libmcrypt, which contains the actual encryption functions themselves. Windows users can download it here, while Linux users can get it here.

Author’s Note: If you are using PHP 5.0.0 you will also need libmcrypt Version 2.5.6 or greater.

Installing Libmcrypt:

  1. Download libmcrypt.dll.
  2. Copy the libmcrypt.dll file to {php_home}/ext and {Windows_home}/System32.
  3. In php.ini activate the extension=php_mcrypt.dll line by deleting the comment mark (“;”).
  4. Save the updated php.ini file.
Author’s Note: For Linux, you have to download the libmcrypt-x.x.tar.gz file and follow the included installation instructions.

MCrypt can operate with the four cipher modes CBC, OFB, CFB, and ECB. If you are using a libmcrypt-2.4.x version or higher, then MCrypt functions also operate with the nOFB and STREAM cipher modes. Table 2 shows the most commonly-used encryption modes, along with a short description of when to use each.

Table 2. Commonly-Used MCrypt Modes: These cipher modes all operate with MCrypt, and are useful in different situations.
Encryption Mode Description
MCRYPT_MODE_ECB Use with random data. You can use this mode to encrypt different keys.
MCRYPT_MODE_CBC Used for encrypting files.
MCRYPT_MODE_CFB Recommended for encrypting byte streams.
MCRYPT_MODE_OFB Used specifically in applications where error propagation is not accepted.
MCRYPT_MODE_NOFB Comparable with OFB, but more secure.
MCRYPT_MODE_STREAM Use when you need stream algorithms such as WAKE or RC4.

In addition to the modes listed in Table 2, MCrypt also currently supports these ciphers:

  • MCRYPT_3DES
  • MCRYPT_ARCFOUR
  • MCRYPT_BLOWFISH
  • MCRYPT_ENIGMA
  • MCRYPT_GOST
  • MCRYPT_IDEA (non-free)
  • MCRYPT_LOKI97
  • MCRYPT_MARS
  • MCRYPT_PANAMA
  • MCRYPT_RIJNDAEL_128
Author’s Note: Because the list of supported ciphers can change over time, you should periodically check this list of the currently supported ciphers .

MCrypt Example
Here’s an example that shows how to encrypt and decrypt the contents of a text file using MCrypt. Again, the example encrypts the contents of textfile.txt and stores the encrypted result in the file encrypted.txt. However, this example also decrypts that file and stores the unencrypted text in the file newfile.txt:

 // Listing file_encrypt.php
   <?php
    
   $file = 'textfile.txt';
   $initial_contents = file_get_contents($file);  
   
   if($initial_contents){
   
      //This function opens the module of the algorithm and the mode to be used
      $td = mcrypt_module_open('tripledes', '', 'ecb', '');
   
      //Create an initialization vector (IV) from a random source
      $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
   
      //This function initializes all buffers needed for encryption
      mcrypt_generic_init($td, $initial_contents, $iv);
   
      //This function encrypts data
      $encrypted_data = mcrypt_generic($td, $initial_contents); 
   
      $encrypted_file = @fopen('encrypted.txt','w');
      $ok_encrypt = @fwrite($encrypted_file,$encrypted_data);
      if($ok_encrypt){
         echo 'The encrypted code was succesfully created '.
         'in encrypted_file.txt!!!'.'<br />';
      }
      else{
         echo ("The write of this file failed!");
      }
      
      @fclose($encrypted_file);
   
      mcrypt_generic_init($td, $initial_contents, $iv);
   
      //This function decrypts data
      $p_t = mdecrypt_generic($td, $encrypted_data);
   
      $newfile = @fopen('newfile.txt','w');
      $ok_decrypt = @fwrite($newfile,$p_t);
      if($ok_decrypt){
         echo 'The decrypted code was succesfully created '.
         'in newfile.txt!!!'.'<br />';
      }
      else{
         echo ("The write of this file failed!");
      }
      @fclose($newfile);
    
      //This function deinitializes an encryption module
      mcrypt_generic_deinit($td);
   
      //Close the mcrypt module
      mcrypt_module_close($td);  
      } 
   
   ?>

Building Hashes with MHash :
MHash is a free library that lets developers choose from a large number of hash algorithms. These algorithms can be used to compute checksums, message digests, and create other signatures.

Installing Libmhash

  1. Download libmhash.dll.
  2. Copy the libmhash.dll file to {php_home}/ext and to {Windows_home}/System32.
  3. In php.ini, activate the extension=php_mhash.dll line by deleting the comment mark (“;”).
  4. Save the updated php.ini file.

Supported Hashes
The hashes currently supported by MHash are:

  • MHASH_ADLER32
  • MHASH_CRC32
  • MHASH_CRC32B
  • MHASH_GOST
  • MHASH_HAVAL128
  • MHASH_HAVAL160
  • MHASH_HAVAL192
  • MHASH_HAVAL256
  • MHASH_MD4
  • MHASH_MD5
  • MHASH_RIPEMD160
  • MHASH_SHA1
  • MHASH_SHA256
  • MHASH_TIGER
  • MHASH_TIGER128
  • MHASH_TIGER160

The following example uses MHash to encrypt the contents of texfile.txt and write the encrypted result to encrypted.txt:

<?php
   
   $file = 'textfile.txt';
   $initial_contents = file_get_contents($file);
   
   if($initial_contents){
   
      //mhash() applies a hash function specified by MHASH_MD5 
      //to the $initial_contents 
      $encrypted = mhash(MHASH_MD5, $initial_contents);
      
      // get current Unix timestamp
      $current = time();
   
      $salt = $current;
      $password = "Octavia";
   
      //mhash_keygen_s2k generates a key according to the hash function 
      //given and the password provided by the user. 
      $hash = mhash_keygen_s2k(MHASH_GOST, $password, $salt, 20);
   
      //concatenate the $salt with the $hash 
      $key = $salt . "|" . bin2hex($hash);
   
      $encrypted_file = @fopen('encrypted.txt','w');
      $ok_encrypt = @fwrite($encrypted_file,
         'mhash: '.bin2hex($encrypted).'  mhash_keygen_s2k:   
         '.$key);
      
      if($ok_encrypt){
         echo 'The encrypted code was succesfully created '. 
         'in encrypted_file.txt !!!'.'<br />';
      }
      else{
         echo ("The write of this file failed!");
      }
      @fclose($encrypted_file);
   }
   ?>

Secret Keys and Crypt_Blowfish :
Secret-key cryptography uses a single key for both encryption and decryption—also called a symmetric key. For example, the commonly-used DES algorithm is a secret key algorithm. The Crypt_Blowfish PEAR package is based on the Blowfish block cipher and supports two-way encryption, either with or without a secret key. The package doesn’t require MCrypt, but Crypt_Blowfish can use MCrypt if it’s installed. The latest released version is 1.0.1 (stable), and you install it like any other PEAR package:
> pear install pear_package_name
This package uses two classes defined in the Blowfish.php file, which you must include in all scripts that use the Crypt_Blowfish package:

require_once ‘Crypt/Blowfish.php’;

Here’s the code for the by-now-familiar encryption example program using Crypt_Blowfish:

<?php
   
   require_once 'Crypt/Blowfish.php';
   
   $file = 'textfile.txt';
   $initial_contents = file_get_contents($file);
   
   if($initial_contents){
      $bf = new Crypt_Blowfish('some secret key!');
   
      // Encrypts a string   
      $encrypted = $bf->encrypt($initial_contents); 
   
      $encrypted_file = @fopen('encrypted.txt','w');
      $ok_encrypt = @fwrite($encrypted_file,$encrypted);
      if($ok_encrypt){
         echo 'The encrypted code was succesfully created '.
         'in encrypted_file.txt!!!'.'<br />';
                 }
      else{
         echo ("The write of this file failed!");
         }
      @fclose($encrypted_file);
   
      // Decrypts an encrypted string
      $plaintext = $bf->decrypt($encrypted); 
      $newfile = @fopen('newfile.txt','w');
      $ok_decrypt = @fwrite($newfile,$plaintext);
      if($ok_decrypt){
            echo 'The decrypted code was succesfully created '.
            'in newfile.txt!!!'.'<br />';
                 }
      else{
         echo ("The write of this file failed!");
         }
      
      @fclose($newfile);
      }
   ?> 

Encrypt Data Using an Arbitrary Key Length with the Crypt_RSA PEAR Package:
This package supports two-way encryption; it’s based on the RSA block cipher. Crypt_RSA supports encryption and decryption using an arbitrary key length. You can <a href=”http://pear.php.net/package/Crypt_RSA&#8221; target=”_blank”>download the latest version</a> (1.0.0, stable) and install it like any other PEAR package:

> pear install pear_package_name

Crypt_RSA performs intensive math calculations, for which it uses one of the following extensions:

Here’s an example of using this package:

<?php
   
   require_once 'Crypt/RSA.php';
   
   //Generates the pair keys
   function generate_key_pair()
   {
      global $public_key,$private_key;
   
      $key_pair = new Crypt_RSA_KeyPair(32);
   
      //Returns public key from the pair
      $public_key = $key_pair->getPublicKey();
   
      //Returns private key from the pair
      $private_key = $key_pair->getPrivateKey();
   }
   
   //Check runtime errors
   function check_error(&$obj)
   {
      if ($obj->isError()){
         $error = $obj->getLastError();
         switch ($error->getCode()) {
         case CRYPT_RSA_ERROR_WRONG_TAIL :
            // nothing to do
            break;
         default:
            // echo error message and exit
            echo 'error: ', $error->getMessage();
            exit;
         }
      }
   }
      
   $file = 'textfile.txt';
   
   generate_key_pair();  
   $plain_text = file_get_contents($file);
      
   //get string represenation of the public key
   $key = Crypt_RSA_Key::fromString($public_key->toString()); 
      
   $rsa_obj = new Crypt_RSA;
   check_error($rsa_obj);
      
   //Ecnrypts $plain_text by the key $key.
   $encrypted = $rsa_obj->encrypt($plain_text, $key);
      
   $encrypted_file = @fopen('encrypted.txt','w');
   $ok_encrypt = fwrite($encrypted_file,$encrypted);
   if($ok_encrypt){
      echo 'The encrypted code was succesfully created '.
      'in encrypted_file.txt!!!'.'<br />';
   }
   else{
      echo ("The write of this file failed!");
   }
   @fclose($encrypted_file);
      
   $enc_text = $encrypted;
     
   //Get string represenation of the private key
   $key2 = Crypt_RSA_Key::fromString($private_key->toString());
   check_error($key2);
      
   //Check encrypting/decrypting function's behaviour
   $rsa_obj->setParams(array('dec_key' => $key2));
   check_error($rsa_obj);
   
   //Decrypts $enc_text
   $decrypted = $rsa_obj->decrypt($enc_text);
      
   $newfile = @fopen('newfile.txt','w');
   $ok_decrypt = @fwrite($newfile,$decrypted);
   if($ok_decrypt){
      echo 'The decrypted code was succesfully created '.
      'in newfile.txt!!!'.'<br />';
   }
   else{
       echo ("The write of this file failed!");
   }
   @fclose($newfile);
    
   ?>  

Generating Hashes with Crypt_HMAC
The Crypt_HMAC PEAR package contains a class you can use to calculate RFC 2104-compliant hashes. Crypt_HMAC is easy to use; you need only provide your secret key, the hash method you want to use, and the plaintext string. Crypt_HMAC supports both MD5 and SHA-1 algorithms. The latest stable released version is 1.0.0. You install it just like any other PEAR package:
> pear install pear_package_name
And here’s a simple example that creates a hash using Crypt_HMAC:

<?php
      
   require_once 'Crypt/HMAC.php';
   
   //Creating a key by repeating the "0x0b" character for 20 times 
   $key = str_repeat(chr(0x0b), 20);
   
   //Creating an instance of the Crypt_HMAC class
   //$crypt = new Crypt_HMAC($key, 'md5');
   $crypt = new Crypt_HMAC($key, 'md5');
     
   //Hashing function
   echo $crypt->hash('Hello')."<br />";
   
   $key = str_repeat(chr(0xaa), 10);
   $data = str_repeat(chr(0xdd), 50);
   
   //Sets key to use with hash
   $crypt->setKey($key);
   echo $crypt->hash($data)."\n";
   ?>

Generating Secret Keys with the Crypt_DiffieHellman PEAR Package
This PEAR package implements the Diffie-Hellman Key Exchange cryptographic protocol in PHP5. You can use the protocol to generate a secret key for two foreign parties, who can then use the generated key for communications even on insecure channels. You can download the latest release, version 0.2.1 (beta) and then install it the same way as any other PEAR package.
> pear install pear_package_name
The following two code examples show two applications for generating a secret key between two parties: subject_1 and subject_2. The first example shows you the simplest way to obtain a secure key based on Diffie Hellman algorithm:

 <?php
   
   //include Diffie Hellman functions
   require_once 'Crypt/DiffieHellman.php';
   
   //set the required options for two subjects
   $subject_1 = array('prime'=>'123', 'generator'=>'7', 'private'=>'3');
   $subject_2 = array('prime'=>'123', 'generator'=>'7', 'private'=>'34');
   
   //apply Diffie Hellman algorithm
   $subject_1_GK = new Crypt_DiffieHellman(
      $subject_1['prime'], $subject_1['generator'], 
      $subject_1['private']);
   $subject_2_GK = new Crypt_DiffieHellman(
      $subject_2['prime'], $subject_2['generator'], 
      $subject_2['private']);
   
   //generate keys      
   $subject_1_GK->generateKeys();
   $subject_2_GK->generateKeys();
   
   //compute the secret keys     
   $subject_1_SK = $subject_1_GK->computeSecretKey(
      $subject_2_GK->getPublicKey())->getSharedSecretKey();
   $subject_2_SK = $subject_2_GK->computeSecretKey(
      $subject_1_GK->getPublicKey())->getSharedSecretKey();
   
   //displaying the secret keys      
   echo('Subject_1_SK:'.$subject_1_SK.'<br />');
   echo('Subject_2_SK:'.$subject_2_SK);
   ?>

The second example shows you how to generate a secret key using the Diffie Hellman BINARY mode:

<?php
   
   //include Diffie Hellman functions
   require_once 'Crypt/DiffieHellman.php';
   
   //set the required options for two subjects
   $subject_1 = array('prime' => 
      '9568094558049898340935098349053', 
      'generator'=>'2', 
      'private' => '2232370277237628823279273723742872289398723');
   $subject_2 = array('prime' => 
      '9568094558049898340935098349053', 
      'generator'=>'2', 
      'private' => '0389237288721323987429834389298232433363463');
   
   //apply Diffie Hellman algorithm
   $subject_1_GK = new Crypt_DiffieHellman(
      $subject_1['prime'], $subject_1['generator'], 
      $subject_1['private']);
   $subject_2_GK = new Crypt_DiffieHellman(
      $subject_2['prime'], $subject_2['generator'], 
      $subject_2['private']);
   
   //generate keys    
   $subject_1_GK->generateKeys();
   $subject_2_GK->generateKeys(); 
   
   //compute the secret keys using BINARY mode      
   $subject_1_SK = $subject_1_GK->computeSecretKey(
     $subject_2_GK->getPublicKey(Crypt_DiffieHellman::BINARY), 
     Crypt_DiffieHellman::BINARY)->
     getSharedSecretKey(Crypt_DiffieHellman::BINARY);
   $subject_2_SK = $subject_2_GK->computeSecretKey(
      $subject_1_GK->getPublicKey(Crypt_DiffieHellman::BINARY), 
      Crypt_DiffieHellman::BINARY)->
      getSharedSecretKey(Crypt_DiffieHellman::BINARY);
   
   //display the secret keys    
   echo('subject_1_SK:'.$subject_1_SK.'<br />');
   echo('subject_2_SK:'.$subject_2_SK.'<br />');
   
   ?>

With the wide variety of cryptographic options you’ve seen here, you should be able to achieve nearly anything you want. Cryptography is a delicate security problem—and as you can see there are many solutions and implementations. The information in this article can help you get started, but beyond that, only experience and hard work with secure systems will help you to choose the cryptographic implementation that represents the perfect compromise between security, speed, and implementation time.

Advertisements

Comments»

No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s