Reputation: 137
I'm surprised that I didn't find any code snippet, advice or tutorial in the web that explains how to encrypt a file using just standard php components.
So I'm asking your advice: how to encrypt/decrypt files using just mcrypt and php standard functions? I do not have the option to use gnupg. No, actually, my question is: how to do the above without messing up my files? Because I'm already encrypting/decrypting the hell out of these files (with mcrypt/AES), and it works well for jpegs, PDF, some .doc files and interestingly password-secured .docx files. It does not work for non-secured .docx files and numerous other filetypes.
My current code is this. Basically, I really just open the file, whisk the data around with mcrypt/AES, and write it on server/let user download it.
To encode after upload:
// using codeigniter's encryption library, which uses mcrypt and the AES cypher
$this->load->library('encrypt');
$pathandname = $config['upload_path'].$output['content'][$a]['file_name'];
$theFile = file_get_contents($pathandname);
$fh = fopen($pathandname,'w');
fwrite($fh,$this->encrypt->encode($theFile));
fclose($fh);
To decode & download:
$this->load->library('encrypt');
$pathandname = $filelocation.$results[0]['encryptedfile'];
$theFile = file_get_contents($pathandname);
$decrypted = $this->encrypt->decode($theFile);
force_download($filename, $decrypted); // a codeigniter function to force download via headers
Upvotes: 1
Views: 16687
Reputation: 34093
how to encrypt/decrypt files using just mcrypt and php standard functions?
Well, you don't want to use mcrypt. You want to use sodium these days.
The relevant API you're looking for is crypto_secretstream
.
const CUSTOM_CHUNK_SIZE = 8192;
/**
* @ref https://stackoverflow.com/q/11716047
*/
function encryptFile(string $inputFilename, string $outputFilename, string $key): bool
{
$iFP = fopen($inputFilename, 'rb');
$oFP = fopen($outputFilename, 'wb');
[$state, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($key);
fwrite($oFP, $header, 24); // Write the header first:
$size = fstat($iFP)['size'];
for ($pos = 0; $pos < $size; $pos += CUSTOM_CHUNK_SIZE) {
$chunk = fread($iFP, CUSTOM_CHUNK_SIZE);
$encrypted = sodium_crypto_secretstream_xchacha20poly1305_push($state, $chunk);
fwrite($oFP, $encrypted, CUSTOM_CHUNK_SIZE + 17);
sodium_memzero($chunk);
}
fclose($iFP);
fclose($oFP);
return true;
}
Decryption looks like this:
/**
* @ref https://stackoverflow.com/q/11716047
*/
function decryptFile(string $inputFilename, string $outputFilename, string $key): bool
{
$iFP = fopen($inputFilename, 'rb');
$oFP = fopen($outputFilename, 'wb');
$header = fread($iFP, 24);
$state = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
$size = fstat($iFP)['size'];
$readChunkSize = CUSTOM_CHUNK_SIZE + 17;
for ($pos = 24; $pos < $size; $pos += $readChunkSize) {
$chunk = fread($iFP, $readChunkSize);
[$plain, $tag] = sodium_crypto_secretstream_xchacha20poly1305_pull($state, $chunk);
fwrite($oFP, $plain, CUSTOM_CHUNK_SIZE);
sodium_memzero($plain);
}
fclose($iFP);
fclose($oFP);
return true;
}
Using the two functions together:
$key = random_bytes(32);
encryptFile('input.txt', 'cipher.txt', $key);
decryptFile('cipher.txt', 'decrypt.txt', $key);
Upvotes: 2