你如何encryption和解密一个PHPstring?
我的意思是:
Original String + Salt or Key --> Encrypted String Encrypted String + Salt or Key --> Decrypted (Original String)
也许是这样的:
"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for eg) "2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
- 在PHP中,你怎么能做到这一点?
试图使用Crypt_Blowfish
,但它不适合我。
在进一步做任何事情之前,请设法了解encryption和身份validation之间的区别 ,以及为什么您可能需要身份validation的encryption,而不仅仅是encryption 。
要实现经过身份validation的encryption,您需要对MACencryption。 encryption和authentication的顺序非常重要! 对这个问题的现有答案之一就犯了这个错误。 许多用PHP编写的encryption库也是如此。
你应该避免实现你自己的密码学 ,而是使用一个由encryption专家编写和审查的安全库。
如果您有PECL访问权限,请使用libsodium (如果您不想使用PECL,则使用sodium_compat ); 除此以外…
使用defuse / phpencryption ; 不要推出你自己的密码学!
上面链接的这两个库使得在您自己的库中实现经过身份validation的encryption变得简单而轻松。
如果你仍然想要编写和部署你自己的密码学库,那么与互联网上每一位密码专家的传统智慧相比,这些就是你必须采取的步骤。
encryption:
- 在CTR模式下使用AESencryption。 您也可以使用GCM(不需要单独的MAC)。 此外,ChaCha20和Salsa20(由libsodium提供)是stream密码,不需要特殊的模式。
- 除非你select上面的GCM,否则你应该用HMAC-SHA-256validation密文(或者对于stream密码,Poly1305 – 大多数libsodium APIs都是为你做的)。 MAC应该覆盖IV以及密文!
解密:
- 除非使用Poly1305或GCM,否则重新计算密文的MAC并将其与使用
hash_equals()
发送的MAC进行比较。 如果失败,则中止。 - 解密消息。
其他devise注意事项:
- 不要压缩任何东西。 密文不可压缩; 在encryption之前压缩明文会导致信息泄漏(例如TLS上的CRIME和BREACH)。
- 确保使用
mb_strlen()
和mb_substr()
,使用'8bit'
字符集模式来防止mbstring.func_overload
问题。 - IVs应该使用CSPRNG生成; 如果你使用
mcrypt_create_iv()
, 不要使用MCRYPT_RAND
!- 也检查出random_compat 。
- 除非你使用AEAD构造,否则总是encryptionMAC然后!
-
bin2hex()
,base64_encode()
等可能泄漏有关您的encryption密钥通过caching时间的信息。 如果可能的话避免它们。
即使你遵循这里给出的build议,很多密码学可能会出错。 总是有一个encryption专家审查你的实施。 如果您没有足够的资格成为当地大学的密码学学生的私人朋友,您可以随时尝试使用Cryptography Stack Exchange论坛获得build议。
如果您需要对您的实施进行专业分析,您可以随时聘请一支声誉良好的安全顾问团队来检查您的PHPencryption代码 (披露:我的雇主)。
重要:何时不使用encryption
不要encryption密码 。 你需要使用这些密码散列algorithm之一来对它们进行散列:
- Argon2
- scrypt
- bcrypt
- PBKDF2-SHA256重复86,000次
切勿使用通用散列函数(MD5,SHA256)进行密码存储。
不要encryptionURL参数 。 这是工作的错误工具。
带有Libsodium的PHPstringencryption示例
如果您没有安装libsodium,可以使用sodium_compat来完成相同的结果(虽然速度较慢)。
<?php // This requires the libsodium PECL extension /** * Encrypt a message * * @param string $message - message to encrypt * @param string $key - encryption key * @return string */ function safeEncrypt($message, $key) { $nonce = \Sodium\randombytes_buf( \Sodium\CRYPTO_SECRETBOX_NONCEBYTES ); $cipher = base64_encode( $nonce. \Sodium\crypto_secretbox( $message, $nonce, $key ) ); \Sodium\memzero($message); \Sodium\memzero($key); return $cipher; } /** * Decrypt a message * * @param string $encrypted - message encrypted with safeEncrypt() * @param string $key - encryption key * @return string */ function safeDecrypt($encrypted, $key) { $decoded = base64_decode($encrypted); $nonce = mb_substr($decoded, 0, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); $ciphertext = mb_substr($decoded, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); $plain = \Sodium\crypto_secretbox_open( $ciphertext, $nonce, $key ); \Sodium\memzero($ciphertext); \Sodium\memzero($key); return $plain; }
然后testing一下:
<?php // This refers to the previous code block. require "safeCrypto.php"; // Do this once then store it somehow: $key = \Sodium\randombytes_buf( \Sodium\CRYPTO_SECRETBOX_KEYBYTES ); $message = 'We are all living in a yellow submarine'; $ciphertext = safeEncrypt($message, $key); $plaintext = safeDecrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext);
Halite – Libsodium更容易
我一直在研究的项目之一是名为Halite的encryption库,旨在使libsodium更容易,更直观。
<?php use \ParagonIE\Halite\KeyFactory; use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto; // Generate a new random symmetric-key encryption key. You're going to want to store this: $key = new KeyFactory::generateEncryptionKey(); // To save your encryption key: KeyFactory::save($key, '/path/to/secret.key'); // To load it again: $loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key'); $message = 'We are all living in a yellow submarine'; $ciphertext = SymmetricCrypto::encrypt($message, $key); $plaintext = SymmetricCrypto::decrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext);
所有的底层encryption都由libsodium来处理。 显然,这意味着你需要PECL扩展来使用Halite。
示例与defuse / phpencryption
<?php /** * This requires https://github.com/defuse/php-encryption * php composer.phar require defuse/php-encryption * * Note that v2.0.0 is around the corner and this might need * to be edited when it's finally released. */ use \Defuse\Crypto\Crypto; require "vendor/autoload.php"; // Do this once then store it somehow: $key = Crypto::createNewRandomKey(); $message = 'We are all living in a yellow submarine'; $ciphertext = Crypto::encrypt($message, $key); $plaintext = Crypto::decrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext);
注意 : Crypto::encrypt()
返回原始的二进制文件,因此您可能需要使用base64_encode()
和base64_decode()
来存储/传输密文,以防止编码错误。 在版本2中,它将默认为hex编码输出。
encryption密钥pipe理
如果您想使用“密码”,请立即停止。 你需要一个随机的128位encryption密钥,而不是一个人类难忘的密码。
您可以存储一个长期使用的encryption密钥,如下所示:
$storeMe = bin2hex($key);
而且,根据需要,您可以像这样检索它:
$key = hex2bin($storeMe);
我强烈build议只保存一个随机生成的密钥长期使用,而不是任何types的密码作为密钥(或派生密钥)。
“但是我真的想用密码。”
这是一个坏主意,但没关系,这是如何安全地做到这一点。
首先,生成一个随机密钥并将其存储在一个常量中。
/** * Replace this with your own salt! * Use bin2hex() then add \x before every 2 hex characters, like so: */ define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");
请注意,你正在添加额外的工作,可以使用这个常量作为关键,并节省自己很多心痛!
然后使用PBKDF2(像这样)从密码派生出一个合适的encryption密钥,而不是直接用你的密码encryption。
/** * Get an AES key from a static password and a secret salt * * @param string $password Your weak password here * @param int $keysize Number of bytes in encryption key */ function getKeyFromPassword($password, $keysize = 16) { return hash_pbkdf2( 'sha256', $password, MY_PBKDF2_SALT, 100000, // Number of iterations $keysize, true ); }
不要只使用16个字符的密码。 您的encryption密钥将被打破。
什么不该做
警告:
这个答案使用ECB 。 ECB不是encryption模式,它只是一个构build模块。 使用这个答案中演示的ECB实际上并不安全地encryptionstring。 不要在代码中使用ECB。 见斯科特的答案是一个很好的解决scheme。
我自己做到了 其实我在google上find了一些答案,只是修改了一些东西。 但结果是完全不安全的。
<?php define("ENCRYPTION_KEY", "!@#$%^&*"); $string = "This is the original data string!"; echo $encrypted = encrypt($string, ENCRYPTION_KEY); echo "<br />"; echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY); /** * Returns an encrypted & utf8-encoded */ function encrypt($pure_string, $encryption_key) { $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv); return $encrypted_string; } /** * Returns decrypted original string */ function decrypt($encrypted_string, $encryption_key) { $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv); return $decrypted_string; } ?>
我迟到了,但正在寻找正确的方法来做到这一点,我遇到了这个页面,它是谷歌search的回报之一,所以我想分享我对这个问题的看法,我认为这是在写这篇文章(2017年初)时是最新的。 从PHP 7.1.0开始, mcrypt_decrypt
和mcrypt_encrypt
将被弃用,所以构build未来的certificate代码应该使用openssl_encrypt和openssl_decrypt
你可以做一些事情:
$string_to_encrypt="Test"; $password="password"; $encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password); $decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);
重要 :这使用ECB模式 ,这是不安全的。 如果你想要一个简单的解决scheme,而不需要在密码学工程的速成课程,不要自己写,只要使用一个库 。
您也可以使用任何其他削片方法,具体取决于您的安全需求。 要找出可用的削片器方法,请参阅openssl_get_cipher_methods函数。
对于Laravel框架
如果你使用的是Laravel框架,那么使用内部函数进行encryption和解密就更容易了。
$string = 'Some text to be encrypted'; $encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string); $decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted); var_dump($string); var_dump($encrypted); var_dump($decrypted_string);
注意:一定要在config / app.php文件的key选项中设置一个16,24或32个字符的随机string。 否则,encryption值将不安全。
历史注意:这是在PHP4时间写的。 这就是我们现在所说的“遗留代码”。
为了历史的目的,我留下了这个答案 – 但是现在已经废弃了一些方法,DESencryption方法不是一个推荐的做法,等等。
由于两个原因,我没有更新这个代码:1)我不再使用PHP中的encryption方法,2)这个代码仍然符合它的目的:演示encryption可以工作的最简单的概念在PHP中。
如果您发现一个类似简单的“PHPencryption傻瓜”,可以让人们开始使用10-20行代码或更less的代码,请在评论中告诉我。
除此之外,请享受这个早期PHP4简约encryption答案的经典情节。
理想情况下,你有 – 或可以获得 – 访问mcrypt PHP库,因为它当然stream行,非常有用的各种任务。 下面是不同types的encryption和一些示例代码: PHP中的encryption技术
//Listing 3: Encrypting Data Using the mcrypt_ecb Function <?php echo("<h3> Symmetric Encryption </h3>"); $key_value = "KEYVALUE"; $plain_text = "PLAINTEXT"; $encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); echo ("<p><b> Text after encryption : </b>"); echo ( $encrypted_text ); $decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); echo ("<p><b> Text after decryption : </b>"); echo ( $decrypted_text ); ?>
几个警告:
1)单向散列时,不要使用可逆或“对称”encryption。
2)如果数据是真实敏感的,如信用卡或社会安全号码,请停止; 你需要的不仅仅是任何简单的代码块,而是你需要一个专门为此目的而devise的encryption库,并且需要大量的时间来研究必要的方法。 此外,软件密码大概是敏感数据安全性的10%。 就像重新连接一个核电站一样 – 接受这个任务是危险和困难的,如果是这样的话,那你就不会知道了。 经济处罚可能是巨大的,所以更好地使用服务和运送责任。
3)这里列出的任何一种易于实施的encryption都可以合理地保护那些在意外/故意泄漏的情况下要防止窥探或限制暴露的轻度重要信息。 但是看到如何在Web服务器上以明文forms存储密钥,如果可以获取数据,则可以获得解密密钥。
就这样吧,玩得开心:)