> For the complete documentation index, see [llms.txt](https://ganymedenil.gitbook.io/php-7/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ganymedenil.gitbook.io/php-7/mo-kuai-yi/di-shi-er-zhang-ti-gao-wang-zhan-an-quan/bu-shi-yong-mcrypt-jin-hang-jia-mi-jie-mi.md).

# 不使用mcrypt进行加密/解密

在一般的 PHP 社区成员中，一个鲜为人知的事实是，作为大多数基于 PHP 的加密的核心的 `mcrypt` 扩展被认为是安全的，但它并不安全。从安全的角度来看，最大的问题之一是 `mcrypt` 扩展需要高级的密码学知识才能成功运行，而很少有程序员具备这些知识。这就导致了严重的误操作，最终导致数据损坏的几率为256分之一等问题。这可不是什么好机会。此外，开发人员对`libmcrypt`的支持，即`mcrypt`扩展所基于的核心库，已于2007年被放弃，这意味着代码库已经过时，错误百出，并且没有应用补丁的机制。因此，了解如何在不使用`mcrypt`的情况下进行强加密/解密是非常重要的。

## 如何做...

1.之前提出的问题的解决方案，如果你想知道，就是使用`openssl`。这个扩展维护得很好，并且具有现代的、非常强大的加密/解密功能。

{% hint style="danger" %}
为了使用任何`openssl*`函数，openssl PHP扩展必须被编译并启用！此外，你需要在你的Web服务器上安装最新的`OpenSSL`包。
{% endhint %}

2\. 首先，你需要确定你的安装中哪些密码方法是可用的。为此，您可以使用 `openssl_get_cipher_methods()` 命令。例子包括基于高级加密标准（AES）、BlowFish（BF）、CAMELLIA、CAST5、数据加密标准（DES）、Rivest密码（RC）（也被亲切地称为Ron's Code）和SEED的算法。你会注意到，这个方法显示的密码方法是大写和小写重复的。

3\. 接下来，你需要弄清楚哪种方法最适合你的需求。下面是一个表格，对各种方法进行了快速的总结。

| 方法         | 发布时间 | 密钥大小(bits)                   | 密钥块大小 (bytes) | 备注                                             |
| ---------- | ---- | ---------------------------- | ------------- | ---------------------------------------------- |
| `camellia` | 2000 | 128, 192, 256                | 16            | 由三菱和NTT共同开发                                    |
| `aes`      | 1998 | 128, 192, 256                | 16            | 由Joan Daemen和Vincent Rijmen开发。最初以Rijndael的名义提交 |
| `seed`     | 1998 | 128                          | 16            | 由韩国信息安全局开发                                     |
| `cast5`    | 1996 | 40-128                       | 8             | 由Carlisle Adams和Stafford Tavares开发             |
| `bf`       | 1993 | 1 - 448                      | 8             | 由Bruce Schneier设计                              |
| `rc2`      | 1987 | <p>8 - 1,024</p><p>默认 64</p> | 8             | 由Ron Rivest（RSA的核心创始人之一）设计                     |
| `des`      | 1977 | 56 (+8 奇偶校验位)                | 8             | 由IBM开发，基于Horst Feistel的工作                      |

4\. 另一个考虑因素是你喜欢的块密码操作模式是什么。常见的选择总结在这个表中。

| 模式  | 代表                                                       | 备注                                                                                                       |
| --- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| ECB | Electronic Code Book                                     | 不需要初始化向量(IV);加密和解密都支持并行化;简单快速;不隐藏数据模式;不推荐!!!                                                             |
| CBC | Cipher Block Chaining                                    | 需要IV；后续的块，即使是相同的，也会与前一个块进行XOR编辑，从而获得更好的整体加密效果；如果IV是可预测的，第一个块可以被解密，剩下的信息就会暴露出来；信息必须被填充到密码块大小的倍数；只支持解密的并行化 |
| CFB | Cipher Feedback                                          | CBC的近亲，只是加密方式是反向的                                                                                        |
| OFB | Output Feedback                                          | 非常对称：加密和解密相同；完全不支持并行化                                                                                    |
| CTR | Counter                                                  | 与OFB的操作类似；支持加密和解密的并行化                                                                                    |
| CCM | Counter with CBC-MAC                                     | CTR的衍生物；仅设计为128位的块长；提供认证和保密性；CBC-MAC代表密码块链-信息认证码                                                         |
| GCM | Galois/Counter Mode                                      | 基于CTR模式；应该对每个流使用不同的IV进行加密；特别高的吞吐量（与其他模式相比）；支持加密和解密的并行化                                                   |
| XTS | XEX-based Tweaked-codebook mode with ciphertext Stealing | 相对较新(2010年)且速度较快；使用两把钥匙；增加了可作为一个区块安全加密的数据量                                                               |

5\. 在选择加密方法和模式之前，你还需要确定加密的内容是否需要在你的PHP应用之外解密。例如，如果你是将数据库凭证加密存储到一个独立的文本文件中，你是否需要具备从命令行解密的能力？如果是这样，请确保你选择的加密方法和操作模式是目标操作系统所支持的。

6\. 为IV提供的字节数根据选择的密码方法而变化。为了得到最好的结果，可以使用 `random_bytes()`（PHP 7 中新增），它返回一个真正的 **CSPRNG** 字节序列。IV的长度有很大的不同。试着从16开始。如果产生警告，将显示该算法所需提供的正确字节数，因此要相应调整大小。

```php
$iv  = random_bytes(16);
```

7\. 要执行加密，使用`openssl_encrypt()`。以下是需要传递的参数。

| 参数       | 备注                                                                                                                                     |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Data     | 纯文本你需要加密的内容                                                                                                                            |
| Method   | 你用`openssl_get_cipher_methods()`确定的一个方法，确定如下。 方法 - key\_size - cipher\_mode 所以，举例来说，如果你想采用AES的方法，密钥大小为256，并采用GCM模式，你可以输入`aes-256-gcm`。 |
| Password | 虽然这个参数被记录为密码，但它可以被看作是一个密钥。使用`random_bytes()`来生成一个与所需密钥大小相匹配的字节数的密钥。                                                                    |
| Options  | 在你获得更多`openssl`加密经验之前，建议你坚持使用默认值0。                                                                                                     |
| IV       | 使用`random_bytes()`来生成一个具有与密码方法相匹配的字节数的IV。                                                                                              |

8\. 举个例子，假设你想选择AES加密方式，密钥大小为256，XTS模式。下面是用于加密的代码。

```php
$plainText = 'Super Secret Credentials';
$key = random_bytes(16);
$method = 'aes-256-xts';
$cipherText = openssl_encrypt($plainText, $method, $key, 0, $iv);
```

9\. 要解密，对`$key`和`$iv`使用相同的值，以及`openssl_decrypt()`函数。

```php
$plainText = openssl_decrypt($cipherText, $method, $key, 0, $iv);
```

## 如何运行...

为了查看可用的密码方法，创建一个名为`chap_12_openssl_encryption.php`的PHP脚本，然后运行这个命令。

```php
<?php
echo implode(', ', openssl_get_cipher_methods());
```

输出应该是这样的。

![](/files/-MPgsgZ-68h6ttLId92H)

接下来，可以为要加密的纯文本、方法、密钥和IV添加值。举个例子，试试使用XTS操作模式下的AES，密钥大小为256。

```php
$plainText = 'Super Secret Credentials';
$method = 'aes-256-xts';
$key = random_bytes(16);
$iv  = random_bytes(16);
```

要加密，你可以使用`openssl_encrypt()`，指定之前配置的参数。

```php
$cipherText = openssl_encrypt($plainText, $method, $key, 0, $iv);
```

你可能还想对结果进行base64编码，以使其更加可用。

```php
$cipherText = base64_encode($cipherText);
```

解密时，使用相同的`$key`和`$iv`值。不要忘了先解密base64值。

```php
$plainText = openssl_decrypt(base64_decode($cipherText), 
$method, $key, 0, $iv);
```

这里的输出显示的是base64编码的密码文本，然后是解密后的明文。

![](/files/-MPgtDT2_VfTbVvxBKFb)

如果你为IV提供的字节数不正确，对于所选择的密码方法，将显示一条警告信息。

![](/files/-MPgtGzuMGolXry3Hqlg)

## 更多...

在 PHP 7 中，当使用 `open_ssl_encrypt()` 和 `open_ssl_decrypt()` 以及所支持的认证数据加密 (AEAD) 模式时出现了一个问题——GCM 和 CCM。因此，在 PHP 7.1 中，这些函数增加了三个额外的参数，如下所示。

| 参数            | 备注                                           |
| ------------- | -------------------------------------------- |
| `$tag`        | 通过引用传递的认证标签；如果认证失败，变量值保持不变。                  |
| `$aad`        | 额外的认证数据                                      |
| `$tag_length` | GCM模式为4-16；CCM模式无限制；仅适用于open\_ssl\_encrypt() |

更多信息，您可以参考<https://wiki.php.net/rfc/openssl\\_aead。>

## 更多...

关于为什么在 PHP 7.1 中取消 mcrypt 扩展的优秀讨论，请参考 <https://wiki.php.net/rfc/mcrypt-viking-funeral> 的文章。关于构成各种加密方法基础的块加密的良好描述，请参考 <https://en.wikipedia.org/wiki/Block\\_cipher> 的文章。关于AES的优秀描述，请参考<https://en.wikipedia.org/wiki/Advanced\\_Encryption\\_Standard。关于描述加密操作模式的优秀文章，可以参考https://en.wikipedia.org/wiki/Block\\_cipher\\_mode\\_of\\_operation。>

{% hint style="info" %}
对于一些较新的模式，如果要加密的数据小于块大小，`openssl_decrypt()`将不返回任何值。如果你把数据填充到至少是块大小，问题就会消失。大多数的模式都实现了内部填充，所以这不是问题。对于一些较新的模式(即xts)，你可能会看到这个问题。在将你的代码投入生产之前，一定要对小于8个字符的短数据串进行测试。
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ganymedenil.gitbook.io/php-7/mo-kuai-yi/di-shi-er-zhang-ti-gao-wang-zhan-an-quan/bu-shi-yong-mcrypt-jin-hang-jia-mi-jie-mi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
