3

I'm looking for a simple yet cryptographically strong PHP implementation of AES using Mcrypt.

Hoping to boil it down to a simple pair of functions, $garble = encrypt($key, $payload) and $payload = decrypt($key, $garble).

Avatar
  • 14,622
  • 9
  • 119
  • 198
ChaseMoskal
  • 7,151
  • 5
  • 37
  • 50
  • Once I have this in order, I'll also be quite interested to achieve a compatible JavaScript implementation. – ChaseMoskal May 10 '14 at 18:54
  • There are a few implementations of php/js: [2011/08/matching-php-and-js-encryption](http://kevinkuchta.com/_site/2011/08/matching-php-and-js-encryption/). Also, [aes-php.html](http://www.movable-type.co.uk/scripts/aes-php.html) – Ryan Vincent May 10 '14 at 22:50
  • The PHP/JavaScript combo sounds like a typical use case for TLS (SSL successor) / HTTPS. – Perseids May 10 '14 at 23:04
  • I have a class I have been playing with [here](http://codereview.stackexchange.com/questions/49267/mcrypt-are-there-any-flaws-or-areas-for-improvement-in-this-class). I'm not suggesting it's good to use (hence being on codereview) but might give inspiration – Luke May 10 '14 at 23:11
  • @ilovecode, i have a similar class but it uses 'twofish'. i may do some comparisons with your class. one immediate difference is that i use GUID to create a 'site reference'. Also, uniqid() is fine for 'salts'. – Ryan Vincent May 10 '14 at 23:54
  • @Ryan I am given to understanding that what I have is equivalent to AES-256 encryption, but I have not had that confirmed yet. I like the idea of using uniqid and will probably make appropriate changes to that class. Do you mean the same thing when you said GUID and `uniqid()`? – Luke May 11 '14 at 00:04
  • @ilovecode, Sorry, was not criticizing your code in any way! was trying explain that others share your concerns about security. 'twofish' is old, and also secure. No, GUID is not the same as 'uniqid()'. GUID: this may be useful: [online-guid-generator](http://www.guidgenerator.com/). – Ryan Vincent May 11 '14 at 00:52
  • It is best not to use mcrypt, it is abandonware, has not been updated in years and does not support standard PKCS#7 (née PKCS#5) padding, only non-standard null padding that can't even be used with binary data. mcrypt had many outstanding [bugs](https://sourceforge.net/p/mcrypt/bugs/) dating back to 2003. Instead consider using [defuse](https://github.com/defuse/php-encryption) or [RNCryptor](https://github.com/RNCryptor), they provide a complete solution and are being maintained and is correct. – zaph Jul 29 '16 at 20:40

4 Answers4

12

I'm recently learning about this subject, and am posting this answer as a community wiki to share my knowledge, standing to be corrected.

It's my understanding that AES can be achieved using Mcrypt with the following constants as options:

MCRYPT_RIJNDAEL_128     // as cipher
MCRYPT_MODE_CBC         // as mode
MCRYPT_MODE_DEV_URANDOM // as random source (for IV)

During encryption, a randomized non-secret initialization vector (IV) should be used to randomize each encryption (so the same encryption never yields the same garble). This IV should be attached to the encryption result in order to be used later, during decryption.

Results should be Base 64 encoded for simple compatibility.

Implementation:

<?php

define('IV_SIZE', mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));

function encrypt ($key, $payload) {
  $iv = mcrypt_create_iv(IV_SIZE, MCRYPT_DEV_URANDOM);
  $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
  $combo = $iv . $crypt;
  $garble = base64_encode($iv . $crypt);
  return $garble;
}

function decrypt ($key, $garble) {
  $combo = base64_decode($garble);
  $iv = substr($combo, 0, IV_SIZE);
  $crypt = substr($combo, IV_SIZE, strlen($combo));
  $payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
  return $payload;
}


//:::::::::::: TESTING ::::::::::::


$key = "secret-key-is-secret";
$payload = "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered.";

// ENCRYPTION
$garble = encrypt($key, $payload);

// DECRYPTION
$end_result = decrypt($key, $garble);

// Outputting Results
echo "Encrypted: ", var_dump($garble), "<br/><br/>";
echo "Decrypted: ", var_dump($end_result);

?>

Output looks like this:

Encrypted: string(152) "4dZcfPgS9DRldq+2pzvi7oAth/baXQOrMmt42la06ZkcmdQATG8mfO+t233MyUXSPYyjnmFMLwwHxpYiDmxvkKvRjLc0qPFfuIG1VrVon5EFxXEFqY6dZnApeE2sRKd2iv8m+DiiiykXBZ+LtRMUCw==" 

Decrypted: string(96) "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered."
ChaseMoskal
  • 7,151
  • 5
  • 37
  • 50
  • 1
    Could you indicate what part of this is different from the PHP sample code in `mcrypt_encrypt`? – Maarten Bodewes May 10 '14 at 20:30
  • @owlstead: Well, here we're defining a pair of simple, reusable functions. Here, `MCRYPT_DEV_URANDOM` is used as an IV source instead of `MCRYPT_RAND` (which is allegedly better). I'm still trying to determine if it's important to hash the keys, and maybe even salt them. I'd also like to make this inter-operable with a common AES JavaScript library, though I'm not sure and haven't chosen one. – ChaseMoskal May 10 '14 at 21:28
  • 1
    `MCRYPT_DEV_URANDOM` is - in my option - better than `MCRYPT_RANDOM` so that's OK, especially for an IV. The key should either be randomly generated (use hex as in the example). If you want to use a password, you will have to add a PBKDF such as bcrypt to the mix; a password is not a key. There is no such thing as a "common AES library". JavaScript encryption in the browser is a disputed technology to say the least. – Maarten Bodewes May 10 '14 at 22:45
  • Note that there does not seem to be a PHP port of [RNCryptor](https://github.com/RNCryptor/RNCryptor) yet. – Maarten Bodewes May 10 '14 at 22:50
  • @owlstead: I realize you're right, and I must salt-hash the passwords into keys. I'll add this soon, after I figure the best way to bcrypt this. `password_hash()` from PHP 5.5+ looks great, but not sure if there is another convenient way to do this for earlier versions of PHP. Will probably update this tomorrow. Thanks! – ChaseMoskal May 11 '14 at 01:05
  • There are '\0\0\0\0' at the end. If you quote the string with PDO, then you will see. – shuangwhywhy Jan 14 '16 at 05:06
  • PHP [RNCryptor](https://github.com/RNCryptor/RNCryptor-php), see all ports of: [RNCryptor](https://github.com/RNCryptor). – zaph Jul 29 '16 at 20:43
1

Add function to clean control characters (�).

function clean($string) {
return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $string);

}

echo "Decrypted: ", clean($end_result);

Sentrapedagang.com

Dewa Putra
  • 15
  • 3
0

Simple and Usable:

$text= 'Hi, i am sentence';
$secret = 'RaNDoM cHars!@#$%%^';

$encrypted = simple_encrypt($text,           $secret);
$decrypted = simple_decrypt($encrypted_text, $secret);

codes:

function simple_encrypt($text_to_encrypt, $salt)    { 
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,  pack('H*', $salt), $text_to_encrypt, MCRYPT_MODE_CBC, $iv =  mcrypt_create_iv($iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND))));
}

function simple_decrypt($encrypted, $salt)  { 
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack('H*', $salt), base64_decode($encrypted), MCRYPT_MODE_CBC, $iv = mcrypt_create_iv($iv_size=mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND))); 
}
T.Todua
  • 53,146
  • 19
  • 236
  • 237
-1

Class Mycrypt

Try using this class. Here. All you need to pass is key and string.

class MCrypt
{
    const iv = 'fedcba9876543210';

    /**
 * @param string $str
 * @param bool $isBinary whether to encrypt as binary or not. Default is: false
 * @return string Encrypted data
 */
public static function encrypt($str, $key="0123456789abcdef", $isBinary = false)
{
    $iv = self::iv;
    $str = $isBinary ? $str : utf8_decode($str);
    $td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
    mcrypt_generic_init($td, $key, $iv);
    $encrypted = mcrypt_generic($td, $str);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $isBinary ? $encrypted : bin2hex($encrypted);
}

/**
 * @param string $code
 * @param bool $isBinary whether to decrypt as binary or not. Default is: false
 * @return string Decrypted data
 */
public static function decrypt($code, $key="0123456789abcdef", $isBinary = false)
{
    $code = $isBinary ? $code : self::hex2bin($code);
    $iv = self::iv;
    $td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
    mcrypt_generic_init($td, $key, $iv);
    $decrypted = mdecrypt_generic($td, $code);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $isBinary ? trim($decrypted) : utf8_encode(trim($decrypted));
}

private static function hex2bin($hexdata)
{
    $bindata = '';
    for ($i = 0; $i < strlen($hexdata); $i += 2) {
        $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
    }
    return $bindata;
}
   }

How To Use

 $var = json_encode(['name'=>['Savatar', 'Flash']]);
 $encrypted = MCrypt::encrypt();
 $decrypted = MCrypt::decrypt($encrypted);
Abhijit Srivastava
  • 1,419
  • 2
  • 10
  • 33
  • I don't see the relevance of changing the character encoding of the encrypted data. What happens if I want to encrypt my poem that makes, say, russian, chinese, and hebrew rhyme together? I feel you should leave your context-specific character encoding handling out of the scope of your cryptography. – Bigue Nique Aug 05 '18 at 08:32