PHP-改进文件加密
免责声明:英语不是我的母语,所以如果有什么不清楚的地方,请随时询问 你好 一旦文件上传到服务器上,我就必须使用AES对其进行加密,并通过邮件将解密所需的密钥发送到客户端(而不是将其存储在服务器端的任何位置)。文件大小可达2GB,上传7天后会被删除 下面是我用来加密/解密文件的内容:PHP-改进文件加密,php,encryption,cryptography,Php,Encryption,Cryptography,免责声明:英语不是我的母语,所以如果有什么不清楚的地方,请随时询问 你好 一旦文件上传到服务器上,我就必须使用AES对其进行加密,并通过邮件将解密所需的密钥发送到客户端(而不是将其存储在服务器端的任何位置)。文件大小可达2GB,上传7天后会被删除 下面是我用来加密/解密文件的内容: function encrypt_file($source, $destination, $key) { $iv = md5("\x1B\x3C\x58".$key, true); $ivsize =
function encrypt_file($source, $destination, $key) {
$iv = md5("\x1B\x3C\x58".$key, true);
$ivsize = openssl_cipher_iv_length('aes-256-cbc');
$fp = fopen($destination, 'wb') or die("Could not open file for writing.");
$handle = fopen($source, "rb");
while (!feof($handle)) {
$e = 0;
$contents = fread($handle, 4 * 1024 * 1024);
$ciphertext = openssl_encrypt($contents, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
$iv = substr($ciphertext, -$ivsize);
while (!fwrite($fp, $ciphertext)) {
$e++;
if ($e == 5) {
die("Couldn't write to file.");
break 2;
}
}
}
fclose($handle);
fclose($fp);
}
function streamdecrypt_file($source, $key) {
$iv = md5("\x1B\x3C\x58".$key, true);
$ivsize = openssl_cipher_iv_length('aes-256-cbc');
$handle = fopen($source, "rb");
while (!feof($handle)) {
$contents = fread($handle, 4 * 1024 * 1024);
$raw = openssl_decrypt($contents, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
$iv = substr($contents, -$ivsize);
print $raw; // Printing because it's directly sent to the user to download
}
fclose($handle);
}
如果你想知道为什么4*1024*1024
这就是我得到最快加密的缓冲区大小。我的实现使用这里提出的模式
我还使用以下两个小函数使用密码短语将字符串加密到文件中:
function encrypt_string($source, $destination, $passphrase) {
$iv = md5("\x1B\x3C\x58".$passphrase, true);
$key = md5("\x2D\xFC\xD8".$passphrase, true);
$ciphertext = openssl_encrypt($source, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
$fp = fopen($destination, 'wb') or die("Could not open file for writing.");
fwrite($fp, $ciphertext) or die("Could not write to file.");
fclose($fp);
}
function decrypt_string($source, $passphrase) {
$iv = md5("\x1B\x3C\x58".$passphrase, true);
$key = md5("\x2D\xFC\xD8".$passphrase, true);
$contents = file_get_contents($source);
return openssl_decrypt($contents, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}
以下是上传完成后我最终要做的事情:
$skey = /* 32 chars random generated string [a-Z0-9]*/
$ukey = /* 10 chars random generated string [a-Z0-9]*/
encrypt_file($originalFile, $encryptedFile, $skey);
encrypt_string($skey, $encryptedKey, $ukey);
然后,我删除原始文件并通过邮件向用户发送包含$ukey
的链接
当他们想要解密文件以下载它时,我首先使用$ukey
对包含$skey
的文件进行解密,检查我是否最终得到一个由[a-Z0-9]组成的32字符256位长的字符串。如果$skey
与regexp不匹配,我知道$ukey
无效,所以我就到此为止
我这样做是为了不必解密文件来检查密钥是否正确
现在,我希望我的问题符合以下要求:
- 我做得对吗
- 有什么可以/应该改进的吗
- 加密2GB文件大约需要60秒,这是“确定”结果吗
- 够好吗?其目的是防止攻击者访问服务器,同时也可以访问已存储的用户文件。我知道他将能够修改代码并访问以下上传,但这应该可以保护已经存储的文件,对吗?我做得太多了吗
谢谢你的回答 对于IV,使用随机字节 对于密码扩展,使用或等效;推导速度需要慢一些 将键限制在字符[a-Z0-9]上,256键基本上减少到36字节。这不是很安全。您至少需要128位的关键材料
您需要更好的方法来验证用户密码。对于IV,请使用随机字节 对于密码扩展,使用或等效;推导速度需要慢一些 将密钥限制为字符[a-Z0-9]会将256个密钥减少到36个字节。这不是很安全。您至少需要128位的关键材料
您需要一种更好的方法来验证用户密码。由于这个问题更多的是一个代码检查而不是一个特定的问题,因此我建议将其移动到您不指定执行加密的系统,该加密需要60秒/4GB。iPhone6s可以加密400MB/s,我的笔记本电脑可以加密150MB/s。对于使用密码扩展或等效密码,推导速度需要较慢。@MatthewHerbst在引用其他站点时,指出这个问题更像是代码审查而不是特定问题通常是有帮助的,我建议将其移动到您不指定执行加密的系统,这需要60s/4GB。iPhone6s可以加密400MB/s,我的笔记本电脑可以加密150MB/s。对于使用密码扩展或等效的方法,推导速度需要慢一些。@MatthewHerbst在引用其他网站时,指出感谢您的回答是很有帮助的,尽管有一部分我不明白。如果我从[a-Z0-9]中选择一个32个字符长的字符串,这难道不意味着有36^32个可能性,即使低于2^256,也高于2^128吗?(我不太擅长加密或数学,所以我很确定我错了,但我看不出有什么错)关于PBKDF2,我没有访问PHP5.5+,我发现许多不同的低版本实现,不确定选择哪个。你有机会得到推荐吗?或者我可以使用吗?你的任务是实现一个自制的加密协议,而他们甚至不允许你使用PHP的安全版本?WTF:任何人,从最无知的业余爱好者到最优秀的密码学家,都可以创建一个他自己无法破解的算法。@ScottArciszewski:我刚刚听说他们正在迁移这个项目,我将开始使用PHP5.6.17,好消息。扎夫,我没有收到你的报价。。。我并不是说我做了一些安全和牢不可破的东西,否则我不会在那里问它。。。(我是不是误解了你的评论?)。如果我从[a-Z0-9]中选择一个32个字符长的字符串,这难道不意味着有36^32个可能性,即使低于2^256,也高于2^128吗?(我不太擅长加密或数学,所以我很确定我错了,但我看不出有什么错)关于PBKDF2,我没有访问PHP5.5+,我发现许多不同的低版本实现,不确定选择哪个。你有机会得到推荐吗?或者我可以使用吗?你的任务是实现一个自制的加密协议,而他们甚至不允许你使用PHP的安全版本?WTF:任何人,从最无知的业余爱好者到最优秀的密码学家,都可以创建一个他自己无法破解的算法。@ScottArciszewski:我刚刚听说他们正在迁移这个项目,我将开始使用PHP5.6.17,好消息。扎夫,我没有收到你的报价。。。我并不是说我做了一些安全和牢不可破的东西,否则我不会在那里问它。。。(我是不是误解了你的评论?)