PHP Classes
Icontem

File: gnuPG_class.inc


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Enrique Garcia M.  >  gnuPG class  >  gnuPG_class.inc  
File: gnuPG_class.inc
Role: Class source
Content type: text/plain
Description: The main class for the project.
Class: gnuPG class
Encrypt data and manipulate keys using gnuPG
 

Contents

Class file image Download
<?php

/**
 * Class to interact with the gnuPG.
 *
 * @package   gnuPG_class
 * @author    Enrique Garcia Molina <egarcia@egm.as>
 * @copyright Copyright (c) 2004-2005, EGM :: Ingenieria sin fronteras
 * @license   GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
 * @since     Viernes, Enero 30, 2004
 * @version   $Id: gnuPG_class.inc,v 1.0.9 2005-07-20 11:59:00-05 egarcia Exp $
 * @see       readme.txt
 */
class gnuPG
{
	/**
	* the path to gpg executable (default: /usr/local/bin/gpg)
	* @access private
	* @var string
	*/
	var $program_path;
	
	/**
	* The path to directory where personal gnupg files (keyrings, etc) are stored (default: ~/.gnupg)
	* @access private
	* @var string
	*/
	var $home_directory;
	
	/**
	* Error and status messages
	* @var string
	*/
	var $error;
	
	/**
	* Output message
	* @var string
	*/
	var $output;
	
	/**
	* Create the gnuPG object.
	*
	* Set the program path for the GNUPG and the home directory of the keyring.
	* If this parameters are not specified, according to the OS the function derive the values.
	*
	* @param  string $program_path   Full program path for the GNUPG
	* @param  string $home_directory Home directory of the keyring
	* @return void
	*/
	function gnuPG($program_path = false, $home_directory = false)
	{
		// if is empty then assume the path based in the OS
		if (empty($program_path)) {
			if ( strstr(PHP_OS, 'WIN') )
				$program_path = 'C:\gnupg\gpg';
			else
				$program_path = '/usr/local/bin/gpg';
		}
		$this->program_path = $program_path;
		
		// if is empty the home directory then assume based in the OS
		if (empty($home_directory)) {
			if ( strstr(PHP_OS, 'WIN') )
				$home_directory = 'C:\gnupg';
			else
				$home_directory = '~/.gnupg';
		}
		$this->home_directory = $home_directory;
	}
	
	/**
	* Call a subprogram redirecting the standard pipes
	*
	* @access private
	* @param  string $command The full command to execute
	* @param  string $input   The input data
	* @param  string $output  The output data
	* @return bool   true on success, false on error
	*/
	function _fork_process($command, $input = false, &$output)
	{
		// define the redirection pipes
		$descriptorspec = array(
			0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
			1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
			2 => array("pipe", "w")   // stderr is a pipe that the child will write to
		);
		$pipes = null;
		
		// calls the process
		$process = proc_open($command, $descriptorspec, $pipes);
		if (is_resource($process)) {
			// writes the input
			if (!empty($input)) fwrite($pipes[0], $input);
			fclose($pipes[0]);
			
			// reads the output
			while (!feof($pipes[1])) {
				$data = fread($pipes[1], 1024);
				if (strlen($data) == 0) break;
				$output .= $data;
			}
			fclose($pipes[1]);
			
			// reads the error message
			$result = '';
			while (!feof($pipes[2])) {
				$data = fread($pipes[2], 1024);
				if (strlen($data) == 0) break;
				$result .= $data;
			}
			fclose($pipes[2]);
			
			// close the process
			$status = proc_close($process);
			
			// returns the contents
			$this->error = $result;
			return ($status == 0);
		} else {
			$this->error = 'Unable to fork the command';
			return false;
		}
	}
	
	/**
	* Get the keys from the KeyRing.
	*
	* The returned array get the following elements:
	* [RecordType, CalculatedTrust, KeyLength, Algorithm,
	*  KeyID, CreationDate, ExpirationDate, LocalID,
	*  Ownertrust, UserID]
	*
	* @param  string $KeyKind the kind of the keys, can be secret or public
	* @return mixed  false on error, the array with the keys in the keyring in success
	*/
	function ListKeys($KeyKind = 'public')
	{
		// validate the KeyKind
		$KeyKind = strtolower(substr($KeyKind, 0, 3));
		if (($KeyKind != 'pub') && ($KeyKind != 'sec')) {
			$this->error = 'The Key kind must be public or secret';
			return false;
		}
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --with-colons ' . (($KeyKind == 'pub') ? '--list-public-keys': '--list-secret-keys'),
			false, $contents) ) {
			
			// initialize the array data
			$returned_keys = array();
			
			// the keys are \n separated
			$contents = explode("\n", $contents);
			
			// find each key
			foreach ($contents as $data) {
				// read the fields to get the : separated, the sub record is dismiss
				$fields = explode(':', $data);
				if (count($fields) <= 3) continue;
				
				// verify the that the record is valid
				if (($fields[0] == 'pub') || ($fields[0] == 'sec')) {
					array_push($returned_keys, array(
						'RecordType' => $fields[0],
						'CalculatedTrust' => $fields[1],
						'KeyLength' => $fields[2],
						'Algorithm' => $fields[3],
						'KeyID' => $fields[4],
						'CreationDate' => $fields[5],
						'ExpirationDate' => $fields[6],
						'LocalID' => $fields[7],
						'Ownertrust' => $fields[8],
						'UserID' => $fields[9]
						)
					);
				}
			}
			return $returned_keys;
		} else
			return false;
	}
	
	/**
	* Export a key.
	*
	* Export all keys from all keyrings, or if at least one name is given, those of the given name.
	*
	* @param  string $KeyID  The Key ID to export
	* @return mixed  false on error, the key block with the exported keys
	*/
	function Export($KeyID = false)
	{
		$KeyID = empty($KeyID) ? '': $KeyID;
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --armor --export ' . $KeyID,
			false, $contents) )
			return (empty($contents) ? false: $contents);
		else
			return false;
	}
	
	/**
	* Import/merge keys.
	*
	* This adds the given keys to the keyring. New keys are appended to your
	* keyring and already existing keys are updated. Note that GnuPG does not
	* import keys that are not self-signed.
	*
	* @param  string $KeyBlock  The PGP block with the key(s).
	* @return mixed  false on error, the array with [KeyID, UserID] elements of imported keys on success.
	*/
	function Import($KeyBlock)
	{
		// Verify for the Key block contents
		if (empty($KeyBlock)) {
			$this->error = 'No valid key block was specified.';
			return false;
		}
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --status-fd 1 --import',
			$KeyBlock, $contents) ) {
			// initialize the array data
			$imported_keys = array();
			
			// parse the imported keys
			$contents = explode("\n", $contents);
			foreach ($contents as $data) {
				$matches = false;
				if (preg_match('/\[GNUPG:\]\sIMPORTED\s(\w+)\s(.+)/', $data, $matches))
					array_push($imported_keys, array(
						'KeyID' => $matches[1],
						'UserID' => $matches[2]));
			}
			return $imported_keys;
		} else
			return false;
	}
	
	/**
	* Generate a new key pair.
	*
	* @param  string $RealName     The real name of the user or key.
	* @param  string $Comment      Any explanatory commentary.
	* @param  string $Email        The e-mail for the user.
	* @param  string $Passphrase   Passphrase for the secret key, default is not to use any passphrase.
	* @param  string $ExpireDate   Set the expiration date for the key (and the subkey).  It may either be entered in ISO date format (2000-08-15) or as number of days, weeks, month or years (<number>[d|w|m|y]). Without a letter days are assumed.
	* @param  string $KeyType      Set the type of the key, the allowed values are DSA and RSA, default is DSA.
	* @param  int    $KeyLength    Length of the key in bits, default is 1024.
	* @param  string $SubkeyType   This generates a secondary key, currently only one subkey can be handled ELG-E.
	* @param  int    $SubkeyLength Length of the subkey in bits, default is 1024.
	* @return mixed  false on error, the fingerprint of the created key pair in success
	*/
	function GenKey($RealName, $Comment, $Email, $Passphrase = '', $ExpireDate = 0, $KeyType = 'DSA', $KeyLength = 1024, $SubkeyType = 'ELG-E', $SubkeyLength = 1024)
	{
		// validates the keytype
		if (($KeyType != 'DSA') && ($KeyType != 'RSA')) {
			$this->error = 'Invalid Key-Type, the allowed are DSA and RSA';
			return false;
		}
		
		// validates the subkey
		if ((!empty($SubkeyType)) && ($SubkeyType != 'ELG-E')) {
			$this->error = 'Invalid Subkey-Type, the allowed is ELG-E';
			return false;
		}
		
		// validate the expiration date
		if (!preg_match('/^(([0-9]+[dwmy]?)|([0-9]{4}-[0-9]{2}-[0-9]{2}))$/', $ExpireDate)) {
			$this->error = 'Invalid Expire Date, the allowed values are <iso-date>|(<number>[d|w|m|y])';
			return false;
		}
		
		// generates the batch configuration script
		$batch_script  = "Key-Type: $KeyType\n" .
			"Key-Length: $KeyLength\n";
		if (($KeyType == 'DSA') && ($SubkeyType == 'ELG-E'))
			$batch_script .= "Subkey-Type: $SubkeyType\n" .
				"Subkey-Length: $SubkeyLength\n";
		$batch_script .= "Name-Real: $RealName\n" .
			"Name-Comment: $Comment\n" .
			"Name-Email: $Email\n" .
			"Expire-Date: $ExpireDate\n" .
			"Passphrase: $Passphrase\n" .
			"%commit\n" .
			"%echo done with success\n";
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --batch --status-fd 1 --gen-key',
			$batch_script, $contents) ) {
			$matches = false;
			if ( preg_match('/\[GNUPG:\]\sKEY_CREATED\s(\w+)\s(\w+)/', $contents, $matches) )
				return $matches[2];
			else
				return true;
		} else
			return false;
	}
	
	/**
	* Encrypt and sign data.
	*
	* @param  string $KeyID          the key id used to encrypt
	* @param  string $Passphrase     the passphrase to open the key used to encrypt
	* @param  string $RecipientKeyID the recipient key id
	* @param  string $Text           data to encrypt
	* @return mixed  false on error, the encrypted data on success
	*/
	function Encrypt($KeyID, $Passphrase, $RecipientKeyID, $Text)
	{
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --armor --passphrase-fd 0 --yes --batch --force-v3-sigs --trust-model classic' .
				" --local-user $KeyID --default-key $KeyID --recipient $RecipientKeyID --sign --encrypt",
			$Passphrase . "\n" . $Text, $contents) )
			return $contents;
		else
			return false;
	}
	
	/**
	* Decrypt the data.
	*
	* If the decrypted file is signed, the signature is also verified.
	*
	* @param  string $KeyID      the key id to decrypt
	* @param  string $Passphrase the passphrase to open the key used to decrypt
	* @param  string $Text       data to decrypt
	* @return mixed  false on error, the clear (decrypted) data on success
	*/
	function Decrypt($KeyID, $Passphrase, $Text)
	{
		// the text to decrypt from another platforms can has a bad sequence
		// this line removes the bad date and converts to line returns
		$Text = preg_replace("/\x0D\x0D\x0A/s", "\n", $Text);
		
		// we generate an array and add a new line after the PGP header
		$Text = explode("\n", $Text);
		if (count($Text) > 1) $Text[1] .= "\n";
		$Text = implode("\n", $Text);
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --passphrase-fd 0 --yes --batch --trust-model classic' .
				" --local-user $KeyID --default-key $KeyID --decrypt",
			$Passphrase . "\n" . $Text, $contents) )
			return $contents;
		else
			return false;
	}
	
	/**
	* Remove key from the public keyring.
	*
	* If secret is specified it try to remove the key from from the secret
	* and public keyring.
	* The returned error codes are:
	* 1 = no such key
	* 2 = must delete secret key first
	* 3 = ambiguos specification
	*
	* @param  string $KeyID   the key id to be removed, if this is the secret key you must specify the fingerprint
	* @param  string $KeyKind the kind of the keys, can be secret or public
	* @return mixed  true on success, otherwise false or the delete error code
	*/
	function DeleteKey($KeyID, $KeyKind = 'public')
	{
		if (empty($KeyID)) {
			$this->error = 'You must specify the KeyID to delete';
			return false;
		}
		
		// validate the KeyKind
		$KeyKind = strtolower(substr($KeyKind, 0, 3));
		if (($KeyKind != 'pub') && ($KeyKind != 'sec')) {
			$this->error = 'The Key kind must be public or secret';
			return false;
		}
		
		// initialize the output
		$contents = '';
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --batch --yes --status-fd 1 ' .
				(($KeyKind == 'pub') ? '--delete-key ': '--delete-secret-keys ') . $KeyID,
			false, $contents) )
			return true;
		else {
			$matches = false;
			if ( preg_match('/\[GNUPG:\]\DELETE_PROBLEM\s(\w+)/', $contents, $matches) )
				return $matches[1];
			else
				return false;
		}
	}
	
	/**
	* Make a signature on key.
	*
	* If the key is not yet signed by the specified user.
	*
	* @param  string $KeyID       the key id used to sign
	* @param  string $Passphrase  the passphrase to open the key used to sign
	* @param  string $KeyIDToSign the key to be signed
	* @param  int    $CheckLevel  the check level (0, 1, 2, 3 -casual to extensive-)
	* @return bool   true on success, otherwise false
	*/
	function SignKey($KeyID, $Passphrase, $KeyIDToSign, $CheckLevel = 0)
	{
		$contents = '';
		
		// validates the check level
		$CheckLevel = intval($CheckLevel);
		if (($CheckLevel < 0) || ($CheckLevel > 3)) {
			$this->error = 'Invalid Check-Level, the allowed are 0, 1, 2, 3';
			return false;
		}
		
		// execute the GPG command
		if ( $this->_fork_process($this->program_path . ' --homedir ' . $this->home_directory .
				' --passphrase-fd 0 --status-fd 1 --yes --batch' .
				" --default-cert-check-level $CheckLevel --default-key $KeyID --edit-key $KeyIDToSign sign save",
			$Passphrase . "\n", $contents) ) {
			$matches = false;
			if ( preg_match('/\[GNUPG:\]\s[ALREADY_SIGNED|GOOD_PASSPHRASE]/', $contents, $matches) )
				return true;
			else
				return false;
		} else
			return false;
	}
}

?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products