我的意思是:
Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)
也许是这样的:
"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
- 在PHP中,你怎么做?
试图使用 Crypt_Blowfish ,但它对我不起作用 .
6 回答
在您进一步做之前,请了解the difference between encryption and authentication,以及为什么您可能需要经过身份验证的加密而不仅仅是加密 .
要实现经过身份验证的加密,您需要加密然后MAC . The order of encryption and authentication is very important!这个问题的现有答案之一造成了这个错误;就像许多用PHP编写的加密库一样 .
您应该使用avoid implementing your own cryptography,而是使用由加密专家编写和审核的安全库 .
Use libsodium if you have PECL access (or sodium_compat if you want libsodium without PECL); otherwise...
Use defuse/php-encryption; don't roll your own cryptography!
上面链接的两个库使得在您自己的库中实现经过身份验证的加密变得轻松而轻松 .
如果您仍然希望编写和部署自己的加密库,而不是互联网上每个加密专家的传统智慧,那么这些步骤就是您必须采取的步骤 .
加密:
在CTR模式下使用AES进行加密 . 您也可以使用GCM(不需要单独的MAC) . 此外,ChaCha20和Salsa20(由libsodium提供)是流密码,不需要特殊模式 .
除非您选择上面的GCM,否则您应该使用HMAC-SHA-256对密文进行身份验证(或者,对于流密码,Poly1305 - 大多数libsodium API都会为您执行此操作) . The MAC should cover the IV as well as the ciphertext!
解密:
除非使用Poly1305或GCM,否则重新计算密文的MAC并将其与使用hash_equals()发送的MAC进行比较 . 如果失败,则中止 .
解密消息 .
其他设计考虑因素:
不要压缩任何东西 . 密文不可压缩;在加密之前压缩明文可能导致信息泄露(例如,TLS上的CRIME和BREACH) .
确保使用
mb_strlen()
和mb_substr()
,使用'8bit'
字符集模式来防止mbstring.func_overload
问题 .IVs应该使用CSPRNG生成;如果你正在使用
mcrypt_create_iv()
, DO NOT USE MCRYPT_RAND !另请查看random_compat .
除非您使用的是AEAD构造,否则ALWAYS encrypt then MAC!
bin2hex()
,base64_encode()
等可能会通过缓存时序泄漏有关加密密钥的信息 . 尽可能避免使用它们 .即使你遵循这里给出的建议,密码学也会出现很多问题 . Always have a cryptography expert review your implementation. 如果您不幸与当地大学的密码学生成为私人朋友,您可以随时到Cryptography Stack Exchange论坛寻求建议 .
如果您需要对您的实施进行专业分析,您可以随时雇用reputable team of security consultants to review your PHP cryptography code(披露:我的雇主) .
重要:何时不使用加密
Don't encrypt passwords . 您希望使用以下密码散列算法之一来散列它们:
Argon2
scrypt
bcrypt
PBKDF2-SHA256 with 86,000 iterations
切勿使用通用散列函数(MD5,SHA256)进行密码存储 .
Don't encrypt URL Parameters. 这是工作的错误工具 .
使用Libsodium的PHP字符串加密示例
如果你使用PHP <7.2或者没有安装libsodium,你可以使用sodium_compat来完成相同的结果(尽管速度较慢) .
然后测试一下:
Halite - Libsodium变得更容易
我一直在研究的项目之一是名为Halite的加密库,旨在使libsodium更容易,更直观 .
所有底层加密都由libsodium处理 .
使用defuse / php-encryption的示例
Note :
Crypto::encrypt()
返回十六进制编码输出 .加密密钥管理
如果您想使用“密码”,请立即停止 . 您需要一个随机的128位加密密钥,而不是一个人类难忘的密码 .
您可以存储加密密钥以供长期使用,如下所示:
并且,根据需要,您可以像这样检索它:
我建议只是存储随机生成的密钥以供长期使用,而不是任何类型的密码作为密钥(或导出密钥) .
如果您正在使用Defuse的库:
$string = $keyObject->saveToAsciiSafeString()
$loaded = Key::loadFromAsciiSafeString($string);
“但我真的想用密码 . ”
这是一个坏主意,但没关系,这是如何安全地做到这一点 .
首先,生成一个随机密钥并将其存储在常量中 .
请注意,您正在添加额外的工作,并且可以只需使用此常量作为键,为自己节省很多心痛!
然后使用PBKDF2(如此)从您的密码中导出合适的加密密钥,而不是直接使用您的密码加密 .
不要只使用16个字符的密码 . 您的加密密钥将被巧妙地破坏 .
What not to do
我得到了自己 . 实际上我在谷歌找到了一些答案,只是修改了一些东西 . The result is completely insecure however.
我迟到了,但是找到了正确的方法,我遇到了这个页面,它是谷歌搜索的最高回报之一,所以我想分享一下我对这个问题的看法,我认为这个问题是撰写本文时(2017年初)的最新信息 . 从PHP 7.1.0开始,
mcrypt_decrypt
和mcrypt_encrypt
将被弃用,因此构建未来验证代码应该使用openssl_encrypt和openssl_decrypt你可以这样做:
您也可以使用任何其他削片机方法,具体取决于您的安全需求 . 要了解可用的削片机方法,请参阅openssl_get_cipher_methods功能 .
对于Laravel框架
如果您使用的是Laravel框架,那么使用内部函数加密和解密会更容易 .
我把这个答案留给了历史目的 - 但现在有些方法已被弃用,DES加密方法不是推荐的做法,等等 .
我没有更新此代码有两个原因:1)我不再使用PHP手工加密方法,2)此代码仍然用于其目的:展示加密如何工作的最小,简单概念用PHP .
如果您发现类似的简单,“PHP加密傻瓜”类型的源代码可以让人们开始使用10到20行或更少的代码,请在评论中告诉我 .
除此之外,请享受早期PHP4简约加密答案的经典剧集 .
理想情况下,您可以 - 或者可以获得 - 访问mcrypt PHP库,因为它肯定很受欢迎且非常有用 . 以下是不同种类的加密和一些示例代码:Encryption Techniques in PHP
一些警告:
1)当单向散列执行时,切勿使用可逆或“对称”加密 .
2)如果数据真正敏感,如信用卡或社会安全号码,请停止;你需要的不仅仅是任何简单的代码块,而是需要一个专为此目的而设计的加密库,并且需要大量的时间来研究必要的方法 . 此外,软件加密可能是敏感数据安全性的10% . 这就像重新布线核电站 - 接受任务是危险和困难的,并且如果是这样的话,超出了你的知识范围 . 经济处罚可能是巨大的,因此最好使用服务并将责任运送给他们 .
3)如此处所列,任何类型的易于实施的加密都可以合理地保护您想要避免的轻微重要信息,以防止在意外/故意泄漏的情况下窥探或限制暴露 . 但是看看密钥是如何以纯文本形式存储在Web服务器上的,如果他们可以获取数据,他们就可以获得解密密钥 .
尽管如此,玩得开心:)
如果你不想使用库(你应该),那么使用这样的东西(PHP 7):