关于 javascript:Web Crypto API using Microsoft Edge (38.14393.0.0)

Web Crypto API using Microsoft Edge (38.14393.0.0)

我在 Chrome(自从第一个 Web Crypto 支持以来)、Firefox(自从第一个 Web Crypto 支持)甚至 Safari TP 上都成功使用了 Web Crypto API (https://www.w3.org/TR/WebCryptoAPI/) (10.2) 在 WebCrypto Liner 的支持下,WebCrypto API (https://github.com/PeculiarVentures/webcrypto-liner) 的 pollyfill。

现在我想使用 Microsoft Edge 测试我们的代码。但是加密和解密示例 ArrayBuffer 已经失败。这里的代码:

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
var crypto = window.crypto;
if (crypto.subtle) {
    var aesGcmKey = null;
    // always create a new, random iv in production systems!!!
    var tempIv = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
    // needed for edge, if additional data missing decrypting is failing
    var tempAdditionalData = new Uint8Array(0);
    var dataToEncrypt = new Uint8Array([1, 2, 3, 4, 5]);

    // 1.) generate key
    var generateKeyPromise = crypto.subtle.generateKey(
        {name:"AES-GCM", length: 256}, true, ["encrypt","decrypt"]
    );
    generateKeyPromise.then(function (tempKey) {
        aesGcmKey = tempKey;
        // 2.) start encryption with this key
        var encryptedDataPromise = crypto.subtle.encrypt(
            {name:"AES-GCM", iv: tempIv, additionalData: tempAdditionalData, tagLength: 128},
            aesGcmKey,
            dataToEncrypt
        );
        encryptedDataPromise.then(function (encryptedData) {
            // 3.) decrypt using same key
            var decryptedDataPromise = crypto.subtle.decrypt(
                {name:"AES-GCM", iv: tempIv, additionalData: tempAdditionalData, tagLength: 128},
                aesGcmKey,
                encryptedData
            );
            decryptedDataPromise.then(function (decryptedData) {
                // 4.) compare decrypted array buffer and inital data
                console.log('data decrypted!');
                console.log(decryptedData);
            });
            decryptedDataPromise.catch(function (error) {
                console.log('decrypting sample data failed');
                console.log(error);
            });
        });
        // if 2.) is failing
        encryptedDataPromise.catch(function (error) {
            console.log('encrypting sample data failed');
            console.log(error);
        });
    });
    // if 1.) is failing
    generateKeyPromise.catch(function (error) {
        console.log('creating aec gcm key failed');
        console.log(error);
    });
}

此代码在 Edge 上的解密阶段(代码中的第 3 步)失败,而在 Chrome、Firefox 甚至 Safari 上运行良好。有线部分,decryptedDataPromise 被异常拒绝,但返回的数据看起来根本不像异常:

1
[object Object] {additionalData: Uint8Array {...}, iv: Uint8Array {...}, name:"AES-GCM", tagLength: 128}

有人知道为什么这在 Microsoft Edge 上会失败吗?


正如评论中所建议的,将 IV 更改为 12 而不是 16 并且附加数据以包含 1 而不是 0 解决了 Edge

中的问题

1
2
var tempIv = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
var tempAdditionalData = new Uint8Array(1);

您对附加数据的评论"// 边缘需要,如果附加数据丢失解密失败"真的不需要。 additionalData 可以是 void

我在 MSDN 中查找有关加密操作的信息,但没有记录此行为。所以我觉得WebCrypto的实现还不够成熟,还是有小bug


在 Edge 41 中,原始代码产生了相同的行为。
但是,将 tempAdditionalData 设置为 null 可以解决问题并且解密成功。