I'm trying to encrypt (big) files in PHP using AES and have looked into using Mcrypt and OpenSSL, the problem is all solutions I have found so far only encrypt strings, and the files I'm trying to encrypt would trigger the max memory limit for PHP (which unfortunately can't be set higher), how would I go about achieving this?
-
I built [this](https://github.com/paragonie-scott/php-crypto-stream) as an experiment/PoC before I start a pull request for [defuse/php-encryption](https://github.com/defuse/php-encryption). If you really need it, I can nudge defuse into merging my other PR and get started on this. – Scott Arciszewski Jun 10 '15 at 15:29
-
Previous link for "this" is broken; see https://github.com/defuse/php-encryption/pull/63 – Scott Arciszewski Jun 15 '15 at 04:16
-
@ScottArciszewski So is it possible to use defuse for large file encryption? Just reading file in chunks and encrypting each chunk with Crypto::encrypt obviously doesn't work...so, any solution? – Andrew Jan 12 '16 at 19:31
-
Look at version 2 (coming out soon). – Scott Arciszewski Jan 12 '16 at 19:36
-
@ScottArciszewski So i can not use version 2 now....must wait until it is released? – Andrew Jan 12 '16 at 20:22
-
If you need something *today*, there's [Halite, based on libsodium](https://github.com/paragonie/halite). – Scott Arciszewski Jan 12 '16 at 20:28
-
@ScottArciszewski Thanks for the link. Well I can wait, but it depends on how 'long'..sometimes 'coming out soon' translates into half a year :) – Andrew Jan 13 '16 at 07:36
-
It's 12 days overdue. I'll bug him when I get a chance. – Scott Arciszewski Jan 13 '16 at 17:28
4 Answers
You could use CBC encryption using Mcrypt and then encrypt a segment of data at a time. Make sure that the segment is x times the block size of the used cipher (e.g. 16 bytes for AES). Encrypt the segment and take the last block of the generated ciphertext and use it as IV for the next segment. The final segment should be PKCS#7 padded (plenty of examples out there including in the mcrypt_encrypt
comments).
By chaining the segments together you get a ciphertext indistinguishable from a single encrypt (test your code using this information). Decryption is identical, using the ciphertext as IV. To see how it works, look at the CBC encryption method:
EDIT: if possible you should use the OpenSSL equivalent functionality. That's not (well) documented, but you should be able to do the same using the code found in the link within the comment that Scott mentioned. Note that you should first perform everything without padding, and then for the final segment with padding.

- 90,524
- 13
- 150
- 263
-
So encrypting 4096byte chunks of data with CBC using the AES cipher, padding the final segment should do the trick? – Sander Jun 09 '15 at 22:26
-
Yep, that should work. Don't forget to use a random IV though. The random IV should be stored somewhere, usually at the beginning. CTR would have been nicer (random access) but mcrypt support is lacking. – Maarten Bodewes Jun 10 '15 at 04:10
-
I haven't programmed this, but is definitely *should* work. Could you please confirm that you were able to use this solution? Otherwise indicate where you are stuck. – Maarten Bodewes Jun 10 '15 at 09:48
-
1You can pass `'ctr'` instead of `MCRYPT_MODE_CBC` to get CTR mode in `mcrypt`. If you're using mcrypt for the `mcrypt_generic_init()`-based streaming interface, okay. Otherwise, [please don't use mcrypt](https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong). – Scott Arciszewski Jun 10 '15 at 15:31
-
@ScottArciszewski Good link. I've warned against mcrypt in the past as well. The previous `mcrypt_encrypt` sample code said it all; this is not programmed by an expert. I personally rewrote that sample code. mcrypt - the C library - has indeed last seen updates in 2007 or so and isn't maintained. The only reason that I didn't use it is because I didn't find the `OPENSSL_RAW_DATA` in the description - which is not surprising as the OpenSSL wrapper hasn't been properly documented. – Maarten Bodewes Jun 10 '15 at 16:16
-
https://github.com/paragonie-scott/php-crypto-stream - This is eventually going to be part of https://github.com/defuse/php-encryption – Scott Arciszewski Jun 10 '15 at 16:19
-
-
Historical note: the repository I referenced two months ago has been replaced by a [pull request](https://github.com/defuse/php-encryption/pull/78). Carry on :) – Scott Arciszewski Aug 11 '15 at 23:38
I have published two functions which encrypt and decrypt even large files with the help of openssl_encrypt()
using the AES-128-CBC algorithm.
Please refer to this openssl_encrypt().

- 6,534
- 4
- 43
- 59
Updated answer
Encrypting big files is a hard problem as its hard to verify that no "chunk" has been tampered with.
Use a library such as https://github.com/defuse/php-encryption
\Defuse\Crypto\File::encryptFile( 'in.file', 'out.file', $key );
-- Old answer --
http://www.shellhacks.com/en/Encrypt-And-Decrypt-Files-With-A-Password-Using-OpenSSL
$ openssl enc -aes-256-cbc -salt -in file.txt -out file.txt.enc
to not use too much memory, you want a stream cipher. Call this in PHP with backticks `
or with shell_exec
Make sure that the variables are NOT user input (eg user cant control file.txt). generate them yourself.
Edit
As shell exec is not available
http://jeremycook.ca/2011/03/20/easy-file-encryption/
There is a solution there. Though and I can't stress this enough. Stream ciphers are hard I have not reviewed the code there fully nor do I think I am capable. Using open SSL directly is a much better option
http://php.net/manual/en/filters.encryption.php
Is the example code

- 18,275
- 8
- 32
- 65
-
I forgot to mention, but I'm afraid that shell_exec() is also not available. – Sander Jun 09 '15 at 21:07
-
WARNING For those who want to use this solution, do not let user to choose file names (source or destination) directly, because it will allow user to execute command on your server!! Only use this solution if you trust all dynamic parts of the command. – Mostafa Lavaei Feb 09 '21 at 22:15
-
Using SSL on your website would take care of it for you. Any files that are transmitted are encrypted by the client browser, and server using the HTTPS protocol.
As far as storing the encrypted versions of the files I would not recommend.

- 380
- 3
- 6
-
1It is for storing encrypted versions of files, the contents of the files may never be known to the party who will be storing the data. – Sander Jun 09 '15 at 21:09