900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > php 固定长度加密解密 如何加密/解密数据在PHP?

php 固定长度加密解密 如何加密/解密数据在PHP?

时间:2024-05-16 14:11:56

相关推荐

php 固定长度加密解密 如何加密/解密数据在PHP?

前言

从您的表定义开始:

- UserID

- Fname

- Lname

- Email

- Password

- IV

这里是更改:

>字段Fname,Lname和Email将使用由OpenSSL提供的对称密码加密,

> IV字段将存储用于加密的initialisation vector。存储要求取决于使用的密码和模式;更多关于这一点。

>密码字段将使用单向密码哈希哈希,

加密

密码和模式

选择最好的加密密码和模式超出了这个答案的范围,但最终的选择影响加密密钥和初始化向量的大小;对于这个帖子,我们将使用AES-256-CBC,其具有16字节的固定块大小和16,24或32字节的密钥大小。

加密密钥

良好的加密密钥是由可靠的随机数生成器生成的二进制Blob。将推荐以下示例(> = 5.3):

$key_size = 32; // 256 bits

$encryption_key = openssl_random_pseudo_bytes($key_size, $strong);

// $strong will be true if the key is crypto safe

这可以执行一次或多次(如果您希望创建一系列加密密钥)。保持这些尽可能私人。

IV

初始化向量将加密的随机性和CBC模式所需的。理想情况下,这些值应仅使用一次(技术上每个加密密钥一次),因此对行的任何部分的更新都应重新生成它。

提供了一个功能来帮助您生成IV:

$iv_size = 16; // 128 bits

$iv = openssl_random_pseudo_bytes($iv_size, $strong);

让我们使用早期的$ encryption_key和$ iv加密name字段;要做到这一点,我们必须填补我们的数据块大小:

function pkcs7_pad($data, $size)

{

$length = $size - strlen($data) % $size;

return $data . str_repeat(chr($length), $length);

}

$name = 'Jack';

$enc_name = openssl_encrypt(

pkcs7_pad($name, 16), // padded data

'AES-256-CBC', // cipher and mode

$encryption_key, // secret key

0, // options (not used)

$iv // initialisation vector

);

存储要求

加密的输出,如IV,是二进制;将这些值存储在数据库中可以通过使用诸如BINARY或VARBINARY之类的指定列类型来实现。

输出值,如IV,是二进制;要在MySQL中存储这些值,请考虑使用BINARY or VARBINARY列。如果这不是一个选项,您还可以使用base64_encode()或bin2hex()将二进制数据转换为文本表示,这样做需要33%到100%的存储空间。

解密

存储值的解密类似:

function pkcs7_unpad($data)

{

return substr($data, 0, -ord($data[strlen($data) - 1]));

}

$row = $result->fetch(PDO::FETCH_ASSOC); // read from database result

// $enc_name = base64_decode($row['Name']);

// $enc_name = hex2bin($row['Name']);

$enc_name = $row['Name'];

// $iv = base64_decode($row['IV']);

// $iv = hex2bin($row['IV']);

$iv = $row['IV'];

$name = pkcs7_unpad(openssl_decrypt(

$enc_name,

'AES-256-CBC',

$encryption_key,

0,

$iv

));

验证加密

您可以通过附加从密钥(不同于加密密钥)和密文生成的签名来进一步提高生成的密文的完整性。在密文被解密之前,首先验证签名(优选地使用恒定时间比较方法)。

// generate once, keep safe

$auth_key = openssl_random_pseudo_bytes(32, $strong);

// authentication

$auth = hash_hmac('sha256', $enc_name, $auth_key, true);

$auth_enc_name = $auth . $enc_name;

// verification

$auth = substr($auth_enc_name, 0, 32);

$enc_name = substr($auth_enc_name, 32);

$actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);

if (hash_equals($auth, $actual_auth)) {

// perform decryption

}

散列

必须尽可能避免在数据库中存储可逆密码;您只希望验证密码,而不是知道其内容。如果用户丢失密码,最好允许他们重置密码,而不是向他们发送密码(确保密码重置只能在有限的时间内完成)。

应用散列函数是一种单向操作;之后可以安全地用于验证而不暴露原始数据;对于密码,强力方法是一个可行的方法来揭开它,由于其相对较短的长度和很多人的密码选择差。

进行诸如MD5或SHA1的哈希算法以相对于已知的哈希值来验证文件内容。他们经过了极大的优化,可以尽可能快地完成验证,同时仍然准确无误。给定它们相对有限的输出空间,很容易建立一个已知密码和它们各自的哈希输出,彩虹表的数据库。

在对密码进行哈希处理之前添加一个盐将会使一张彩虹表无用,但最近的硬件进步使得强制查找成为可行的方法。这就是为什么你需要一个哈希算法,故意慢,根本不可能优化。它还应该能够增加更快速硬件的负载,而不影响验证现有密码散列以使其未来证明的能力。

目前有两种流行的选择:

> PBKDF2(基于密码的密钥导出功能v2)

> bcrypt(aka河豚)

这个答案将使用一个bcrypt的例子。

密码哈希可以这样生成:

$password = 'my password';

$random = openssl_random_pseudo_bytes(18);

$salt = sprintf('$2y$%02d$%s',

13, // 2^n cost factor

substr(strtr(base64_encode($random), '+', '.'), 0, 22)

);

$hash = crypt($password, $salt);

盐用openssl_random_pseudo_bytes()生成以形成随机数据块,然后通过base64_encode()和strtr()运行以匹配所需的字母表[A-Za-z0-9 /。]。

crypt()函数基于算法(Blowfish的$ 2y $)执行散列,成本因子(在3GHz机器上大约为0.40s的因子为13)和22个字符的盐。

验证

一旦您提取了包含用户信息的行,您将以这种方式验证密码:

$given_password = $_POST['password']; // the submitted password

$db_hash = $row['Password']; // field with the password hash

$given_hash = crypt($given_password, $db_hash);

if (isEqual($given_hash, $db_hash)) {

// user password verified

}

// constant time string compare

function isEqual($str1, $str2)

{

$n1 = strlen($str1);

if (strlen($str2) != $n1) {

return false;

}

for ($i = 0, $diff = 0; $i != $n1; ++$i) {

$diff |= ord($str1[$i]) ^ ord($str2[$i]);

}

return !$diff;

}

要验证密码,请再次调用crypt(),但是将之前计算的哈希值作为salt值传递。如果给定的密码与散列匹配,则返回值产生相同的散列。为了验证哈希,通常建议使用常数时间比较函数来避免定时攻击。

密码散列与PHP 5.5

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);

并验证:

if (password_verify($given_password, $db_hash)) {

// password valid

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。