CryptoKey ArrayBuffer到base64和Back

时间:2016-07-30 19:28:05

标签: javascript base64 pem arraybuffer webcryptoapi

我想知道如何解决这个问题。我使用WebCrypto API生成RSA-OAEP密钥对,然后我从密钥对导出pkcs8中的私钥,该密钥对作为ArrayBuffer导出,我想将此ArrayBuffer编码为base64,以便将其存储为PEM。

在这个测试示例中,我将密钥导出为pkcs8并将此pkcs8导回到CryptoKey。问题在于它有时会起作用,有时却不起作用。

这些是代码的结果: 注意:只有这些状态中的一个不会同时发生。 注2:此示例不包含----- BEGIN PRIVATE KEY -----前缀和后缀我只对密钥进行编码。

案例1:未捕获(承诺)URIError:URI格式不正确(...)b64DecodeUnicode @ try.php:20b64toab @ try.php:70wayBack @ try.php:66(匿名函数)@ try.php:56

案例2:未定义:1未捕获(在承诺中)DOMException

案例3:好的 - 一直有效。

我不知道导致错误的原因,但我认为它与base64编码有关。正如我所说,有时私钥生成正常,有时不生成。

非常感谢你提前得到的每一个帮助。

function b64EncodeUnicode(str) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}

function addNewLines(str) {
    var finalString = '';
    for(var i=0; i < str.length; i++) {
        finalString += str.substring(0, 64) + '\n';
        str = str.substring(64);
    }

     return finalString;
}

window.crypto.subtle.generateKey(
    {
        name: "RSA-OAEP",
        modulusLength: 2048,
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: {name: "SHA-256"}
    },
    true,
    ["encrypt", "decrypt"]
).then(function(keyPair) {
    window.crypto.subtle.exportKey(
        "pkcs8",
        keyPair.privateKey
    ).then(function(exportedPrivateKey) {
        var byteArray = new Uint8Array(exportedPrivateKey);
        console.log(byteArray);
        var byteString = '';
        for(var i=0; i < byteArray.byteLength; i++) {
            byteString += String.fromCodePoint(byteArray[i]);
        }

        wayBack(addNewLines(b64EncodeUnicode(byteString)));
    });
});

function wayBack(pem) {
    var lines = pem.split('\n');
    var encodedString = '';
    for(var i=0; i < lines.length; i++) {
        encodedString += lines[i].trim();
    }
    b64toab(encodedString);
}

function b64toab(b64) {
    var byteString = b64DecodeUnicode(b64);
    console.log(byteString);
    var byteArray = new Uint8Array(byteString.length);
    for(var i=0; i < byteString.length; i++) {
        byteArray[i] = byteString.codePointAt(i);
    }
    console.log(byteArray);

    window.crypto.subtle.importKey(
        "pkcs8",
        byteArray,
        {
            name: "RSA-OAEP",
            hash: {name: "SHA-256"}
        },
        true,
        ["decrypt"]
    ).then(function(importedPrivateKey) {
        console.log(importedPrivateKey);
    });
}

2 个答案:

答案 0 :(得分:4)

当您将字符串拆分为64个字符的块时,您忘记包含PEM的最后一部分。只需将<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="//code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script> <div id="greendiv"> <img src="http://dummyimage.com/30x40" /> <img src="http://dummyimage.com/30x40" /> </div> <div id="reddiv"></div>添加到z-index

即可
finalString += str;

我已经重构了你的例子,看看发生了什么。如果您认为有用,请使用以下代码

addNewLines

答案 1 :(得分:0)

我发布了其他工作代码: (注意:代码没有----- BEGIN PRIVATE KEY -----和----- END PRIVATE KEY ----- base64 only)

function addNewLines(str) {
    var finalString = '';
    while(str.length > 0) {
        finalString += str.substring(0, 64) + '\n';
        str = str.substring(64);
    }

    return finalString;
}

function removeLines(str) {
    return str.replace("\n", "");
}

function arrayBufferToBase64(arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer);
    var byteString = '';
    for(var i=0; i < byteArray.byteLength; i++) {
        byteString += String.fromCharCode(byteArray[i]);
    }
    var b64 = window.btoa(byteString);

    return b64;
}

function base64ToArrayBuffer(b64) {
    var byteString = window.atob(b64);
    var byteArray = new Uint8Array(byteString.length);
    for(var i=0; i < byteString.length; i++) {
        byteArray[i] = byteString.charCodeAt(i);
    }

    return byteArray;
}

window.crypto.subtle.generateKey(
    {
        name: "RSA-OAEP",
        modulusLength: 2048,
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: {name: "SHA-256"}
    },
    true,
    ["encrypt", "decrypt"]
).then(function(keyPair) {
    window.crypto.subtle.exportKey(
        "pkcs8",
        keyPair.privateKey
    ).then(function(exportedPrivateKey) {
        var pem = addNewLines(arrayBufferToBase64(exportedPrivateKey));
        importKey(pem);
    });
});

function importKey(b64) {
    b64 = removeLines(b64);
    arrayBuffer = base64ToArrayBuffer(b64);

    window.crypto.subtle.importKey(
        "pkcs8",
        arrayBuffer,
        {
            name: "RSA-OAEP",
            hash: {name: "SHA-256"}
        },
        true,
        ["decrypt"]
    ).then(function(importedPrivateKey) {
        console.log(importedPrivateKey);
    });
}

更新: 我写了一个小的加密库,你可以用它来进行PEM转换等等。 https://github.com/PeterBielak/OpenCrypto

用法示例:

var crypt = new OpenCrypto();

crypt.getKeyPair().then(function(keyPair) {
    crypt.cryptoPrivateToPem(keyPair.privateKey).then(function(pemPrivateKey) {
        console.log(pemPrivateKey);
    });
});