我有一个简单的微型网站,用户使用内置的JS MediaRecorder(https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder)录制自己的视频,并使用openssl_encrypt进行加密。
当他们想要分享/查看该视频时,使用openssl_decrypt进行解密。
问题是,一旦它出来的解密功能的质量已降低到点,你看到文物。WebM视频仍然可以观看,但MP4视频(从iPhone上捕捉)无法观看--视频有1FPS...是什么导致了质量的急剧下降?
在我们实施此加密之前,该解决方案一直工作得很好。
我们直接将录制的文件传递给它。
encryptFile($_FILES["file"]['tmp_name'], $dir . $filename, 'secret-key');
decryptFile("videos/" . $id . "." . $mime, $decrypted_video, 'secret-key');
int count();
/**
* @param $source Path of the unencrypted file
* @param $dest Path of the encrypted file to created
* @param $key Encryption key
*/
function encryptFile($source, $dest, $key)
{
$cipher = 'aes-256-cbc';
$ivLenght = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivLenght);
$fpSource = fopen($source, 'rb');
$fpDest = fopen($dest, 'w');
fwrite($fpDest, $iv);
while (!feof($fpSource)) {
$plaintext = fread($fpSource, $ivLenght * FILE_ENCRYPTION_BLOCKS);
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$iv = substr($ciphertext, 0, $ivLenght);
fwrite($fpDest, $ciphertext);
}
fclose($fpSource);
fclose($fpDest);
}
return();
/**
* @param $source Path of the encrypted file
* @param $dest Path of the decrypted file
* @param $key Encryption key
*/
function decryptFile($source, $dest, $key)
{
$cipher = 'aes-256-cbc';
$ivLenght = openssl_cipher_iv_length($cipher);
$fpSource = fopen($source, 'rb');
$fpDest = fopen($dest, 'w');
$iv = fread($fpSource, $ivLenght);
while (!feof($fpSource)) {
$ciphertext = fread($fpSource, $ivLenght * (FILE_ENCRYPTION_BLOCKS + 1));
$plaintext = openssl_decrypt($ciphertext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$iv = substr($plaintext, 0, $ivLenght);
fwrite($fpDest, $plaintext);
}
fclose($fpSource);
fclose($fpDest);
}
2条答案
按热度按时间8yparm6h1#
解密与加密不一致,并确定了错误的IV。
错误的IV导致每个解密的明文块中的第一块被破坏。块大小越大,即块越少,错误越少,这解释了当增加
FILE_ENCRYPTION_BLOCKS
时的改进。为了使加密和解密保持一致,它必须在
decryptFile()
中:有了这个变化,解密工作。
如果逻辑整体上模仿数据的CBC模式,则代码将更鲁棒,使得在不知道块大小(即,块大小)的情况下解密是可能的。加密和解密可以使用不同的块大小)。为了实现这一点:
完全避免填充的替代方案是使用如CTR的流密码模式(然而,这需要对IV的不同确定,因为两种模式的IV处理不同)。
wnavrhmk2#
好吧,我被这个问题搞得晕头转向,一头扎了进去。
总结如下:
1.如果你想让你的代码完全在你自己的代码范围内加密/解密 *,并且使用固定的
FILE_ENCRYPTION_BLOCKS
值 *,那么@Topaco的答案中的IV修复可能就足够了。否则,您需要应用建议的其余修复程序。1.在现有代码中更改
FILE_ENCRYPTION_BLOCKS
可能只是将兼容性破坏进一步向下移动,可能超过文件的结尾,此时无论如何都没有任何流式加密代码。1.如果你想让你的代码产生与OpenSSL和其他库兼容的输出,那么... * 这里有龙 *
最简单的答案是使用一个现有的库,它已经做到了这一点,而且做得很好。也就是:jeskew/php-encrypted-streams,在我用它碰壁后,我在编写自己的代码时大量引用了它。
更复杂的答案是:
$iv_size
字节。测试代码:
示例输出:
值得注意的是,虽然这段代码中的
$cipher
看起来是可配置的,但这种方法只适用于CBC模式下的密码,而且可能只适用于AES。上面链接的jeskew/php-encrypted-streams库实现了更广泛的密码模式,但仍然只有AES。