-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 php. It's my rags-to-riches 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.