PHP:使用公钥加密文件,使用私钥解密



我有这个应用程序来使用公钥(public.pem(加密MP3音频片段,然后使用私钥(private.key(解密。我尝试了以下方法,但加密的文件返回为0字节文件。未返回任何错误。

exec("openssl genrsa -out private.key 2048");
exec("openssl rsa -in private.key -out public.pem -outform PEM -pubout");
$public_key = file_get_contents('./public.pem');
$private_key = file_get_contents('./private.key');
$source = "./sample.mp3";
$dest = "./sample.mp3.enc";
$data = file_get_contents($source);
openssl_public_encrypt($data, $output, $public_key, OPENSSL_NO_PADDING);
file_put_contents($dest, $output);

我该怎么做?有一些PHP示例可以使用这种私钥/公钥方式加密文本,但不能加密文件。

正如@Peter所评论的,使用RSA加密的数据大小(取决于RSA密钥大小(仅限于大约60到400字节的明文长度。要解决加密文件(这里是大约5 mb的MP3文件(的问题,您需要按照@Topaco的建议切换到混合加密

事实上,公开的例子很少,所以我写了一个非常简单的程序,实现了它承诺要做的事情。

该程序生成随机加密密钥(AES-256的长度为32字节(、随机初始化矢量("iv",AES CBC模式的长度为16字节(,然后用RSA填充PKCS1_OAEP_padding的公钥对密钥进行加密。它将加密密钥、iv和密文写入一个文件。

为了解密,从文件中读取(加密的(密钥(256字节长(,然后读取iv和加密数据。然后用私钥对加密的密钥进行解密,并用于AES的最终解密。最后,解密后的数据被写入一个文件,瞧,这个文件是可以播放的。

注意:我的代码中的主要问题可能是加载完整的文件(例如,加密端的原始mp3文件和解密端的加密文件(在它们被加密或解密之前将其存储到存储器中——例如,具有数百mb大小的未剪切mp3文件可能导致"错误">内存不足错误"-小心这一点。

安全警告:此文件绝对没有异常处理,仅用于教育目的

该代码将从实际目录加载私钥和公钥,mp3文件处理也将在该内存中进行。

输出短:

PHP OpenSSL RSA & AES CBC 256 hybrid encryption
encryption finished
decryption finished

以下是-注意限制和安全警告:

<?php
// hybrid encryption
// https://stackoverflow.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;
?>

我认为最好的方法是将文件转换为加密字节之后的字节,并在需要解密的地方解密

尝试:

如何将base64字符串转换为音频mp3文件?

然后使用php的OpenSSL函数对具有私钥和公钥的字符串(字节(文件进行加密和解密!我认为这是一个很好的资源:

https://www.geeksforgeeks.org/how-to-encrypt-and-decrypt-a-php-string/

最新更新