4

I am trying to come up with a way to have PHP encrypt a file. I used to just use a PHP system call to run a script that encoded the file:

#!/bin/sh
/usr/bin/openssl aes-256-cbc -a -salt -k $1 -in $2

Argument 1 was the password to use and argument 2 is the data. I then use a second script on a computer to de-crypt the file.

#!/bin/sh
/usr/bin/openssl aes-256-cbc -a -d -salt -k $1 -in $2

This method of encrypting will not work on a production host as the PHP system call is disabled. I also would prefer not the change the decode function if at all possible.

Is there a way to replicate the above encrypt function using only PHP?

2
  • 2
    The Mcrypt library does AES apparently ("Rijndael" is another name for AES). Commented Sep 19, 2011 at 21:10
  • Rijndael was the original name before it became "AES" as part of the NIST standardization process. Commented Apr 24, 2012 at 18:43

3 Answers 3

7

Take a look at mcyrpt_encrypt():

string mcrypt_encrypt ( string $cipher , string $key , string $data , 
                        string $mode [, string $iv ] )

Set $cipher to MCRYPT_RIJNDAEL_128 (AES-128), and $mode to MCRYPT_MODE_CBC.

Then use base64_encode() to generate a base-64 encoded output (ie: what the -a option does).


openssl derives the key and IV as follows:

Key = MD5(Password + Salt)
IV  = MD5(Key + Password + Salt)

Where Salt is a 8 byte salt. With this in mind, I created simple encrypt() and decrypt() routines:


function ssl_encrypt($pass, $data) {

    $salt = substr(md5(mt_rand(), true), 8);

    $key = md5($pass . $salt, true);
    $iv = md5($key . $pass . $salt, true);

    $ct = mcrypt_encrypt (MCRYPT_RIJNDAEL_128, $key, $data, 
                          MCRYPT_MODE_CBC, $iv);

    return base64_encode('Salted__' . $salt . $ct);
}

function ssl_decrypt($pass, $data) {

    $data = base64_decode($data);
    $salt = substr($data, 8, 8);
    $ct = substr($data, 16);

    $key = md5($pass . $salt, true);
    $iv = md5($key . $pass . $salt, true);

    $pt = mcrypt_decrypt (MCRYPT_RIJNDAEL_128, $key, $ct, 
                          MCRYPT_MODE_CBC, $iv);

    return $pt;
}

The parameter $data takes the string to be encrypted. If you want to encrypt a file, you'll have to get it via file_get_contents() or similar and then give that to the function.

Usage:

echo ssl_encrypt('super secret key', 'Hello World');

Generates something like (will change every time because of the random salt):

U2FsdGVkX18uygnq8bZYi6f62FzaeAnyB90U6v+Pyrk=
Sign up to request clarification or add additional context in comments.

10 Comments

@GregS This is the openssl enc format. The IV is not saved, instead it is derived from the salt as I described.
This should work, but for some reason openssl is failing to decrypt some of the input generated by my encrypt() routine when it's saved to a file, even though my decrypt() routine can handle strings generated by both my encrypt() routine and openssl's enc just fine. This might have something to do with the way newlines at the end of the file are handled.
@Greg Well, if that were the case, shouldn't my decrypt() also fail?
@kaptk2 Yes, I've been getting that too. It's probably a padding issue.
apperently mcrypt_encrypt pads with zeros, whereas openssl used standard PKCS7 padding.
|
2

As stated above in the comments padding is necessary to make this work. The function below will make a file that can be decrypted on the command line like this:

openssl enc -d -aes-256-cbc -a -salt -in test.txt

The test.txt file is created from the output of the ssl_encrypt function below.

function ssl_encrypt($pass, $data)
{
    // Set a random salt
    $salt = substr(md5(mt_rand(), true), 8);

    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $pad = $block - (strlen($data) % $block);

    $data = $data . str_repeat(chr($pad), $pad);

    // Setup encryption parameters
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, "", MCRYPT_MODE_CBC, "");


    $key_len =  mcrypt_enc_get_key_size($td);
    $iv_len =  mcrypt_enc_get_iv_size($td);

    $total_len = $key_len + $iv_len;
    $salted = '';
    $dx = '';
    // Salt the key and iv
    while (strlen($salted) < $total_len)
    {
        $dx = md5($dx.$pass.$salt, true);
        $salted .= $dx;
    }
    $key = substr($salted,0,$key_len);
    $iv = substr($salted,$key_len,$iv_len);


    mcrypt_generic_init($td, $key, $iv);
    $encrypted_data = mcrypt_generic($td, $data);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);


    return chunk_split(base64_encode('Salted__' . $salt . $encrypted_data),32,"\r\n");
}

Example Usage:

$plainText = "Secret Message";
$password = "SecretPassword";
$test = ssl_encrypt($password, $plainText);
$file = fopen('test.txt', 'wb');
// Write the Base64 encrypted output to a file.
fwrite($file, $test);
fclose($file);
// Show the output on the screen
echo $test;

References: http://juan.boxfi.com/2010/03/16/write-openssl-files-in-php/

Comments

1

Perhaps PHP's OpenSSL library?

1 Comment

One would think that would work. However I have been unsuccessful at getting PHP's implementation of OpenSSL to work with a "standard" install of OpenSSL.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.