6

I found some tutorials online that could help but I am not sure there the best options. I would like to encrypt the file with a highly secure algorithm (I am a bit paranoid) but at the same time I am looking for speed (I know it's a bit of a contradiction)... So I chose AES-256... But what is the best way to use AES-256 with PHP to encrypt files?

hakre
  • 193,403
  • 52
  • 435
  • 836
jnbdz
  • 4,863
  • 9
  • 51
  • 93

2 Answers2

6

PHP 5.x and 7.0.x

For a symmetric algorithm, use Mcrypt.

Note though that it can be risky, from a security perspective, to use that library without knowing what everything does. Take a look at some ready-made solutions.

(Incidentally, the ciphers supported are here).

PHP 7.1.x+

The Mcrypt extension was deprecated in 7.1 and removed in 7.2, so you will need an alternative. Use Sodium instead.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • 2
    Whatever you do, just don't use the mode MCRYPT_MODE_ECB. Always use a non-ECB mode, and randomly-generated salt. – slashingweapon Nov 27 '12 at 21:18
  • Thanks @slashingweapon. Out of interest, why should that mode be avoided? – halfer Nov 28 '12 at 10:26
  • 3
    **The short version:** If you encrypt plaintext X in ECB with the same salt every time, you always get the same output. This equals very weak security. **The long version:** [Applied Cryptography](http://www.amazon.com/Applied-Cryptography-Protocols-Algorithms-ebook/dp/B000SEHPK6/ref=dp_kinw_strp_1) – slashingweapon Nov 28 '12 at 18:12
  • Heh, I'm sure that's a fine book, but libraries such as Mcrypt should be simple enough to use without reading _War And Peace_ `;-)` – halfer Nov 28 '12 at 22:10
  • 3
    That's why I gave you the short answer. – slashingweapon Nov 28 '12 at 22:55
-2

PHP Mcrypt file based symmetric encryption with AES-256, (storing IV as first 16 bytes of file), and using sha256 hmac for authenticated encryption:

<?php
print_r(mcrypt_list_algorithms());//check if rijndael-128 available
print_r(stream_get_filters());    //should contain mcrypt.* and mdecrypt.*

//16 byte key=>AES-128, 24 byte key=>AES-192, 32 byte key=>AES-256
$key='BkK8Jts................sPo38nNcW';

//encrypt file
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_RANDOM);//or MCRYPT_DEV_URANDOM
$fin = fopen($in_filename, "rb");
$fcrypt = fopen($aes_filename, 'wb');
fwrite($fcrypt, $iv);
$opts = array('iv'=>$iv, 'key'=>$key, 'mode'=>'cbc');
stream_filter_append($fcrypt, 'mcrypt.rijndael-128', STREAM_FILTER_WRITE, $opts);
while (!feof($fin))
{
    fwrite($fcrypt, fread($fin, 8192));
}
fclose($fcrypt);
fclose($fin);
$hmac_real = hash_hmac_file('sha256', $aes_filename, $key, $raw=false);

//decrypt file
$hmac_calc = hash_hmac_file('sha256', $aes_filename, $key, $raw=false);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$fcrypt = fopen($aes_filename, "rb");
$fout = fopen($out_filename, 'wb');
$iv = fread($fcrypt, $iv_size);
$opts = array('iv'=>$iv, 'key'=>$key, 'mode'=>'cbc');
stream_filter_append($fcrypt, 'mdecrypt.rijndael-128', STREAM_FILTER_READ, $opts);
while (!feof($fcrypt))
{
    $block = fread($fcrypt, 8192);
    $block = feof($fcrypt)? rtrim($block,"\0") : $block;//removes aes pad
    fwrite($fout, $block);
}
fclose($fout);
fclose($fcrypt);
$hmac_calc==$hmac_real or unlink($out_filename);//invalid if they don't match

see: http://php.net/manual/en/filters.encryption.php

AES-256 has a known weakness, so you can use a 16 byte key to trigger AES-128 in this code see: https://www.schneier.com/blog/archives/2009/07/another_new_aes.html

velcrow
  • 6,336
  • 4
  • 29
  • 21
  • 2
    AES-256 is **not** "Rijndael 256". The 256 for Rijndael refers to the blocksize which is set to 128-bit in AES for every keysize available (128, 192, 256). Use `MCRYPT_RIJNDAEL_128` for AES compatibility instead. – Artjom B. Jan 02 '15 at 19:44
  • Working example of AES-256 (not Rijndael-256) in PHP: http://blog.turret.io/the-missing-php-aes-encryption-example/ – Piohen Jan 23 '15 at 13:44