SubtleCrypto
============

**安全上下文:** 此项功能仅在一些支持的浏览器的安全上下文（HTTPS）中可用。

Web Crypto API 的 **`SubtleCrypto`** 接口提供了许多底层加密函数。你可以通过 `crypto` 属性提供的 `Crypto` 对象中的 `subtle` 属性来访问 `SubtleCrypto` 的相关特性。

**警告：** 此 API 提供了许多底层密码学原语。滥用它们很容易陷入微妙的陷阱中。

即使你正确地运用了基础加密方法，也很难设计一套正确的安全密钥管理及整体安全设计方案，这些往往是安全专家所做的事情。

错误的安全系统设计和实现会使系统的安全性完全失效。

你可以学习并进行实验，但我们并不能保证这些内容的安全性，最好有熟悉该领域的人对你的相关工作进行彻底的审查以保证其安全性。如果你要学习安全系统的设计和部署，可以学习 Crypto 101 课程。

实例属性
----

*此接口没有任何父接口，因此没有继承任何属性。*

实例方法
----

*此接口没有任何父接口，因此没有继承任何方法。*

`SubtleCrypto.encrypt()`

返回一个 `Promise`，会兑现与参数中给定的明文、算法和密钥对应的密文。

`SubtleCrypto.decrypt()`

返回一个 `Promise`，会兑现与参数中给定的密文、算法和密钥对应的明文。

`SubtleCrypto.sign()`

返回一个 `Promise`，会兑现与参数中给定的文本、算法和密钥对应的签名。

`SubtleCrypto.verify()`

返回一个 `Promise`，会兑现一个布尔值，表示参数中给定的签名是否与文本、密钥和算法对应的签名相匹配。

`SubtleCrypto.digest()`

返回一个 `Promise`，会兑现通过参数中给定的算法和文本生成的摘要。

`SubtleCrypto.generateKey()`

返回一个 `Promise`，会兑现一个新生成的密钥（用于对称加密算法）或密钥对 (en-US)（用于非对称加密算法）。它们与通过参数给定的算法、用法和可导出性相对应。

`SubtleCrypto.deriveKey()`

返回一个 `Promise`，会兑现一个新生成的、从主密钥（以过参数给定的算法）派生出来的密钥。

`SubtleCrypto.deriveBits()`

返回一个 `Promise`，会兑现一个新生成的、从主密钥（以通过参数给定的算法）派生出来的伪随机比特序列。

`SubtleCrypto.importKey()`

返回一个 `Promise`，会兑现一个新生成的密钥，该密钥与通过参数给定的密钥格式、算法、原始密钥数据、用法和可导出性相对应。

`SubtleCrypto.exportKey()`

返回一个 `Promise`，会兑现一个包含所请求格式的密钥的原始密钥数据。

`SubtleCrypto.wrapKey()`

返回一个 `Promise`，会兑现一个包装的对称密钥，该密钥可在不安全的环境中使用（传输、存储）。该密钥与通过参数给定的格式相匹配，并使用制定的算法来包装给定的密钥。

`SubtleCrypto.unwrapKey()`

返回一个 `Promise`，会兑现一个与通过参数给定的包装密钥（wrapped key）对应的密钥。

使用 SubtleCrypto
---------------

我们可以将此 API 的实现函数分为两类：加密函数和密钥管理函数。

### 加密函数

这些函数你可以用来实现系统中的隐私和身份验证等安全特性。`SubtleCrypto` API 提供了如下加密函数：

* `sign()` 和 `verify()`：创建和验证数字签名。
* `encrypt()` 和 `decrypt()`：加密和解密数据。
* `digest()`：生成某些数据的定长、防碰撞的消息摘要。
### 密钥管理函数

除了 `digest()`，`SubtleCrypto` API 中所有加密函数都会使用密钥，并使用 `CryptoKey` 对象表示加密密钥。要执行签名和加密操作，请将 `CryptoKey` 对象传参给 `sign()` 或 `encrypt()` 函数。

#### 生成和派生密钥

`generateKey()` 和 `deriveKey()` 函数都可以创建一个新的 `CryptoKey` 对象。

不同之处在于 `generateKey()` 每次都会生成一个新的键值对，而 `deriveKey()` 通过基础密钥资源派生一个新的密钥。如果为两个独立的 `deriveKey()` 函数调用提供相同的基础密钥资源，那么你会获得两个具有相同基础值的 `CryptoKey` 对象。如果你想通过密码派生加密密钥，然后从相同的密码派生相同的密钥以解密数据，那么这将会非常有用。

#### 导入和导出密钥

要在应用程序外部使密钥可用，你需要导出密钥，`exportKey()` 可以为你提供该功能。你可以选择多种导出格式。

`importKey()` 与 `exportKey()` 刚好相反。你可以从其他系统导入密钥，并且支持像 PKCS #8 和 JSON Web Key 这样可以帮助你执行此操作的标准格式。`exportKey()` 函数以非加密格式导出密钥。

如果密钥是敏感的，你应该使用 `wrapKey()`，该函数导出密钥并且使用另外一个密钥加密它。此类 API 调用被称为“密钥包装密钥”（key-wrapping key）。

`unwrapKey()` 与 `wrapKey()` 相反，该函数解密密钥后导入解密的密钥。

#### 存储密钥

`CryptoKey` 对象可以通过结构化克隆算法来存储，这意味着你可以通过 web storage API 来存储和获取它们。更为规范的方式是通过使用 IndexedDB API 来存储 `CryptoKey` 对象。

### 支持的算法

Web Crypto API 提供的加密函数可以由一个或多个不同的*加密算法*执行：函数可以通过 `algorithm` 参数来指定使用的算法。一些算法需要额外的参数，在这些情况下可以将 `algorithm` 参数作为对象字典传入额外的参数。

下表总结了哪些算法适用于哪些加密操作：

|  | sign()verify() | encrypt()decrypt() | digest() | deriveBits()deriveKey() | wrapKey()unwrapKey() |
| --- | --- | --- | --- | --- | --- |
| RSASSA-PKCS1-v1\_5 | ✓ |  |  |  |  |
| RSA-PSS | ✓ |  |  |  |  |
| ECDSA | ✓ |  |  |  |  |
| HMAC | ✓ |  |  |  |  |
| RSA-OAEP |  | ✓ |  |  | ✓ |
| AES-CTR |  | ✓ |  |  | ✓ |
| AES-CBC |  | ✓ |  |  | ✓ |
| AES-GCM |  | ✓ |  |  | ✓ |
| SHA-1 |  |  | ✓ |  |  |
| SHA-256 |  |  | ✓ |  |  |
| SHA-384 |  |  | ✓ |  |  |
| SHA-512 |  |  | ✓ |  |  |
| ECDH |  |  |  | ✓ |  |
| HKDF |  |  |  | ✓ |  |
| PBKDF2 |  |  |  | ✓ |  |
| AES-KW |  |  |  |  | ✓ |

规范
--

| Specification |
| --- |
| Web Cryptography API # subtlecrypto-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Web Crypto API
* SubtleCrypto 的非加密用途 (en-US)
* Web 安全
* 隐私、权限和信息安全 (en-US)
* `Crypto` 和 `Crypto.subtle`。
* Crypto 101：密码学入门课程。