1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
---
title: SubtleCrypto.encrypt()
slug: Web/API/SubtleCrypto/encrypt
tags:
- API
- Crypto
- 加密
translation_of: Web/API/SubtleCrypto/encrypt
---
<p>{{APIRef("Web Crypto API")}}</p>
<p><code><strong>SubtleCrypto.encrypt()</strong></code> 方法以算法、密钥、明文为参数返回一个包含加密数据的 {{jsxref("Promise")}} 对象。</p>
<h2 id="语法">语法</h2>
<pre class="syntaxbox">var <em>result</em> = <em>crypto</em><code>.encrypt(<em>algo</em>, <em>key</em>, <em>cleartext</em>)</code>;
</pre>
<h3 id="参数">参数</h3>
<ul>
<li><em><code>algo</code></em> 是一个使用加密函数的对象或者 {{domxref("DOMString")}},后者是 <code>{"name": algo}</code> 的缩写。支持的值是:
<ul>
<li><code>{"name": "AES-CBC", iv}</code> <code><em>iv</em></code> 是具有16个随机字节的 {{jsxref("ArrayBuffer")}} 或 {{jsxref("ArrayBufferView")}} (这些应该由 {{domxref("RandomSource.getRandomValues()")}} 生成)。</li>
<li><code>{"name": "AES-CTR", counter, length}</code></li>
<li><code>{"name": "AES-GCM", iv, additionalData, tagLength}</code> (<em><code>additionalData</code></em> 和 <code><em>tagLength</em></code> 是可选的)</li>
<li><code>{"name": "RSA-OAEP", label}</code> (<code><em>label</em></code> 是可选的)</li>
</ul>
</li>
<li><code><em>key</em></code> 是一个包含签名密钥的 {{domxref("CryptoKey")}}。</li>
<li><em><code>cleartext </code></em><code>是一个包含需要加密的明文</code> {{jsxref("ArrayBuffer")}} 或者 {{jsxref("ArrayBufferView")}} 对象。</li>
</ul>
<h3 id="返回值">返回值</h3>
<ul>
<li><font face="Consolas, Liberation Mono, Courier, monospace">返回值是一个 </font>{{jsxref("Promise")}} 对象,返回一个由 {{glossary("cleartext")}} 加密生成的 {{glossary("ciphertext")}} 的 {{jsxref("ArrayBuffer")}}。</li>
</ul>
<h3 id="异常">异常</h3>
<p>当遇到以下异常时,promise 将会返回一次错误(reject):</p>
<dl>
<dt>InvalidAccessError</dt>
<dd>当针对提供的 key 值执行的操作无效时(例如加密算法或者 key 值无效),将会抛出该错误。</dd>
</dl>
<dl>
<dt>OperationError</dt>
<dd>发生于由于特定于操作的原因使得操作失败时,例如算法参数的大小无效,或者 AES-GCM 明文长度超过 2³⁹−256 字节。</dd>
</dl>
<h2 id="支持的算法">支持的算法</h2>
<p>Crypto 接口提供了支持 <code>encrypt()</code> 和 <code>decrypt()</code> 操作的四种算法。</p>
<p>其中的 RSA-OAEP 算法是一种非对称加密的公钥密码({{Glossary("public-key cryptography", "public-key cryptosystem")}})。</p>
<p>其它三种算法则都是对称密钥加密({{Glossary("Symmetric-key cryptography", "symmetric algorithms")}}),并且它们都是基于同一种基础加密,即 AES (Advanced Encryption Standard)。它们不同之处在于分组加密的操作方式({{Glossary("Block cipher mode of operation", "mode")}})。Crypto 接口支持以下三种 AES 加密类型:</p>
<ul>
<li>CTR (Counter Mode)</li>
<li>CBC (Cipher Block Chaining)</li>
<li>GCM (Galois/Counter Mode)</li>
</ul>
<p>这里强烈建议使用<em><strong>认证加密</strong></em>(<em>authenticated encryption</em>),它可以检测密文是否已被攻击者篡改。使用认证也可以避免<em>选择密文攻击</em>(<em>chosen-ciphertext</em> attacks),即攻击者可以请求系统解密任意的消息,然后使用解密结果来倒推出关于密钥的一些信息。虽然 CTR 和 CBC 模式可以添加认证,但是它们默认不提供该操作,并且在手动实现它们的时候,很同意犯一些微小但严重的错误。GCM 不支持内置的认证,由于这个原因,常常推荐使用另外两种 AES 加密算法。</p>
<h3 id="RSA-OAEP">RSA-OAEP</h3>
<p>关于 RSA-OAEP 公钥加密算法的规范位于 <a href="https://tools.ietf.org/html/rfc3447">RFC 3447</a>。</p>
<h3 id="AES-CTR">AES-CTR</h3>
<p>使用 Counter 模式的 AES 算法,相关规范位于 <a href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">NIST SP800-38A</a>。</p>
<h3 id="AES-CBC">AES-CBC</h3>
<p>使用 Cipher Block Chaining 模式的 AES 算法,规范位于<a href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">NIST SP800-38A</a>。</p>
<h3 id="AES-GCM">AES-GCM</h3>
<p>使用 Galois/Counter 模式的 AES 算法,规范位于 <a href="https://csrc.nist.gov/publications/detail/sp/800-38d/final">NIST SP800-38D</a>。</p>
<p>这种模式与上面的模式不同之处在于,GCM 是一种 "认证(authenticated)" 模式,意思就是它包含了检测密文是否未被攻击者篡改的功能。</p>
<h2 id="示例">示例</h2>
<div class="blockIndicator note">
<p><strong>注意</strong>: 你可以在 GitHub 尝试这个示例(<a href="https://mdn.github.io/dom-examples/web-crypto/encrypt-decrypt/index.html">try the working examples</a>)。</p>
</div>
<h3 id="RSA-OAEP_2">RSA-OAEP</h3>
<p>以下代码获取文本框中的内容,编码后进行加密,使用的算法为 RSA-OAEP。可以在 GitHub 查看完整代码:<a href="https://github.com/mdn/dom-examples/blob/master/web-crypto/encrypt-decrypt/rsa-oaep.js" rel="noopener">See the complete code on GitHub</a>。</p>
<pre>function getMessageEncoding() {
const messageBox = document.querySelector(".rsa-oaep #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
function encryptMessage(publicKey) {
let encoded = getMessageEncoding();
return window.crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
publicKey,
encoded
);
}</pre>
<h3 id="AES-CTR_2">AES-CTR</h3>
<p>以下代码同样获取文本框内容,进行编码后使用 AES 的 CTR 模式加密,完整代码:<a href="https://github.com/mdn/dom-examples/blob/master/web-crypto/encrypt-decrypt/aes-ctr.js" rel="noopener">See the complete code on GitHub</a>。</p>
<pre>function getMessageEncoding() {
const messageBox = document.querySelector(".aes-ctr #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
function encryptMessage(key) {
let encoded = getMessageEncoding();
// counter will be needed for decryption
counter = window.crypto.getRandomValues(new Uint8Array(16));
return window.crypto.subtle.encrypt(
{
name: "AES-CTR",
counter,
length: 64
},
key,
encoded
);
}
</pre>
<pre>let iv = new Uint8array(16);
let key = new Uint8array(16);
let data = new Uint8array(12345);
//crypto functions are wrapped in promises so we have to use await and make sure the function that
//contains this code is an async function
//encrypt function wants a cryptokey object
const key_encoded = await crypto.subtle.importKey( "raw", key.buffer, 'AES-CTR' , false, ["encrypt", "decrypt"]);
const encrypted_content = await window.crypto.subtle.encrypt(
{
name: "AES-CTR",
counter: iv,
length: 128
},
key_encoded,
data
);
//Uint8array
console.log(encrypted_content);</pre>
<h3 id="AES-CBC_2">AES-CBC</h3>
<p>使用 AES 的 CBC 模式加密,完整代码:<a href="https://github.com/mdn/dom-examples/blob/master/web-crypto/encrypt-decrypt/aes-cbc.js" rel="noopener">See the complete code on GitHub</a>。</p>
<pre>function getMessageEncoding() {
const messageBox = document.querySelector(".aes-cbc #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
function encryptMessage(key) {
let encoded = getMessageEncoding();
// iv will be needed for decryption
iv = window.crypto.getRandomValues(new Uint8Array(16));
return window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv
},
key,
encoded
);
}</pre>
<h3 id="AES-GCM_2">AES-GCM</h3>
<p>使用 AES 的 GCM 模式加密,完整代码:<a href="https://github.com/mdn/dom-examples/blob/master/web-crypto/encrypt-decrypt/aes-gcm.js" rel="noopener">See the complete code on GitHub</a>。</p>
<pre>function getMessageEncoding() {
const messageBox = document.querySelector(".aes-gcm #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
function encryptMessage(key) {
let encoded = getMessageEncoding();
// iv will be needed for decryption
iv = window.crypto.getRandomValues(new Uint8Array(12));
return window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encoded
);
}</pre>
<h2 id="规范">规范</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td>{{ SpecName('Web Crypto API', '#dfn-SubtleCrypto-method-encrypt', 'SubtleCrypto.encrypt()') }}</td>
<td>{{ Spec2('Web Crypto API') }}</td>
<td>Initial definition.</td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p>{{Compat("api.SubtleCrypto.encrypt")}}</p>
<h2 id="另见">另见</h2>
<ul>
<li>{{domxref("SubtleCrypto.decrypt()")}}.</li>
<li><a href="https://tools.ietf.org/html/rfc3447">RFC 3447</a> specifies RSAOAEP.</li>
<li><a href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">NIST SP800-38A</a> specifies CTR mode.</li>
<li><a href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">NIST SP800-38A</a> specifies CBC mode.</li>
<li><a href="https://csrc.nist.gov/publications/detail/sp/800-38d/final">NIST SP800-38D</a> specifies GCM mode.</li>
</ul>
|