Hi all,
Will post this to the Wiki when it's back from the land of the dead. Here's a
copy of my Zend_Crypt proposal which intitially implements Hashed Message
Authentication COde (HMAC) and Diffie-Hellman Key Exchange (DH).
It's the wiki formatted form - still readable of course ;).
The Math classes which are currently omitted are located in the referred
Subversion repository. The code is basically complete barring review comments -
I got these through the PEAR proposal process over the last few weeks for the
PEAR OpenID effort.
{zone-template-instance:ZFDEV:Zend Proposal Zone Template}
{zone-data:component-name}
Zend_Crypt
{zone-data}
{zone-data:proposer-list}
[Pádraic Brady|mailto:padraic dot brady at yahoo dot com]
{zone-data}
{zone-data:revision}
1.0 - 13 July 2007
{zone-data}
{zone-data:overview}
The purpose of Zend_Crypt is to offer PHP5 implemented cryptographic and
encryption algorithms for use by other components (e.g. Zend_Mail, Zend_OpenId)
and application developers themselves. In proposing Zend_Crypt, a primary goal
is to reduce reliance on disparate implementations within the framework by
offering very flexible implementations which will utilise available PHP5 core
extensions. This reduces duplication and centralises maintenance of essential
core cryptographic algorithms.
The two initial Zend_Crypt implementations of the Hashed Message Authentication
Code (HMAC; RFC 2104) and Diffie-Hellman Key Exchange (DH; RFC 2631) are
proposed first since they are required algorithms of the OpenID 2.0
Authentication Specification. Others will follow should the proposal be
accepted.
{zone-data}
{zone-data:references}
* [Implementations in
subversion|http://svn.astrumfutura.org/zendframework/trunk/library/Proposed/Zend/Crypt]
*Related PEAR proposals for PHP5/PEAR2*
* [PEAR Crypt_HMAC2|http://pear.php.net/pepr/pepr-proposal-show.php?id=495]
* [PEAR
Crypt_DiffieHellman|http://pear.php.net/pepr/pepr-proposal-show.php?id=496]
*RFC References*
* [RFC 2104: HMAC: Keyed-Hashing for Message
Authentication|http://tools.ietf.org/html/rfc2104]
* [RFC 2631: Diffie-Hellman Key Agreement
Method|http://tools.ietf.org/html/rfc2631]
{zone-data}
{zone-data:requirements}
* *Must* be accompanied by comprehensive unit tests reflecting any RFCs which
illustrate a testing framework
* *Must* implement Hashed Message Authentication Code (RFC2104)
* *Must* implement Diffie-Hellman Key Exchange (RFC2631)
* *Must* implement Math methods for enabling big integer (> 32 bit) support and
methods for transforming big integer strings to binary forms, and vice versa.
{zone-data}
{zone-data:dependencies}
* Zend_Crypt_Math
* Zend_Exception
{zone-data}
{zone-data:operation}
Zend_Crypt will be a collection of cryptographic and encryption classes. As
such each component can be used in isolation, or to perform aggregate
operations (e.g. using Diffie-Hellman to negotiate an HMAC). Operation is
intended to be flexible, with support for input and output (where warranted)
forms like big integers and binary.
Please refer to Use Cases for additional API overviews.
{zone-data}
{zone-data:milestones}
* Milestone 1: Implement Hashed-Message-Authentication-Code (HMAC) and
Diffie-Hellman-Key-Exchange (DH)
* Milestone 2: Verify operation using Unit Tests based on RFC test examples and
which test both standard and binary output.
* Milestone 3: Documentation
{zone-data}
{zone-data:class-list}
* Zend_Crypt_Hmac
* Zend_Crypt_DiffieHellman
* Zend_Crypt_Math
{zone-data}
{zone-data:use-cases}
* All use cases take the form of Unit Tests*
* Zend_Crypt_Hmac *
{code:php}
class Zend_Crypt_HmacTest extends PHPUnit_Framework_TestCase
{
public function testHmacMD5_1()
{
$data = 'Hi There';
$key = str_repeat("\x0b", 16);
$hmac = new Zend_Crypt_Hmac($key, 'MD5');
$this->assertEquals('9294727a3638bb1c13f48ef8158bfc9d',
$hmac->hash($data));
}
public function testHmacSHA1_4()
{
$data = str_repeat("\xcd",50);
$key =
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19";
$hmac = new Zend_Crypt_Hmac($key, 'SHA1');
$this->assertEquals('4c9007f4026250c6bc8414f9bf50c86c2d7235da',
$hmac->hash($data));
}
public function testHmacRIPEMD160_6()
{
$data = 'Test Using Larger Than Block-Size Key - Hash Key First';
$key = str_repeat("\xaa",80);
$hmac = new Zend_Crypt_Hmac($key, 'RIPEMD160');
$this->assertEquals('6466ca07ac5eac29e1bd523e5ada7605b791fd8b',
$hmac->hash($data));
}
}
{code}
Please note that these simple Unit Tests are matched with far more realistic
tests using big integers. The above are simple test cases used for illustrative
purposes.
* Zend_Crypt_DiffieHellman *
Diffie-Hellman Key Exchange involved two parties, communicating across an
insecure communication channel, negotiating a shared secret key which cannot be
guessed or reverse engineered by a third party. If it looks a bit unintuitive -
bear in mind the private keys are never exchanged. Without the private keys, a
third party can have every single piece of data but remain unable to re-perform
the shared key computation.
{code:php}
class Zend_Crypt_DiffieHellmanTest extends PHPUnit_Framework_TestCase
{
public function testDiffieWithSpec()
{
$aliceOptions = array(
'prime'=>'563',
'generator'=>'5',
'private'=>'9'
);
$bobOptions = array(
'prime'=>'563',
'generator'=>'5',
'private'=>'14'
);
$alice = new Zend_Crypt_DiffieHellman($aliceOptions['prime'],
$aliceOptions['generator'], $aliceOptions['private']);
$bob = new Zend_Crypt_DiffieHellman($bobOptions['prime'],
$bobOptions['generator'], $bobOptions['private']);
$alice->generateKeys();
$bob->generateKeys();
$this->assertEquals('78', $alice->getPublicKey());
$this->assertEquals('534', $bob->getPublicKey());
$aliceSecretKey =
$alice->computeSecretKey($bob->getPublicKey())->getSharedSecretKey();
$bobSecretKey =
$bob->computeSecretKey($alice->getPublicKey())->getSharedSecretKey();
// both Alice and Bob should now have the same secret key
$this->assertEquals('117', $aliceSecretKey);
$this->assertEquals('117', $bobSecretKey);
}
}
{code}
Please note that these simple Unit Tests are matched with far more realistic
tests using big integers. The above are simple test cases used for illustrative
purposes.
{zone-data}
{zone-data:skeletons}
*Zend_Crypt_Hmac*
{code:php}
/**
* PHP implementation of the RFC 2104 Hash based Message Authentication Code
* algorithm.
*
* @category Zend
* @package Zend_Crypt
* @copyright Copyright (c) 2007 Pádraic Brady (http://blog.astrumfutura.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @todo Check if mhash() is a required alternative (will be PECL-only
soon)
*/
class Zend_Crypt_Hmac
{
/**
* The key to use for the hash
*
* @var string
*/
private $_key = null;
/**
* pack() format to be used for current hashing method
*
* @var string
*/
private $_packFormat = null;
/**
* Hashing algorithm; can be the md5/sha1 functions or any algorithm name
* listed in the output of PHP 5.1.2+ hash_algos().
*
* @var string
*/
private $_hashAlgorithm = 'md5';
/**
* Supported direct hashing functions in PHP
*
* @var array
*/
private $_supportedHashNativeFunctions = array(
'md5',
'sha1',
);
/**
* List of hash pack formats for each hashing algorithm supported.
* Only required when hash or mhash are not available, and we are
* using either md5() or sha1().
*
* @var array
*/
private $_hashPackFormats = array(
'md5' => 'H32',
'sha1' => 'H40'
);
/**
* List of algorithms supported my mhash()
*
* @var array
*/
private $_supportedMhashAlgorithms = array('adler32',' crc32', 'crc32b',
'gost',
'haval128', 'haval160', 'haval192', 'haval256', 'md4', 'md5',
'ripemd160',
'sha1', 'sha256', 'tiger', 'tiger128', 'tiger160');
/**
* Constants representing the output mode of the hash algorithm
*/
const STRING = 'string';
const BINARY = 'binary';
/**
* Constructor; optionally set Key and Hash at this point
*
* @param string $key
* @param string $hash
* @return void
*/
public function __construct($key = null, $hash = null)
{}
/**
* Set the key to use when hashing
*
* @param string $key
* @return Zend_Crypt_Hmac
*/
public function setKey($key)
{}
/**
* Getter to return the currently set key
*
* @return string
*/
public function getKey()
{}
/**
* Setter for the hash method. Supports md5() and sha1() functions, and if
* available the hashing algorithms supported by the hash() PHP5 function.
*
* @param string $hash
* @return Zend_Crypt_Hmac
*/
public function setHashAlgorithm($hash)
{}
/**
* Return the current hashing algorithm
*
* @return string
*/
public function getHashAlgorithm()
{}
/**
* Perform HMAC and return the keyed data
*
* @param string $data
* @param string $output
* @param bool $internal Option to not use hash() functions for testing
* @return string
*/
public function hash($data, $output = self::STRING, $internal = false)
{}
/**
* Since MHASH accepts an integer constant representing the hash algorithm
* we need to make a small detour to get the correct integer matching our
* algorithm's name.
*
* @param string $hashAlgorithm
* @return integer
*/
protected function _getMhashDefinition($hashAlgorithm)
{}
/**
* Digest method when using native functions which allows the selection
* of raw binary output.
*
* @param string $hash
* @param string $key
* @param string $mode
* @return string
*/
protected function _digest($hash, $key, $mode)
{}
}
{code}
*Zend_Crypt_DiffieHellman*
{code:php}
/**
* PHP implementation of the Diffie-Hellman public key encryption algorithm.
* Allows two unassociated parties to establish a joint shared secret key
* to be used in encrypting subsequent communications.
*
* @category Zend
* @package Zend_Crypt
* @subpackage DiffieHellman
* @copyright Copyright (c) 2007 Pádraic Brady (http://blog.astrumfutura.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Crypt_DiffieHellman
{
/**
* Default large prime number; required by the algorithm.
*
* @var string
*/
private $_prime = null;
/**
* The default generator number. This number must be greater than 0 but
* less than the prime number set.
*
* @var string
*/
private $_generator = null;
/**
* A private number set by the local user. It's optional and will
* be generated if not set.
*
* @var string
*/
private $_privateKey = null;
/**
* BigInteger support object courtesy of Zend_Math
*
* @var Zend_Math_BigInteger
*/
private $_math = null;
/**
* The public key generated by this instance after calling generateKeys().
*
* @var string
*/
private $_publicKey = null;
/**
* The shared secret key resulting from a completed Diffie Hellman
* exchange
*
* @var string
*/
private $_secretKey = null;
/**
* Constants
*/
const BINARY = 'binary';
const NUMBER = 'number';
const BTWOC = 'btwoc';
/**
* Constructor; if set construct the object using the parameter array to
* set values for Prime, Generator and Private.
* If a Private Key is not set, one will be generated at random.
*
* @param string $prime
* @param string $generator
* @param string $privateKey
* @param string $privateKeyType
* @return void
*/
public function __construct($prime, $generator, $privateKey = null,
$privateKeyType = self::NUMBER)
{}
/**
* Generate own public key. If a private number has not already been
* set, one will be generated at this stage.
*
* @return Zend_Crypt_DiffieHellman
*/
public function generateKeys()
{}
/**
* Returns own public key for communication to the second party to this
* transaction.
*
* @param string $type
* @return string
*/
public function getPublicKey($type = self::NUMBER)
{}
/**
* Compute the shared secret key based on the public key received from the
* the second party to this transaction. This should agree to the secret
* key the second party computes on our own public key.
* Once in agreement, the key is known to only to both parties.
* By default, the function expects the public key to be in binary form
* which is the typical format when being transmitted.
*
* @param string $publicKey
* @param string $type
* @return Zend_Crypt_DiffieHellman
*/
public function computeSecretKey($publicKey, $type = self::NUMBER)
{}
/**
* Return the computed shared secret key from the DiffieHellman transaction
*
* @param string $type
* @return string
*/
public function getSharedSecretKey($type = self::NUMBER)
{}
/**
* Setter for the value of the prime number
*
* @param string $number
* @return Zend_Crypt_DiffieHellman
*/
public function setPrime($number)
{}
/**
* Getter for the value of the prime number
*
* @return string
*/
public function getPrime()
{}
/**
* Setter for the value of the generator number
*
* @param string $number
* @return Zend_Crypt_DiffieHellman
*/
public function setGenerator($number)
{}
/**
* Getter for the value of the generator number
*
* @return string
*/
public function getGenerator()
{}
/**
* Setter for the value of the private number
*
* @param string $number
* @param string $type
* @return Zend_Crypt_DiffieHellman
*/
public function setPrivateKey($number, $type = self::NUMBER)
{}
/**
* Getter for the value of the private number
*
* @param string $type
* @return string
*/
public function getPrivateKey($type = self::NUMBER)
{}
/**
* Setter to pass an extension parameter which is used to create
* a specific BigInteger instance for a specific extension type.
* Allows manual setting of the class in case of an extension
* problem or bug.
*
* @param string $extension
* @return void
*/
public function setBigIntegerMath($extension = null)
{}
/**
* In the event a private number/key has not been set by the user,
* generate one at random.
*
* @return string
*/
protected function _generatePrivateKey()
{}
}
{code}
{zone-data}
{zone-template-instance}
Pádraic Brady
http://blog.astrumfutura.com
http://www.patternsforphp.com
____________________________________________________________________________________
Looking for earth-friendly autos?
Browse Top Cars by "Green Rating" at Yahoo! Autos' Green Center.
http://autos.yahoo.com/green_center/