PHP 中 AES
加密和解密的原理主要基于对称加密算法。对称加密算法使用相同的密钥进行加密和解密操作,常见的对称加密算法包括 AES
、DES
、3DES
等。
AES 加密解密原理
在 PHP 中,你可以使用 OpenSSL
扩展来实现 AES
加密和解密。AES
加密算法采用分组密码的方式,将明文分成固定长度的数据块,然后对每个数据块使用相同的密钥进行加密。解密时使用相同的密钥对密文进行解密,还原出原始的明文。
具体的加密和解密过程如下:
加密过程
- 选择一个合适的密钥,长度可以是 128 位、192 位或 256 位。
- 选择一个合适的初始化向量(
IV
),长度为 16 字节(128 位)。 - 将明文分成固定长度的数据块,每个数据块的长度与密钥长度相同(128 位)。
- 使用密钥对每个数据块进行加密,生成相应的密文。
- 可以选择使用
padding
方式对明文进行补齐,以确保明文的长度符合要求。常见的padding
方式有PKCS7
、PKCS5
等。 - 将加密后的数据块和初始化向量进行合并,生成最终的密文。
解密过程:
- 获取加密过程中使用的密钥和初始化向量。
- 将密文分成固定长度的数据块,每个数据块的长度与密钥长度相同(128 位)。
- 使用相同的密钥对每个数据块进行解密,还原出相应的明文。
- 可以选择使用相同的
padding
方式对解密后的数据进行处理,以确保还原的明文符合要求。 - 将解密后的数据块和初始化向量进行合并,生成最终的明文。
需要注意的是,在实际应用中,为了确保数据的安全性,通常会在传输过程中对数据进行加密,并在接收端进行解密。同时,为了防止重复攻击和篡改攻击,还需要对数据进行校验和签名等操作。
示例
1. 创建合适的密钥
对于这个,我们可以生成一个随机字符串,长度为 32 字节就行(也就是 256 位),下面是一个例子:
function randomStr($length = 32)
{
// 随机数种子
mt_srand(microtime(true) * 1000000);
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
在这个例子中,我们默认生成 32 字节的字符串,当然 AES 也支持 16 字节的,根据我们需要去选择即可。
注意:在我们的应用中,不需要每次调用加密解密函数都去生成一个新的密钥。而是在整个应用的生命周期中,只使用同一个密钥。除非我们的密钥泄漏了,才需要去更换。
因为密钥需要用来加密,但是也需要使用同一个密钥来进行解密。
2. 加密
下面是一个加密的函数:
// 加密函数
public static function encrypt($key, $data): string
{
$ivLength = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($ivLength);
$encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encryptedData);
}
过程如下:
- 使用
openssl_cipher_iv_length
获取AES-256-CBC
模式下的初始向量(IV
)长度。 - 使用
openssl_random_pseudo_bytes
生成随机的初始向量$iv
。 - 使用
openssl_encrypt
对数据进行AES-256-CBC
模式的加密,使用密钥$key
和初始向量$iv
。 - 最后,将初始向量和加密后的数据拼接在一起,并使用
base64_encode
对结果进行Base64
编码,返回最终的加密字符串。
注意:
openssl_encrypt
得到的是二进制数据,我们一般需要进行base64
转换为字节流来进行传输。
3. 解密
下面是一个解密的函数:
// 解密函数
public static function decrypt($key, $encryptedData)
{
$data = base64_decode($encryptedData);
$ivLength = openssl_cipher_iv_length('AES-256-CBC');
$iv = substr($data, 0, $ivLength);
$encryptedData = substr($data, $ivLength);
return openssl_decrypt($encryptedData, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
}
过程如下:
- 使用
base64_decode
对加密后的字符串进行Base64
解码,得到包含初始向量和加密数据的二进制字符串$data
。 - 使用
openssl_cipher_iv_length
获取AES-256-CBC
模式下的初始向量(IV
)长度。 - 使用
substr
将初始向量$iv
和加密数据$encryptedData
分别截取出来。 - 使用
openssl_decrypt
对加密数据进行AES-256-CBC
模式的解密,使用密钥$key
和初始向量$iv
。 - 最终,返回解密后的原始数据。
完整代码如下:
class Aes
{
// 加密函数
public static function encrypt($key, $data): string
{
$ivLength = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($ivLength);
$encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encryptedData);
}
// 解密函数
public static function decrypt($key, $encryptedData)
{
$data = base64_decode($encryptedData);
$ivLength = openssl_cipher_iv_length('AES-256-CBC');
$iv = substr($data, 0, $ivLength);
$encryptedData = substr($data, $ivLength);
return openssl_decrypt($encryptedData, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
}
}
iv 的作用是什么?
我们在上面的代码中看到了有个叫 iv
的东西,那它是什么呢?到底有什么作用呢?
IV
(Initialization Vector
,初始化向量)是在对称加密算法中使用的一种辅助输入,主要作用是增加密码算法的强度和安全性。
在 AES
加密中,IV
是一个随机生成的固定长度的二进制串,通常与密钥一起用于初始化加密算法。每次使用相同密钥进行加密时,可以使用不同的 IV
。IV
的主要作用包括:
破解抵抗性: 在相同的密钥下,使用不同的
IV
加密相同的明文,可以产生不同的密文。这使得攻击者难以分析并找到明文和密文之间的模式。如果每次加密都使用相同的IV
,那么相同的明文会产生相同的密文,这样就容易受到攻击。防止密码分析: 使用不同的
IV
可以避免在密码分析中出现的一些问题,比如对相同明文的多次加密产生相同的密文。IV
的引入使得相同明文在不同的加密操作中产生不同的密文。增加密码强度:
IV
的随机性和不可预测性有助于增加密码算法的强度。攻击者无法通过事先知道的信息来预测IV
的值,从而增加了密码的安全性。
总的来说,IV
的引入有助于防止对称加密算法中的一些攻击,并提高密码算法的安全性。在实际应用中,IV
的生成应当是随机的且不可预测的,以达到最佳的安全效果。
总结
上述 PHP 代码演示了在 PHP 中使用 AES
加密和解密的原理。AES
是一种对称加密算法,使用相同的密钥进行加密和解密。在 PHP 中,使用 OpenSSL
扩展实现了 AES
加密和解密。
AES
加密的原理包括选择合适的密钥和初始化向量(IV
),将明文分成数据块,使用密钥和 IV
对每个数据块进行加密,最后合并成最终的密文。解密则是相反的过程,使用相同的密钥和 IV 对密文进行解密,还原出原始的明文。
示例代码中还包括了生成随机密钥和加密解密函数的实现。密钥的安全性对于加密算法的安全至关重要,因此建议在实际应用中采用足够安全的方法生成和管理密钥。
最后,解释了初始化向量(IV
)的作用,它在对称加密中用于增加算法的强度和安全性,防止密码分析和提高密码强度。 IV
的生成应当是随机的和不可预测的,以提高安全性。