你如何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:

  1. 在CTR模式下使用AESencryption。 您也可以使用GCM(不需要单独的MAC)。 此外,ChaCha20和Salsa20(由libsodium提供)是stream密码,不需要特殊的模式。
  2. 除非你select上面的GCM,否则你应该用HMAC-SHA-256validation密文(或者对于stream密码,Poly1305 – 大多数libsodium APIs都是为你做的)。 MAC应该覆盖IV以及密文!

解密:

  1. 除非使用Poly1305或GCM,否则重新计算密文的MAC并将其与使用hash_equals()发送的MAC进行比较。 如果失败,则中止。
  2. 解密消息。

其他devise注意事项:

  1. 不要压缩任何东西。 密文不可压缩; 在encryption之前压缩明文会导致信息泄漏(例如TLS上的CRIME和BREACH)。
  2. 确保使用mb_strlen()mb_substr() ,使用'8bit'字符集模式来防止mbstring.func_overload问题。
  3. IVs应该使用CSPRNG生成; 如果你使用mcrypt_create_iv()不要使用MCRYPT_RAND
    • 也检查出random_compat 。
  4. 除非你使用AEAD构造,否则总是encryptionMAC然后!
  5. 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_decryptmcrypt_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存储密钥,如果可以获取数据,则可以获得解密密钥。

就这样吧,玩得开心:)