Skip to end of metadata
Go to start of metadata

<p>Following on from this <a href="http://zend-framework-community.634137.n4.nabble.com/Cryptography-in-ZF-td4261844.html">mailing list discussion</a>, and <a href="http://framework.zend.com/wiki/display/ZFDEV2/2012-03-28+Meeting+Log">IRC meeting of 28th March</a> this RFC describes the new features to add to the Zend\Crypt component.</p>

<p>The idea is to improve the Zend\Crypt with some new API to provide a simple way to encrypt/decrypt sensitive information and to store password in a secure way using the <a href="http://en.wikipedia.org/wiki/Bcrypt">bcrypt</a> algorithm. For the encryption/decryption API the idea is to use one of the MCrypt <a href="http://www.php.net/manual/en/mcrypt.ciphers.php">simmetric algorithms</a> in <a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29">CBC mode</a> and authenticate the encrypted data using <a href="http://www.cryptopp.com/wiki/Authenticated_Encryption">encrypt-then-authenticate</a> schema. The CBC mode for simmetric ciphers with the usage of random <a href="http://en.wikipedia.org/wiki/Initialization_vector">IV</a> and the encrypt-then-authenticate schema is considered secure from the community of cryptographic engineers (in primis <a href="http://www.schneier.com/">Bruce Schneier</a> that suggests this use case in the books <a href="http://www.schneier.com/book-ce.html">Cryptopgraphy Engineering</a>). <br />
For the authentication schema the idea is to use the Zend\Crypt\Hmac::compute() function with the <a href="http://en.wikipedia.org/wiki/SHA-2">SHA-256</a> algorithm. If you are wondering why we have to authenticate an encrypted message you should read the article of Serge Vaudenay about the <a href="http://en.wikipedia.org/wiki/Padding_oracle_attack">Padding oracle attack</a>.<br />
For more information on the security of encrypt-then-authenticate schema you can read the article <a href="http://eprint.iacr.org/2001/045">The order of encryption and authentication for protecting communications (Or: how secure is SSL?)</a> of Hugo Krawczyk.</p>

<p>The idea is to offer a generic API to encrypt/decrypt string (to add to the Zend\Crypt class):</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
public static function encrypt(string $data, string $key, string $alg = 'rijndael-128', string $iv = null) {}
public static function decrypt(string $data, string $key) {}
]]></ac:plain-text-body></ac:macro>

<p>where $alg is the cipher algorithm (<a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES</a> by default: rijndael-128), and $iv is the Initialization Vector (IV).<br />
Note: the decrypt function does not need the cipher algorithm and the IV specification because they are stored in the encrypted string.</p>

<p>And we want to support the encryption/decryption of Stream (for instance a file) using the following API:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
public static function encryptStream(string $data, string $key, resource $stream, string $alg = 'rijndael-128', string $iv = null) {}
public static function decryptStream(string $data, string $key, resource $stream) {}
]]></ac:plain-text-body></ac:macro>

<h2>Bcrypt support</h2>

<p>I would like to add a better interface of the algorithm bcrypt that is supported by PHP 5.3.0+. The API for the bcrypt algorithm is supported in the crypt() function.<br />
In order to use the bcrypt you have to use a syntax like that:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
$salt = substr(str_replace('+', '.',base64_encode($salt)), 0, 22);
$hash = crypt($password,'$2a$'.$workload.'$'.$salt);
]]></ac:plain-text-body></ac:macro>

<p>The bcrypt algorithm is recognized as the best algorithm for storing user's passwords. You can read this interesting article <a href="http://codahale.com/how-to-safely-store-a-password/">How To Safely Store A Password</a> of Coda Hale to discover why.<br />
The idea is to add the bcrypt algorithm as static function in Zend\Crypt. </p>

<p>The $workload factor is related to the CPU speed (it is a number from 10 to 31). To estimate the value to use as $workload factor you can refer to the slides num. 17 of my presentation at <a href="http://www.zendcon.com/">ZendCon</a> 2011, <a href="http://www.slideshare.net/e.zimuel/cryptography-in-php-use-cases">Cryptography in PHP: use cases</a>.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
public static function bcrypt(string $data, string $salt = null, int $workload = 14) {}
]]></ac:plain-text-body></ac:macro>

<h2>Improve the randomness of rand() in Zend\Crypt\Math</h2>

<p>I would like to refactor the Zend\Crypt\Math::rand to use the openssl_random_pseudo_bytes as first option and after the /dev/urandom source.</p>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 29, 2012

    <p>Hi Enrico, thanks for writing this down.</p>

    <p>First of all you know my opinion about Math already, I'd rather refactor any math related stuff to a Math namespace.</p>

    <p>About the encrypt and decrypt functions. Wouldn't it make more sense to have an Encrypter object? That way one can create their own encryption algorithms. Something like:</p>

    <ac:macro ac:name="code"><ac:parameter ac:name="title">Example</ac:parameter><ac:parameter ac:name="borderStyle">solid</ac:parameter><ac:plain-text-body><![CDATA[
    interface Encrpyter
    {
    public function decrypt( $data );
    public function decryptStream( $stream );

    public function encrypt( $data );
    public function encryptStream( $data );
    }

    class Rijndael128Encrypter implements Encrpyter
    {
    // ...
    }

    class MyCustomEncrypter implements Encrpyter
    {
    // ...
    }

    class MyWorker
    {
    private $_encrypter;

    public function __construct( $encrypter )

    Unknown macro: { $this->_encrypter = $encrypter; }

    public function load( $path )

    Unknown macro: { $data = $this->_readData( $path ); $data = $this->_encrypter->decrypt( $data ); // ... }

    public function save( $path )

    Unknown macro: { $data = $this->_writeData(); $data = $this->_encrypter->encrypt( $data ); // ... }

    }

    $worker = new MyWorker( new MyCustomEncrypter() );
    $worker->save( 'test' );
    ]]></ac:plain-text-body></ac:macro>

    <p>Or am I missing the point here?</p>

  2. Mar 29, 2012

    <p>Hi Walter,<br />
    as developer I like the idea to have an Encryption interface but at the same time I don't want to encourage PHP developers to customize the encryption/decryption algorithms. The cryptography algorithms must be standard and that's why I mentioned the Mcrypt extension in the RFC. If we are going to use only the MCrypt actually I don't think we need an Encryption interface for that. The idea to implement cryptographic algorithms in PHP doesn't sound good to me for a security reason and last, but not least, for the performance.</p>