我的意思是:
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!"
尝试使用Crypt_Blowfish
,,但对我不起作用。
发布于 2019-07-29 16:15:43
已更新
PHP 7就绪版本。它使用PHP OpenSSL Library中的openssl_encrypt函数。
class Openssl_EncryptDecrypt {
function encrypt ($pure_string, $encryption_key) {
$cipher = 'AES-256-CBC';
$options = OPENSSL_RAW_DATA;
$hash_algo = 'sha256';
$sha2len = 32;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
$hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
return $iv.$hmac.$ciphertext_raw;
}
function decrypt ($encrypted_string, $encryption_key) {
$cipher = 'AES-256-CBC';
$options = OPENSSL_RAW_DATA;
$hash_algo = 'sha256';
$sha2len = 32;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($encrypted_string, 0, $ivlen);
$hmac = substr($encrypted_string, $ivlen, $sha2len);
$ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
$calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
if(function_exists('hash_equals')) {
if (hash_equals($hmac, $calcmac)) return $original_plaintext;
} else {
if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
}
}
/**
* (Optional)
* hash_equals() function polyfilling.
* PHP 5.6+ timing attack safe comparison
*/
function hash_equals_custom($knownString, $userString) {
if (function_exists('mb_strlen')) {
$kLen = mb_strlen($knownString, '8bit');
$uLen = mb_strlen($userString, '8bit');
} else {
$kLen = strlen($knownString);
$uLen = strlen($userString);
}
if ($kLen !== $uLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $kLen; $i++) {
$result |= (ord($knownString[$i]) ^ ord($userString[$i]));
}
return 0 === $result;
}
}
define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";
$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);
发布于 2015-05-11 11:12:21
在做进一步的工作之前,请先了解the difference between and ,以及为什么您可能需要经过身份验证的加密,而不只是加密。
要实现经过身份验证的加密,您需要先加密MAC。这个问题的现有答案之一The order of encryption and authentication is very important!犯了这个错误;许多用PHP语言编写的密码库也是如此。
您应该使用avoid implementing your own cryptography,而不是使用由密码学专家编写和审查的安全库。
更新:PHP7.2现在提供Update!为了获得最好的安全性,请将您的系统更新为使用PHP 7.2或更高版本,并且只遵循此答案中的higher建议。
(如果您想要不带PECL的without,则为 );否则...
;不要使用自己的加密技术!
上面链接的两个库都使得在您自己的库中实现经过身份验证的加密变得简单而轻松。
如果您仍然想要编写和部署您自己的密码库,而不是Internet上每个密码学专家的传统智慧,那么这些是您必须采取的步骤。
加密:
在CTR模式下使用AES进行
解密:
hash_equals()
发送的MAC进行比较。如果失败,则使用abort.其他设计注意事项:
mb_strlen()
和mb_substr()
,使用'8bit'
字符集模式来防止mbstring.func_overload
问题。除非您正在使用AEAD结构、
bin2hex()
,
即使你遵循了这里给出的建议,密码学也会出很多问题。总是有一位密码学专家审查你的实现。如果你不够幸运地和你当地大学的密码学学生成为私人朋友,你总是可以尝试Cryptography Stack Exchange论坛寻求建议。
如果你需要对你的实现进行专业的分析,你可以雇佣一个reputable team of security consultants to review your PHP cryptography code (披露:我的雇主)。
重要提示:何时不使用加密
切勿使用通用散列函数(MD5、SHA256)存储密码。
.这工具不适合这项工作。
使用String的PHP字符串加密示例
如果你使用的是PHP < 7.2或者没有安装slower,你可以使用sodium_compat来达到同样的效果(尽管速度较慢)。
<?php
declare(strict_types=1);
/**
* Encrypt a message
*
* @param string $message - message to encrypt
* @param string $key - encryption key
* @return string
* @throws RangeException
*/
function safeEncrypt(string $message, string $key): string
{
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new RangeException('Key is not the correct size (must be 32 bytes).');
}
$nonce = random_bytes(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
* @throws Exception
*/
function safeDecrypt(string $encrypted, string $key): string
{
$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
);
if (!is_string($plain)) {
throw new Exception('Invalid MAC');
}
sodium_memzero($ciphertext);
sodium_memzero($key);
return $plain;
}
然后进行测试:
<?php
// This refers to the previous code block.
require "safeCrypto.php";
// Do this once then store it somehow:
$key = random_bytes(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 -Halite变得更容易
我一直在做的一个项目是一个名为Halite的加密库,它旨在使library更容易和更直观。
<?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);
所有的底层加密都是由libsodium处理的。
使用defuse/php-encryption的示例
<?php
/**
* This requires https://github.com/defuse/php-encryption
* php composer.phar require defuse/php-encryption
*/
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;
require "vendor/autoload.php";
// Do this once then store it somehow:
$key = Key::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()
返回十六进制编码的输出。
加密密钥管理
如果你想使用“密码”,现在就停止吧。您需要一个随机的128位加密密钥,而不是人类难忘的密码。
您可以存储加密密钥以供长期使用,如下所示:
$storeMe = bin2hex($key);
并且,根据需要,您可以像这样检索它:
$key = hex2bin($storeMe);
我强烈建议只存储一个随机生成的密钥供长期使用,而不是将任何类型的密码作为密钥(或派生密钥)。
如果您使用的是Defuse的库:
“但我真的想使用密码。”
这不是一个好主意,但好吧,这里是如何安全地做它。
首先,生成一个随机密钥并将其存储在一个常量中。
/**
* 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 (如下所示)从您的密码派生合适的加密密钥,而不是直接使用您的密码进行加密。
/**
* 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个字符的密码。你的加密密钥会被滑稽地破解。
发布于 2017-01-13 06:24:22
我来晚了,但为了寻找正确的方法,我偶然发现了这个页面,它是谷歌搜索返回的顶级页面之一,所以我想分享我对这个问题的看法,我认为它在撰写这篇文章时(2017年初)是最新的。从PHP7.1.0开始,mcrypt_decrypt
和mcrypt_encrypt
将被弃用,因此构建未来的验证代码应该使用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 mode,这是不安全的。如果您想要一个简单的解决方案,而不需要参加密码工程的速成课程,那么不要自己编写,只需使用库即可。
根据您的安全需求,您还可以使用任何其他切片器方法。要找出可用的切片器方法,请参阅openssl_get_cipher_methods函数。
https://stackoverflow.com/questions/16600708
复制相似问题