As commented by @Peter the datasize using RSA encryption is limited (depends on RSA keysize) to plaintext lengths of about 60 to 400 bytes only.
To solve the problem of encrypting a file (here a MP3-file of about 5 mb) you need to switch to a hybrid encryption as recommended by @Topaco.
Indeed, there are fewer examples for this in public so I wrote a very simple program that does what it promises to do.
The program generates a random encryption key (length 32 bytes for AES-256), a random initialization vector ("iv", 16 bytes long for AES CBC mode) and then encrypts the key with the public key with RSA padding PKCS1_OAEP_PADDING. It writes the encrypted key, the iv and the ciphertext to a file.
For decryption the (encrypted) key is read (256 bytes long) from the file, followed by the iv and the encrypted data. Then the encrypted key is decrypted with the private key and used for the final decryption with AES. In the end the decrypted data is written to a file and voilà - the file is playable.
NOTICE: The main problem in my code could be the loading of the complete files (e.g. original mp3-file on encryption and encrypted file on decryption side)
into memory before they get encrypted or decrypted - e.g. having an uncut mp3-file of hundreds of mb size may cause an ""out of memory error" - beware of this.
Security warning: this file comes with absolute NO exception handling and is for educational purpose only!.
The code will load the private and public keys from actual directory as well as the mp3-file processing takes place in this memory.
The output is short:
PHP OpenSSL RSA & AES CBC 256 hybrid encryption
encryption finished
decryption finished
here is the - beware of the limitations and security warning:
<?php
// hybrid encryption
// https://stackguides.com/questions/64693606/php-encrypt-a-file-using-public-key-and-decrypt-using-private-key
echo 'PHP OpenSSL RSA & AES CBC 256 hybrid encryption' . PHP_EOL;
// get filenames
$plainfile = "./whateverittakes.mp3";
$cipherfile = "./whateverittakes.mp3.enc";
$decryptedfile = "./whateverittakesdec.mp3";
// attention: it is a RSA PRIVATE KEY !
// key generation:
// openssl genrsa -out private.key 2048
// openssl rsa -in private.key -out public.pem -outform PEM -pubout
// load private & public key
$public_key = openssl_pkey_get_public(file_get_contents('./public.pem'));
$private_key = openssl_pkey_get_private(file_get_contents('./private.key'));
// generate random aes encryption key
$key = openssl_random_pseudo_bytes(32); // 32 bytes = 256 bit aes key
// now encrypt the aes encryption key with the public key
openssl_public_encrypt($key, $encryptedKey, $public_key, OPENSSL_PKCS1_OAEP_PADDING);
// save 256 bytes long encrypted key
file_put_contents($cipherfile, $encryptedKey);
// aes cbc encryption
// generate random iv
$iv = openssl_random_pseudo_bytes(16);
// save 16 bytes long iv
file_put_contents($cipherfile, $iv, FILE_APPEND);
$data = file_get_contents($plainfile);
$cipher = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
// save cipher
file_put_contents($cipherfile, $cipher, FILE_APPEND);
echo 'encryption finished' . PHP_EOL;
// decryption
// read the data
$handle = fopen($cipherfile, "rb");
// read 256 bytes long encryptedKey
$decryptionkeyLoad = fread($handle, 256);
// decrypt the encrypted key with private key
openssl_private_decrypt($decryptionkeyLoad, $decryptionkey, $private_key, OPENSSL_PKCS1_OAEP_PADDING);
// read 16 bytes long iv
$ivLoad = fread($handle, 16);
// read ciphertext
$dataLoad = fread($handle, filesize($cipherfile));
fclose($handle);
$decrypt = openssl_decrypt($dataLoad, 'AES-256-CBC', $decryptionkey, OPENSSL_RAW_DATA, $ivLoad);
file_put_contents($decryptedfile, $decrypt);
echo 'decryption finished' . PHP_EOL;
?>
OPENSSL_PKCS1_PADDING
orOPENSSL_PKCS1_OAEP_PADDING
). For symmetric encryption, the AES algorithm can be used, which can be carried out in PHP e.g. withopenssl_encrypt()
(documentation including use cases). – Topaco