15
\$\begingroup\$

-Hello Agent. Are you on a secure line?

-Yes, secured.

-Good, in 30 seconds the launch codes will be in your e-mail's inbox. You now have the go. Are you ready for the package?

-Yes.

-The key is: "revi3wJAVA-fim++". You should have the codes by now. Be prepared to take action in T minus 14 minutes.

-Thank you, I accept my mission.

Are you guys ready? We've got the key. We've got the codes. 14 minutes til action time!

The agency is using AES-192 of course, so even if we screw up and the bad guys get these, no way will they crack 'em. Open your inbox, check out these encrypted codes.

bWPpcmX7aXttNz7Dro/LJXhEqEuGFO5FnSITtrUImUoAyRm/6BfT1Ptxzbvdc4MF3K7Pjh4QiiPbKc1ipdVi70EtjreOXKGMZIZuK4K5WBg=

and

t0kBpsCzNBMSxwQ27X6EJqgOp4dENBZOdDzF8UNQjR4YkgB+o7fajMbXMgbtIEprf6QittM3KstX6uB+8Xfh4px/50YQljo/nl2ZIKVnTKU0OWcDqdCH8nwm8zvfT7jDurC5A0vS5Z8=

Whip out your laptop, we're doing some decoding today... Load up these file and visit your host. Of course, edit in our codes and key.

McryptResource.php

<?php

/**
 * Resource container for Mcrypt encryption
 *
 * @author Alex Liebscher <alexliebscher@gmail.com>
 * @version 1.0.0
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
 */
class McryptResource {

    /**
     *
     * @var resource Encryption descriptor 
     */
    private $resource;

    /**
     *
     * @var string One of the MCRYPT_* ciphers
     */
    protected $cipher;

    /**
     *
     * @var string One of the MCRYPT_MODE_* modes
     */
    protected $mode;

    /**
     *
     * @var int Size of the initialization vector
     */
    protected $ivSize;

    /**
     *
     * @var int Size of the encryption key
     */
    protected $keySize;

    /**
     * Get the current encryption descriptor 
     * 
     * @since 1.0.0
     * @return resource Encryption descriptor
     */
    public function getResource() {
        return $this->resource;
    }

    /**
     * Create a new mcrypt module
     * 
     * @since 1.0.0
     * @param string $cipher Cipher to use
     * @param string $mode Mode to use
     * @throws InvalidArgumentException
     * @return void
     */
    public function createResource($cipher, $mode) {
        if (!in_array($cipher, mcrypt_list_algorithms())) {
            throw new InvalidArgumentException('Algorithm not supported.');
        }
        if (!in_array($mode, mcrypt_list_modes())) {
            throw new InvalidArgumentException('Mode not supported.');
        }
        $this->resource = mcrypt_module_open($cipher, '', $mode, '');
        $this->ivSize = mcrypt_enc_get_iv_size($this->resource);
        $this->keySize = mcrypt_enc_get_key_size($this->resource);
    }

    /**
     * Close the current resource
     * 
     * @since 1.0.0
     * @return void
     */
    public function freeResource() {
        if (isset($this->resource)) {
            mcrypt_generic_deinit($this->resource);
            mcrypt_module_close($this->resource);
        }
    }

    /**
     * Get the current key size
     * 
     * @since 1.0.0
     * @return int Key size
     */
    public function getKeySize() {
        return $this->keySize;
    }

    /**
     * Get the current IV size
     * 
     * @since 1.0.0
     * @return int IV size
     */
    public function getIVSize() {
        return $this->ivSize;
    }

    /**
     * Use createResource() instead to make a new resource
     * 
     * @since 1.0.0
     * @throws Exception
     * @return void
     */
    public function __clone() {
        throw new Exception('Clone not possible.');
    }

}

Mcrypt.php

<?php
/**
 * @uses McryptResource.php Unless autoloading, this file must be included
 */
require 'McryptResource.php';

/**
 * Mcrypt encryption container
 *
 * @author Alex Liebscher <alexliebscher@gmail.com> 
 * @version 1.0.0
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
 */
class Mcrypt {
    /**
     * Encrypt data using an McryptResource and a key
     * 
     * @param McryptResource $source Initialized resource to encrypt with
     * @param string $key Key to encrypt data with
     * @param string $data Data to encrypt
     * @uses Mcrypt::newSalt Creates a new salt to hash the key
     * @uses Mcrypt::newIV Creates a new IV for encryption
     * @uses Mcrypt::newKey Create a hashed key based on the user-supplied key and the new salt
     * @uses mcrypt_generic Encrypts the data
     * @return string Released ciphertext. Suitable for storage
     */
    public static function encrypt(McryptResource $source, $key, $data) {

        $salt = static::newSalt($source);
        $iv = static::newIV($source);

        mcrypt_generic_init($source->getResource(), static::newKey($source, $key, $salt), $iv);

        $ciphertext = mcrypt_generic($source->getResource(), $data);

        $source->freeResource();

        return $salt . $iv . $ciphertext;
    }

    /**
     * Decrypt data using an McryptResource and a key
     * 
     * @param McryptResource $source Initialized resource to decrypt with
     * @param string $key The key used to encrypt the data
     * @param string $ciphertext Encrypted data to decrypt
     * @uses Mcrypt::getResourceParts Break apart the ciphertext into usable parts
     * @uses Mcrypt::newKey Create a hashed key based on the user-supplied key and the new salt
     * @uses mdecrypt_generic Decrypts the data
     * @return string Decrypted plaintext
     */
    public static function decrypt(McryptResource $source, $key, $ciphertext) {

        $parts = static::getResourceParts($source, $ciphertext);

        mcrypt_generic_init($source->getResource(), static::newKey($source, $key, $parts['salt']), $parts['iv']);

        $plaintext = mdecrypt_generic($source->getResource(), $parts['data']);

        $source->freeResource();

        return $plaintext;
    }

    /**
     * Break apart ciphertext into the key's salt, the IV, and the actual data
     * 
     * @param McryptResource $resource Initialized resource to reference
     * @param string $ciphertext Ciphertext to break apart
     * @return array Parts of ciphertext needed to decrypt
     */
    protected static function getResourceParts(McryptResource $resource, $ciphertext) {
        return [
            'salt' => substr($ciphertext, 0, $resource->getKeySize()),
            'iv' => substr($ciphertext, $resource->getKeySize(), $resource->getIVSize()),
            'data' => substr($ciphertext, $resource->getKeySize() + $resource->getIVSize())
        ];
    }

    /**
     * Create a new salt to hash the key
     * 
     * @param McryptResource $resource Initialized resource to reference
     * @uses openssl_random_pseudo_bytes Utilize PHP's CSPRNG
     * @return string New salt
     */
    protected static function newSalt(McryptResource $resource) {
        return openssl_random_pseudo_bytes($resource->getKeySize());
    }

    /**
     * Hash the user-supplied key to generate a new key
     * 
     * @param McryptResource $resource Initialized resource to reference
     * @param string $key User-supplied key
     * @param string $salt Random salt
     * @uses hash Hash using SHA-256
     * @return string New key as long as the encryption methods allowed key size
     */
    protected static function newKey(McryptResource $resource, $key, $salt) {
        $hashed = hash('SHA256', $key . $salt);

        return substr($hashed, 0, $resource->getKeySize());
    }

    /**
     * Create a cryptographically secure initialization vector
     * 
     * @param McryptResource $resource Initialized resource to reference
     * @uses mcrypt_create_iv Create and IV using MCRYPT_DEV_URANDOM 
     * @return string New initialization vector
     */
    protected static function newIV(McryptResource $resource) {
        return mcrypt_create_iv($resource->getIVSize(), MCRYPT_DEV_URANDOM);
    }

}

Here's our index. Edit in the codes. The lives of many are depending on you!

<?php

require 'Mcrypt.php';

$key = 'revi3wJAVA-fim++';

/**
 * Fill this with the text to decrypt. One code at a time.
 */
$data = '';

$source = new McryptResource();
$source->createResource(MCRYPT_RIJNDAEL_192, MCRYPT_MODE_CBC);

var_dump(Mcrypt::decrypt($source, $key, $data));

Got the codes now!? Good!

3... 2... 1... Launch!


-Once again, thank you Agent. We appreciate your brave service.


Just in case you guys forgot your laptop, or maybe the email didn't get through (darn Yahoo mail...), here are the decrypted codes:

CR.SE_35559

and

SocraticUnsungHeroLegendary


Alright, less joking now! This was my attempt at creating a secure encryption handler in . It's my attempt at recreating another CR post regarding mcrypt security. I went to answer the question, but then realized I didn't know I would do it!

So I recreated it in a way I thought would be best. It allows for any cipher the machine supports, and I think it's a lot cleaner. Maybe too many comments though.

Did I need to salt and hash the key? (The original post did)

Any other nit-pickings are welcome of course.

\$\endgroup\$
  • \$\begingroup\$ that question doesn't even have an answer! \$\endgroup\$ – Malachi Aug 4 '14 at 18:49
14
\$\begingroup\$

Well, I don't know much about PHP; but I know a little about security so that is what I am going to review. First I am going to review your encryption algorithm: AES-192.

  • In June 2003, the U.S. Government announced that AES could be used to protect classified information. So that means you are doing okay/decent with your choice.

  • High speed and low RAM requirements were criteria of the AES selection process. Thus AES performs well on a wide variety of hardware, from 8-bit smart cards to high-performance computers. This isn't necessarily a good thing. The faster the algorithms run, the faster a brute-force method can get to your password.

The agency is using AES-192 of course, so even if we screw up and the bad guys get these, no way will they crack 'em.

  • Not necessarily. You need to be wary of biclique attacks (currently is the best single-key attack on AES-128, AES-192 and AES-256) and related-key attacks.

    I would be most worried about side-channel attacks. Side-channel attacks do not attack the underlying cipher, and thus are not related to security in that context. They rather attack implementations of the cipher on systems which inadvertently leak data. Cache-timing attacks is a popular side-channel attack, with some implementations being able to obtain an entire AES key after only 800 operations triggering encryptions, in a total of 65 milliseconds.


Did I need to salt and hash the key?

  • If I were you, I would forget the key; salt and hash the password directly. Sure, you will need to modify your software a bit; but overall it will be more secure. This is because hashes are one-way functions, it is believed that the text cannot be transformed back into the original (mathematically, we do not know if secure hash functions actually exist, we just have "candidates": nobody in the world knows how to break it yet). And then you don't have to worry about a key, because you can just compare the hashes directly.

  • We need a slower cryptographic hashing function. SHA-256 is too fast for us too use. With the speed at which hardware can do hashing calculations today, an attacker with off-the-shelf hardware can crack through your salted and hashed password in a few hours, calculating and comparing up to trillions of hashes per second. You've got to slow them down.

    So how do we slow them down? The easiest way to slow them down is to just make them do more work. Instead of calculating one hash to check a password, you have to calculate 1000 (or whatever number you feel like). Combining scrypt (CPU and RAM intensive) and bcrypt (more GPU intensive) should do the job for us.

  • Keep in mind that this slower function won't affect an attacker with rainbow tables. However, the hashes in a rainbow table have to use the exact same hash function for them to be of any use. This is where the salting of the password can make a huge difference, since instead of using one hashing function we use multiple distinct hashing functions. Properly applied salts will completely thwart rainbow tables.

\$\endgroup\$
  • 1
    \$\begingroup\$ That was a great read, I'll be going over this multiple times :) \$\endgroup\$ – Alex L Jul 30 '14 at 18:01
  • \$\begingroup\$ "I would forget the key and salt and hash the password directly" - A comma could really help here ;) What're the differences between a "key" and a "password"? \$\endgroup\$ – Alex L Jul 30 '14 at 22:01
  • \$\begingroup\$ @AlexL Key vs. password. Edits made. \$\endgroup\$ – syb0rg Jul 31 '14 at 21:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.