SubtleCrypto.exportKey()
========================

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

`SubtleCrypto` 接口的 **`exportKey()`** 方法用于导出密钥。也就是说，它将一个 `CryptoKey` 对象作为输入，并给出对应的外部可移植格式的密钥。

若要导出密钥，密钥的 `CryptoKey.extractable` (en-US) 必须设置为 `true`。

密钥可导出为多种格式：请参阅 `SubtleCrypto.importKey()` 页面支持的格式以获取详细信息。

 密钥不会以加密的格式导出：要在导出密钥时对密钥进行加密，请使用
 `SubtleCrypto.wrapKey()`
 API 代替。

语法
--


```js
exportKey(format, key)
```

### 参数

`format`

一个描述要导出的密钥格式的字符串。可为以下值之一：

* `raw`：Raw 格式。
* `pkcs8`：PKCS #8 格式。
* `spki`：SubjectPublicKeyInfo 格式。
* `jwk`：JSON Web Key 格式。

`key`

要导出的 `CryptoKey`。

### 返回值

一个 `Promise`。

* 如果 `format` 为 `jwk`，则 promise 会兑现一个包含密钥的 JSON 对象。
* 否则，promise 将会兑现一个包含密钥的
 `ArrayBuffer`。
### 异常

当发生以下几种异常时，promise 会被拒绝：

`InvalidAccessError` `DOMException`

若尝试导出不可导出的密钥，则会抛出此异常。

`NotSupported` `DOMException`

若尝试导出为未知的格式，则会抛出此异常。

`TypeError`

若尝试使用无效的格式，则会抛出此异常。

示例
--

**备注：** 你可以在 GitHub 上尝试可用的示例。

### 导出为 Raw 格式

该示例将 AES 密钥导出为包含二进制密钥的 `ArrayBuffer`。在 GitHub 上查看完整代码。


```js
/\*
导出给定密钥，并将其写入“exported-key”的区域。
\*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("raw", key);
  const exportedKeyBuffer = new Uint8Array(exported);

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = `[${exportedKeyBuffer}]`;
}

/\*
生成加密/解密密钥，
然后在“导出”按钮上设置事件监听器。
\*/
window.crypto.subtle
  .generateKey(
    {
      name: "AES-GCM",
      length: 256,
    },
    true,
    ["encrypt", "decrypt"],
  )
  .then((key) => {
    const exportButton = document.querySelector(".raw");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(key);
    });
  });
```

### 导出为 PKCS #8 格式

该示例将 RSA 私有签名密钥导出为 PKCS #8 对象。然后将导出的密钥编码为 PEM 格式。在 GitHub 上查看完整代码。


```js
/\*
将 ArrayBuffer 转换为字符串
代码来自 https://developer.chrome.com/blog/how-to-convert-arraybuffer-to-and-from-string/
\*/
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

/\*
导出给定密钥，并将其写入“exported-key”的区域。
\*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("pkcs8", key);
  const exportedAsString = ab2str(exported);
  const exportedAsBase64 = window.btoa(exportedAsString);
  const pemExported = `-----BEGIN PRIVATE KEY-----\n${exportedAsBase64}\n-----END PRIVATE KEY-----`;

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = pemExported;
}

/\*
生成签名/验证密钥对，
然后在“导出”按钮上设置事件监听器。
\*/
window.crypto.subtle
  .generateKey(
    {
      name: "RSA-PSS",
      // 考虑为要求保证长期安全性的系统使用 4096 位的密钥
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
    },
    true,
    ["sign", "verify"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".pkcs8");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.privateKey);
    });
  });
```

### 导出为 SubjectPublicKeyInfo 格式

 该示例将 RSA 公开加密密钥导出为 PEM 编码的 SubjectPublicKeyInfo
 对象。在 GitHub 上查看完整代码。


```js
/\*
将 ArrayBuffer 转换为字符串
代码来自 https://developer.chrome.com/blog/how-to-convert-arraybuffer-to-and-from-string/
\*/
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

/\*
导出给定密钥，并将其写入“exported-key”的区域。
\*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("spki", key);
  const exportedAsString = ab2str(exported);
  const exportedAsBase64 = window.btoa(exportedAsString);
  const pemExported = `-----BEGIN PUBLIC KEY-----\n${exportedAsBase64}\n-----END PUBLIC KEY-----`;

  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = pemExported;
}

/\*
生成加密/解密密钥对，
然后在“导出”按钮上设置事件监听器。
\*/
window.crypto.subtle
  .generateKey(
    {
      name: "RSA-OAEP",
      // 考虑为要求保证长期安全性的系统使用 4096 位的密钥
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
    },
    true,
    ["encrypt", "decrypt"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".spki");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.publicKey);
    });
  });
```

### 导出为 JSON Web Key 格式

该示例将 ECDSA 私有签名密钥导出为 JSON Web Key 对象。在 GitHub 上查看完整代码。


```js
/\*
导出给定密钥，并将其写入“exported-key”的区域。
\*/
async function exportCryptoKey(key) {
  const exported = await window.crypto.subtle.exportKey("jwk", key);
  const exportKeyOutput = document.querySelector(".exported-key");
  exportKeyOutput.textContent = JSON.stringify(exported, null, " ");
}

/\*
生成签名/验证密钥对，
然后在“导出”按钮上设置事件监听器。
\*/
window.crypto.subtle
  .generateKey(
    {
      name: "ECDSA",
      namedCurve: "P-384",
    },
    true,
    ["sign", "verify"],
  )
  .then((keyPair) => {
    const exportButton = document.querySelector(".jwk");
    exportButton.addEventListener("click", () => {
      exportCryptoKey(keyPair.privateKey);
    });
  });
```

规范
--

| Specification |
| --- |
| Web Cryptography API # SubtleCrypto-method-exportKey |

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

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

参见
--

* `SubtleCrypto.importKey()`
* `SubtleCrypto.wrapKey()`
* PKCS #8 格式。
* SubjectPublicKeyInfo 格式。
* JSON Web Key 格式。