使用WebCrypto API包装和解包密钥

时间:2017-06-23 16:25:16

标签: javascript encryption webcryptoapi

我在客户端使用Webcrypto API进行一些加密工作。 虽然我无法打包和解包密钥,但浏览器始终返回以下错误。

DOMException [OperationError: "The operation failed for an operation-specific reason"

你和我对这个错误无能为力,所以我粘贴了我的代码。

function wrapPrivateKey(privateKey, wrappingKey) {
    var iv = window.crypto.getRandomValues(new Uint8Array(12));
    return window.crypto.subtle.wrapKey(
        "jwk",
        privateKey,
        wrappingKey,
        {
            name: "AES-GCM",
            length: 256,
            iv: iv,
        }
        )
        .then(function (key) {
            return {
                "key": StringToB64(arrayBufferToString(key)),
                "iv": StringToB64(arrayBufferToString(iv))
            };
        })
        .catch(function (err) {
            console.error(err);
            return false;
        });
}

function unwrapPrivateKey(wrappedPrivateKey, unwrappingKey) {
    var obj = JSON.parse(B64ToString(wrappedPrivateKey));
    var key = stringToArrayBuffer(B64ToString(obj["key"]));
    var iv = stringToArrayBuffer(B64ToString(obj["iv"]));
    return window.crypto.subtle.unwrapKey(
        "jwk",
        key,
        unwrappingKey,
        {
            name: "AES-GCM",
            length: 256,
            iv: iv,
        },
        {
            name: "RSA-OAEP",
            hash: {name: "SHA-256"},
        },
        true,
        ["encrypt", "decrypt"]
        )
        .then(function (key) {
            return key;
        })
        .catch(function (err) {
            console.error(err);
            return false;
        });
}

我不知道问题是否与将密钥对象转换为字符串有关。不幸的是,我需要将其转换为字符串以将其保存在数据库中。

1 个答案:

答案 0 :(得分:1)

以下是密钥换行/展开的简单示例。此代码适用于Chrome / Mozilla

const rsaAlg = {
    name: "RSA-OAEP",
    hash: "SHA-256",
    publicExponent: new Uint8Array([1, 0, 1]),
    modulusLength: 2048
};
const aesAlg = {
    name: "AES-GCM",
    length: 256,
    iv: crypto.getRandomValues(new Uint8Array(12)),
};

crypto.subtle.generateKey(rsaAlg, true, ["encrypt", "decrypt"])
    .then((rsaKeys) => {
        return crypto.subtle.generateKey(aesAlg, true, ["encrypt", "decrypt", "wrapKey", "unwrapKey"])
            .then((aesKey) => {
                return crypto.subtle.wrapKey("jwk", rsaKeys.privateKey, aesKey, aesAlg)
                    .then((wrappedKey) => {
                        console.log(wrappedKey); // ArrayBuffer

                        // Unwrap key
                        return crypto.subtle.unwrapKey("jwk", wrappedKey, aesKey, aesAlg, rsaAlg, true, ["decrypt"])
                    })
                    .then((unwrappedKey) => {
                        console.log(unwrappedKey);
                    })
            })
    })
    .catch((err) => {
        console.error(err);
    })

WebCrypto API因浏览器而异。最好使用一些允许修复它的模块webcrypto-shimwebcrypto-liner

我也看到你使用var key = stringToArrayBuffer(B64ToString(obj["key"]));。但关键必须是CryptoKey。如果您有原始的对称密钥,则必须使用importKey函数从CryptoKey创建raw