Skip to content

Instantly share code, notes, and snippets.

@sergio
Forked from deiu/webcryptoapi.html
Created October 31, 2018 17:00
Show Gist options
  • Select an option

  • Save sergio/73c75ed46bc035a43b55ff1d941e4d29 to your computer and use it in GitHub Desktop.

Select an option

Save sergio/73c75ed46bc035a43b55ff1d941e4d29 to your computer and use it in GitHub Desktop.

Revisions

  1. Andrei revised this gist Apr 13, 2016. 1 changed file with 18 additions and 18 deletions.
    36 changes: 18 additions & 18 deletions webcryptoapi.html
    Original file line number Diff line number Diff line change
    @@ -229,25 +229,25 @@
    })
    // Test encryption
    generateKey(encryptAlgorithm, scopeEncrypt).then(function(keys) {
    var title = document.createElement('h2')
    title.innerHTML = 'Encryption'
    document.querySelector('body').appendChild(title)
    encryptData(vector, keys.publicKey, _data).then(function(encryptedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Encrypted text:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arrayBufferToBase64(encryptedData)
    document.querySelector('body').appendChild(divSig)
    decryptData(vector, keys.privateKey, encryptedData).then(function(result) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Encryption outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (arrayBufferToText(result) === _data)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    var title = document.createElement('h2')
    title.innerHTML = 'Encryption'
    document.querySelector('body').appendChild(title)
    encryptData(vector, keys.publicKey, _data).then(function(encryptedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Encrypted text:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arrayBufferToBase64(encryptedData)
    document.querySelector('body').appendChild(divSig)
    decryptData(vector, keys.privateKey, encryptedData).then(function(result) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Encryption outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (arrayBufferToText(result) === _data)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })
    })
    }
    </script>
  2. Andrei revised this gist Apr 13, 2016. 1 changed file with 100 additions and 30 deletions.
    130 changes: 100 additions & 30 deletions webcryptoapi.html
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@
    <html>
    <head>
    <script>
    function generateSigKey(alg) {
    function generateKey(alg, scope) {
    return new Promise(function(resolve) {
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"])
    var genkey = crypto.subtle.generateKey(alg, true, scope)
    genkey.then(function (pair) {
    resolve(pair)
    })
    })
    }

    function arrayBufferToBase64String(arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer)
    var byteString = ''
    @@ -18,7 +18,7 @@
    }
    return btoa(byteString)
    }

    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str)
    var bytes = new Uint8Array(byteStr.length)
    @@ -27,7 +27,7 @@
    }
    return bytes.buffer
    }

    function textToArrayBuffer(str) {
    var buf = unescape(encodeURIComponent(str)) // 2 bytes for each char
    var bufView = new Uint8Array(buf.length)
    @@ -36,11 +36,21 @@
    }
    return bufView
    }

    function arraySignatureToBase64(arr) {

    function arrayBufferToText(arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer)
    var str = ''
    for (var i=0; i<byteArray.byteLength; i++) {
    str += String.fromCharCode(byteArray[i])
    }
    return str
    }


    function arrayBufferToBase64(arr) {
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)))
    }

    function convertBinaryToPem(binaryData, label) {
    var base64Cert = arrayBufferToBase64String(binaryData)
    var pemCert = "-----BEGIN " + label + "-----\r\n"
    @@ -57,7 +67,7 @@
    pemCert += "-----END " + label + "-----\r\n"
    return pemCert
    }

    function convertPemToBinary(pem) {
    var lines = pem.split('\n')
    var encoded = ''
    @@ -72,7 +82,7 @@
    }
    return base64StringToArrayBuffer(encoded)
    }

    function importPublicKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"])
    @@ -81,7 +91,7 @@
    })
    })
    }

    function importPrivateKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"])
    @@ -90,7 +100,7 @@
    })
    })
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    @@ -99,7 +109,7 @@
    })
    })
    }

    function exportPrivateKey(keys) {
    return new Promise(function(resolve) {
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey)
    @@ -108,7 +118,7 @@
    })
    })
    }

    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    @@ -118,16 +128,37 @@
    })
    })
    }

    function signData(key, data) {
    var buffer = textToArrayBuffer(data)
    return window.crypto.subtle.sign(signAlgorithm, key, buffer)
    return window.crypto.subtle.sign(signAlgorithm, key, textToArrayBuffer(data))
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data)
    }


    function encryptData(vector, key, data) {
    return crypto.subtle.encrypt(
    {
    name: "RSA-OAEP",
    iv: vector
    },
    key,
    textToArrayBuffer(data)
    )
    }

    function decryptData(vector, key, data) {
    return crypto.subtle.decrypt(
    {
    name: "RSA-OAEP",
    iv: vector
    },
    key,
    data
    )
    }

    // Test everything
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    @@ -138,47 +169,86 @@
    extractable: false,
    publicExponent: new Uint8Array([1, 0, 1])
    }


    var encryptAlgorithm = {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    extractable: false,
    hash: {
    name: "SHA-256"
    }
    }

    var crypto = window.crypto || window.msCrypto
    if (crypto.subtle) {
    var _signedData
    var _toSign = "test"
    generateSigKey(signAlgorithm).then(function(pair) {
    var _data = "test"
    var scopeSign = ["sign", "verify"]
    var scopeEncrypt = ["encrypt", "decrypt"]
    var vector = crypto.getRandomValues(new Uint8Array(16))

    // Test signature
    generateKey(signAlgorithm, scopeSign).then(function(pair) {
    exportPemKeys(pair).then(function(keys) {
    var title = document.createElement('h2')
    title.innerHTML = 'Signature'
    document.querySelector('body').appendChild(title)
    var divS = document.createElement('div')
    var divP = document.createElement('div')
    divS.innerHTML = JSON.stringify(keys.privateKey)
    divP.innerHTML = JSON.stringify(keys.publicKey)
    document.querySelector('body').appendChild(divS)
    document.querySelector('body').appendChild(document.createElement('br'))
    document.querySelector('body').appendChild(divP)
    signData(pair.privateKey, _toSign).then(function(signedData) {
    signData(pair.privateKey, _data).then(function(signedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Signature:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arraySignatureToBase64(signedData)
    divSig.innerHTML = arrayBufferToBase64(signedData)
    document.querySelector('body').appendChild(divSig)
    _signedData = signedData
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign)).then(function(match) {
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_data)).then(function(result) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Outcome:'
    verT.innerHTML = 'Signature outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (match)?'Success':'Failed';
    divOut.innerHTML = (result)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })

    // load keys and re-check signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign)).then(function(match) {
    console.log("Signature verified after importing PEM public key:", match)
    testVerifySig(key, _signedData, textToArrayBuffer(_data)).then(function(result) {
    console.log("Signature verified after importing PEM public key:", result)
    })
    })
    // should output `Signature verified: true` twice in the console
    })
    })
    // Test encryption
    generateKey(encryptAlgorithm, scopeEncrypt).then(function(keys) {
    var title = document.createElement('h2')
    title.innerHTML = 'Encryption'
    document.querySelector('body').appendChild(title)
    encryptData(vector, keys.publicKey, _data).then(function(encryptedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Encrypted text:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arrayBufferToBase64(encryptedData)
    document.querySelector('body').appendChild(divSig)
    decryptData(vector, keys.privateKey, encryptedData).then(function(result) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Encryption outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (arrayBufferToText(result) === _data)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })
    })
    }
    </script>
    </head>
  3. Andrei revised this gist Apr 13, 2016. 2 changed files with 186 additions and 180 deletions.
    186 changes: 186 additions & 0 deletions webcryptoapi.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,186 @@
    <html>
    <head>
    <script>
    function generateSigKey(alg) {
    return new Promise(function(resolve) {
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"])
    genkey.then(function (pair) {
    resolve(pair)
    })
    })
    }

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

    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str)
    var bytes = new Uint8Array(byteStr.length)
    for (var i = 0; i < byteStr.length; i++) {
    bytes[i] = byteStr.charCodeAt(i)
    }
    return bytes.buffer
    }

    function textToArrayBuffer(str) {
    var buf = unescape(encodeURIComponent(str)) // 2 bytes for each char
    var bufView = new Uint8Array(buf.length)
    for (var i=0; i < buf.length; i++) {
    bufView[i] = buf.charCodeAt(i)
    }
    return bufView
    }

    function arraySignatureToBase64(arr) {
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)))
    }

    function convertBinaryToPem(binaryData, label) {
    var base64Cert = arrayBufferToBase64String(binaryData)
    var pemCert = "-----BEGIN " + label + "-----\r\n"
    var nextIndex = 0
    var lineLength
    while (nextIndex < base64Cert.length) {
    if (nextIndex + 64 <= base64Cert.length) {
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n"
    } else {
    pemCert += base64Cert.substr(nextIndex) + "\r\n"
    }
    nextIndex += 64
    }
    pemCert += "-----END " + label + "-----\r\n"
    return pemCert
    }

    function convertPemToBinary(pem) {
    var lines = pem.split('\n')
    var encoded = ''
    for(var i = 0;i < lines.length;i++){
    if (lines[i].trim().length > 0 &&
    lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
    lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
    encoded += lines[i].trim()
    }
    }
    return base64StringToArrayBuffer(encoded)
    }

    function importPublicKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function importPrivateKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    then(function(spki) {
    resolve(convertBinaryToPem(spki, "RSA PUBLIC KEY"))
    })
    })
    }

    function exportPrivateKey(keys) {
    return new Promise(function(resolve) {
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey)
    expK.then(function(pkcs8) {
    resolve(convertBinaryToPem(pkcs8, "RSA PRIVATE KEY"))
    })
    })
    }

    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    exportPrivateKey(keys).then(function(privKey) {
    resolve({publicKey: pubKey, privateKey: privKey})
    })
    })
    })
    }

    function signData(key, data) {
    var buffer = textToArrayBuffer(data)
    return window.crypto.subtle.sign(signAlgorithm, key, buffer)
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data)
    }

    // Test everything
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {
    name: "SHA-256"
    },
    modulusLength: 2048,
    extractable: false,
    publicExponent: new Uint8Array([1, 0, 1])
    }

    var crypto = window.crypto || window.msCrypto
    if (crypto.subtle) {
    var _signedData
    var _toSign = "test"
    generateSigKey(signAlgorithm).then(function(pair) {
    exportPemKeys(pair).then(function(keys) {
    var divS = document.createElement('div')
    var divP = document.createElement('div')
    divS.innerHTML = JSON.stringify(keys.privateKey)
    divP.innerHTML = JSON.stringify(keys.publicKey)
    document.querySelector('body').appendChild(divS)
    document.querySelector('body').appendChild(document.createElement('br'))
    document.querySelector('body').appendChild(divP)
    signData(pair.privateKey, _toSign).then(function(signedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Signature:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arraySignatureToBase64(signedData)
    document.querySelector('body').appendChild(divSig)
    _signedData = signedData
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign)).then(function(match) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (match)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })

    // load keys and re-check signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign)).then(function(match) {
    console.log("Signature verified after importing PEM public key:", match)
    })
    })
    // should output `Signature verified: true` twice in the console
    })
    })
    }
    </script>
    </head>
    <body></body>
    </html>
    180 changes: 0 additions & 180 deletions webcryptoapi.js
    Original file line number Diff line number Diff line change
    @@ -1,180 +0,0 @@

    function generateSigKey(alg) {
    return new Promise(function(resolve) {
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"])
    genkey.then(function (pair) {
    resolve(pair)
    })
    })
    }

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

    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str)
    var bytes = new Uint8Array(byteStr.length)
    for (var i = 0; i < byteStr.length; i++) {
    bytes[i] = byteStr.charCodeAt(i)
    }
    return bytes.buffer
    }

    function textToArrayBuffer(str) {
    var buf = unescape(encodeURIComponent(str)) // 2 bytes for each char
    var bufView = new Uint8Array(buf.length)
    for (var i=0; i < buf.length; i++) {
    bufView[i] = buf.charCodeAt(i)
    }
    return bufView
    }

    function arraySignatureToBase64(arr) {
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)))
    }

    function convertBinaryToPem(binaryData, label) {
    var base64Cert = arrayBufferToBase64String(binaryData)
    var pemCert = "-----BEGIN " + label + "-----\r\n"
    var nextIndex = 0
    var lineLength
    while (nextIndex < base64Cert.length) {
    if (nextIndex + 64 <= base64Cert.length) {
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n"
    } else {
    pemCert += base64Cert.substr(nextIndex) + "\r\n"
    }
    nextIndex += 64
    }
    pemCert += "-----END " + label + "-----\r\n"
    return pemCert
    }

    function convertPemToBinary(pem) {
    var lines = pem.split('\n')
    var encoded = ''
    for(var i = 0;i < lines.length;i++){
    if (lines[i].trim().length > 0 &&
    lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
    lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
    encoded += lines[i].trim()
    }
    }
    return base64StringToArrayBuffer(encoded)
    }

    function importPublicKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function importPrivateKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    then(function(spki) {
    resolve(convertBinaryToPem(spki, "RSA PUBLIC KEY"))
    })
    })
    }

    function exportPrivateKey(keys) {
    return new Promise(function(resolve) {
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey)
    expK.then(function(pkcs8) {
    resolve(convertBinaryToPem(pkcs8, "RSA PRIVATE KEY"))
    })
    })
    }

    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    exportPrivateKey(keys).then(function(privKey) {
    resolve({publicKey: pubKey, privateKey: privKey})
    })
    })
    })
    }

    function signData(key, data) {
    var buffer = textToArrayBuffer(data)
    return window.crypto.subtle.sign(signAlgorithm, key, buffer)
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data)
    }

    // Test everything
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {
    name: "SHA-256"
    },
    modulusLength: 2048,
    extractable: false,
    publicExponent: new Uint8Array([1, 0, 1])
    }

    var crypto = window.crypto || window.msCrypto
    if (crypto.subtle) {
    var _signedData
    var _toSign = "test"
    generateSigKey(signAlgorithm).then(function(pair) {
    exportPemKeys(pair).then(function(keys) {
    var divS = document.createElement('div')
    var divP = document.createElement('div')
    divS.innerHTML = JSON.stringify(keys.privateKey)
    divP.innerHTML = JSON.stringify(keys.publicKey)
    document.querySelector('body').appendChild(divS)
    document.querySelector('body').appendChild(document.createElement('br'))
    document.querySelector('body').appendChild(divP)
    signData(pair.privateKey, _toSign).then(function(signedData) {
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Signature:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arraySignatureToBase64(signedData)
    document.querySelector('body').appendChild(divSig)
    _signedData = signedData
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign)).then(function(match) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (match)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })

    // load keys and re-check signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign)).then(function(match) {
    console.log("Signature verified after importing PEM public key:", match)
    })
    })
    // should output `Signature verified: true` twice in the console
    })
    })
    }
  4. Andrei revised this gist Apr 13, 2016. 1 changed file with 100 additions and 87 deletions.
    187 changes: 100 additions & 87 deletions webcryptoapi.js
    Original file line number Diff line number Diff line change
    @@ -1,167 +1,180 @@
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {
    name: "SHA-256"
    }
    }

    function generateRSAKey() {
    var alg = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {name: "SHA-256"},
    modulusLength: 2048,
    extractable: true,
    publicExponent: new Uint8Array([1, 0, 1])
    };

    function generateSigKey(alg) {
    return new Promise(function(resolve) {
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
    genkey.then(function (pair) {
    resolve(pair);
    });
    });
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"])
    genkey.then(function (pair) {
    resolve(pair)
    })
    })
    }

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

    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str);
    var bytes = new Uint8Array(byteStr.length);
    var byteStr = atob(b64str)
    var bytes = new Uint8Array(byteStr.length)
    for (var i = 0; i < byteStr.length; i++) {
    bytes[i] = byteStr.charCodeAt(i);
    bytes[i] = byteStr.charCodeAt(i)
    }
    return bytes.buffer;
    return bytes.buffer
    }

    function textToArrayBuffer(str) {
    var buf = unescape(encodeURIComponent(str)); // 2 bytes for each char
    var bufView = new Uint8Array(buf.length);
    var buf = unescape(encodeURIComponent(str)) // 2 bytes for each char
    var bufView = new Uint8Array(buf.length)
    for (var i=0; i < buf.length; i++) {
    bufView[i] = buf.charCodeAt(i);
    bufView[i] = buf.charCodeAt(i)
    }
    return bufView;
    return bufView
    }

    function arraySignatureToBase64(arr) {
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)));
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)))
    }

    function convertBinaryToPem(binaryData, label) {
    var base64Cert = arrayBufferToBase64String(binaryData);
    var pemCert = "-----BEGIN " + label + "-----\r\n";
    var nextIndex = 0;
    var lineLength;
    var base64Cert = arrayBufferToBase64String(binaryData)
    var pemCert = "-----BEGIN " + label + "-----\r\n"
    var nextIndex = 0
    var lineLength
    while (nextIndex < base64Cert.length) {
    if (nextIndex + 64 <= base64Cert.length) {
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n";
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n"
    } else {
    pemCert += base64Cert.substr(nextIndex) + "\r\n";
    pemCert += base64Cert.substr(nextIndex) + "\r\n"
    }
    nextIndex += 64;
    nextIndex += 64
    }
    pemCert += "-----END " + label + "-----\r\n";
    return pemCert;
    pemCert += "-----END " + label + "-----\r\n"
    return pemCert
    }

    function convertPemToBinary(pem) {
    var lines = pem.split('\n');
    var encoded = '';
    var lines = pem.split('\n')
    var encoded = ''
    for(var i = 0;i < lines.length;i++){
    if (lines[i].trim().length > 0 &&
    lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
    lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
    encoded += lines[i].trim();
    encoded += lines[i].trim()
    }
    }
    return base64StringToArrayBuffer(encoded);
    return base64StringToArrayBuffer(encoded)
    }

    function importPublicKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"]);
    importer.then(function(key) {
    resolve(key);
    });
    });
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function importPrivateKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"]);
    importer.then(function(key) {
    resolve(key);
    });
    });
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"])
    importer.then(function(key) {
    resolve(key)
    })
    })
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    then(function(spki) {
    resolve(convertBinaryToPem(spki, "RSA PUBLIC KEY"));
    });
    });
    resolve(convertBinaryToPem(spki, "RSA PUBLIC KEY"))
    })
    })
    }

    function exportPrivateKey(keys) {
    return new Promise(function(resolve) {
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey);
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey)
    expK.then(function(pkcs8) {
    resolve(convertBinaryToPem(pkcs8, "RSA PRIVATE KEY"));
    });
    });
    resolve(convertBinaryToPem(pkcs8, "RSA PRIVATE KEY"))
    })
    })
    }

    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    exportPrivateKey(keys).then(function(privKey) {
    resolve({publicKey: pubKey, privateKey: privKey});
    });
    });
    });
    resolve({publicKey: pubKey, privateKey: privKey})
    })
    })
    })
    }

    function signData(key, data) {
    var buffer = textToArrayBuffer(data);
    console.log();
    return window.crypto.subtle.sign(signAlgorithm, key, buffer);
    var buffer = textToArrayBuffer(data)
    return window.crypto.subtle.sign(signAlgorithm, key, buffer)
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data).then(function(match) {
    console.log("Signature verified: "+match);
    });
    return crypto.subtle.verify(signAlgorithm, pub, sig, data)
    }

    // Test everything
    var crypto = window.crypto || window.msCrypto;
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {
    name: "SHA-256"
    },
    modulusLength: 2048,
    extractable: false,
    publicExponent: new Uint8Array([1, 0, 1])
    }

    var crypto = window.crypto || window.msCrypto
    if (crypto.subtle) {
    var _signedData;
    var _toSign = "test";
    generateRSAKey().then(function(pair) {
    var _signedData
    var _toSign = "test"
    generateSigKey(signAlgorithm).then(function(pair) {
    exportPemKeys(pair).then(function(keys) {
    // signData returns an ArrayBuffer; use arraySignatureToBase64() to see the value
    var divS = document.createElement('div')
    var divP = document.createElement('div')
    divS.innerHTML = JSON.stringify(keys.privateKey)
    divP.innerHTML = JSON.stringify(keys.publicKey)
    document.querySelector('body').appendChild(divS)
    document.querySelector('body').appendChild(document.createElement('br'))
    document.querySelector('body').appendChild(divP)
    signData(pair.privateKey, _toSign).then(function(signedData) {
    // console.log(arraySignatureToBase64(result));
    _signedData = signedData;
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign));
    });
    var sigT = document.createElement('h2')
    sigT.innerHTML = 'Signature:'
    document.querySelector('body').appendChild(sigT)
    var divSig = document.createElement('div')
    divSig.innerHTML = arraySignatureToBase64(signedData)
    document.querySelector('body').appendChild(divSig)
    _signedData = signedData
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign)).then(function(match) {
    var verT = document.createElement('h2')
    verT.innerHTML = 'Outcome:'
    document.querySelector('body').appendChild(verT)
    var divOut = document.createElement('div')
    divOut.innerHTML = (match)?'Success':'Failed';
    document.querySelector('body').appendChild(divOut)
    })
    })

    // load keys and re-check signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign));
    });
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign)).then(function(match) {
    console.log("Signature verified after importing PEM public key:", match)
    })
    })
    // should output `Signature verified: true` twice in the console
    });
    });
    }
    })
    })
    }
  5. Andrei revised this gist Mar 20, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion webcryptoapi.js
    Original file line number Diff line number Diff line change
    @@ -157,7 +157,7 @@ if (crypto.subtle) {
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign));
    });

    // load keys and recheck signature
    // load keys and re-check signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign));
    });
  6. Andrei revised this gist Mar 14, 2015. 1 changed file with 9 additions and 11 deletions.
    20 changes: 9 additions & 11 deletions webcryptoapi.js
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,6 @@ function arrayBufferToBase64String(arrayBuffer) {
    return btoa(byteString);
    }


    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str);
    var bytes = new Uint8Array(byteStr.length);
    @@ -144,24 +143,23 @@ function testVerifySig(pub, sig, data) {
    });
    }


    // Do some crypto tests
    // Test everything
    var crypto = window.crypto || window.msCrypto;
    if (crypto.subtle) {
    var keys, signed;
    var toSign = "test";
    var _signedData;
    var _toSign = "test";
    generateRSAKey().then(function(pair) {
    exportPemKeys(pair).then(function(keys) {
    // signData returns an ArrayBuffer; used arraySignatureToBase64() to see the value
    signData(pair.privateKey, toSign).then(function(result) {
    // signData returns an ArrayBuffer; use arraySignatureToBase64() to see the value
    signData(pair.privateKey, _toSign).then(function(signedData) {
    // console.log(arraySignatureToBase64(result));
    signed = result;
    testVerifySig(pair.publicKey, result, textToArrayBuffer(toSign));
    _signedData = signedData;
    testVerifySig(pair.publicKey, signedData, textToArrayBuffer(_toSign));
    });

    // load keys and recheck sig
    // load keys and recheck signature
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, signed, textToArrayBuffer(toSign));
    testVerifySig(key, _signedData, textToArrayBuffer(_toSign));
    });
    // should output `Signature verified: true` twice in the console
    });
  7. Andrei renamed this gist Mar 14, 2015. 1 changed file with 1 addition and 4 deletions.
    5 changes: 1 addition & 4 deletions gistfile1.js → webcryptoapi.js
    Original file line number Diff line number Diff line change
    @@ -125,10 +125,7 @@ function exportPrivateKey(keys) {
    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    document.getElementById("pem-public-key").innerText = pubKey;

    exportPrivateKey(keys).then(function(privKey) {
    document.getElementById("pem-private-key").innerText = privKey;
    resolve({publicKey: pubKey, privateKey: privKey});
    });
    });
    @@ -148,7 +145,7 @@ function testVerifySig(pub, sig, data) {
    }


    // Do the crypto goodness
    // Do some crypto tests
    var crypto = window.crypto || window.msCrypto;
    if (crypto.subtle) {
    var keys, signed;
  8. Andrei revised this gist Mar 14, 2015. No changes.
  9. Andrei revised this gist Mar 14, 2015. No changes.
  10. Andrei revised this gist Mar 14, 2015. No changes.
  11. Andrei revised this gist Mar 14, 2015. 1 changed file with 34 additions and 24 deletions.
    58 changes: 34 additions & 24 deletions gistfile1.js
    Original file line number Diff line number Diff line change
    @@ -86,6 +86,24 @@ function convertPemToBinary(pem) {
    return base64StringToArrayBuffer(encoded);
    }

    function importPublicKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), signAlgorithm, true, ["verify"]);
    importer.then(function(key) {
    resolve(key);
    });
    });
    }

    function importPrivateKey(pemKey) {
    return new Promise(function(resolve) {
    var importer = crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), signAlgorithm, true, ["sign"]);
    importer.then(function(key) {
    resolve(key);
    });
    });
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    @@ -104,7 +122,7 @@ function exportPrivateKey(keys) {
    });
    }

    function exportKeys(keys) {
    function exportPemKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    document.getElementById("pem-public-key").innerText = pubKey;
    @@ -124,39 +142,31 @@ function signData(key, data) {
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data);
    return crypto.subtle.verify(signAlgorithm, pub, sig, data).then(function(match) {
    console.log("Signature verified: "+match);
    });
    }


    // Do the crypto goodness
    var crypto = window.crypto || window.msCrypto;
    if (crypto.subtle) {
    var keys, signed, __pkey;
    var keys, signed;
    var toSign = "test";
    generateRSAKey().then(function(pair) {
    console.log("Pair: ", pair);
    exportKeys(pair).then(function(keys) {
    // console.log(keys);

    // sign
    signData(pair.privateKey, "test").then(function(result) {
    console.log(arraySignatureToBase64(result));
    exportPemKeys(pair).then(function(keys) {
    // signData returns an ArrayBuffer; used arraySignatureToBase64() to see the value
    signData(pair.privateKey, toSign).then(function(result) {
    // console.log(arraySignatureToBase64(result));
    signed = result;
    testVerifySig(pair.publicKey, result, textToArrayBuffer("test")).then(function(verdict) {
    console.log("Signature verified: "+verdict);
    });
    testVerifySig(pair.publicKey, result, textToArrayBuffer(toSign));
    });

    // load keys and check sig
    var parsedPEM = convertPemToBinary(keys.publicKey);
    crypto.subtle.importKey("spki", parsedPEM, signAlgorithm, true, ["verify"]).
    then(function(key) {
    __pkey = key;
    console.log("Parsed key", key);

    testVerifySig(key, signed, textToArrayBuffer("test")).then(function(verdict) {
    console.log("Signature verified again: "+verdict);
    });
    });
    // load keys and recheck sig
    importPublicKey(keys.publicKey).then(function(key) {
    testVerifySig(key, signed, textToArrayBuffer(toSign));
    });
    // should output `Signature verified: true` twice in the console
    });
    });
    }
  12. Andrei revised this gist Mar 14, 2015. No changes.
  13. Andrei created this gist Mar 14, 2015.
    162 changes: 162 additions & 0 deletions gistfile1.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@
    var signAlgorithm = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {
    name: "SHA-256"
    }
    }

    function generateRSAKey() {
    var alg = {
    name: "RSASSA-PKCS1-v1_5",
    hash: {name: "SHA-256"},
    modulusLength: 2048,
    extractable: true,
    publicExponent: new Uint8Array([1, 0, 1])
    };

    return new Promise(function(resolve) {
    var genkey = crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
    genkey.then(function (pair) {
    resolve(pair);
    });
    });
    }

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


    function base64StringToArrayBuffer(b64str) {
    var byteStr = atob(b64str);
    var bytes = new Uint8Array(byteStr.length);
    for (var i = 0; i < byteStr.length; i++) {
    bytes[i] = byteStr.charCodeAt(i);
    }
    return bytes.buffer;
    }

    function textToArrayBuffer(str) {
    var buf = unescape(encodeURIComponent(str)); // 2 bytes for each char
    var bufView = new Uint8Array(buf.length);
    for (var i=0; i < buf.length; i++) {
    bufView[i] = buf.charCodeAt(i);
    }
    return bufView;
    }

    function arraySignatureToBase64(arr) {
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arr)));
    }

    function convertBinaryToPem(binaryData, label) {
    var base64Cert = arrayBufferToBase64String(binaryData);
    var pemCert = "-----BEGIN " + label + "-----\r\n";
    var nextIndex = 0;
    var lineLength;
    while (nextIndex < base64Cert.length) {
    if (nextIndex + 64 <= base64Cert.length) {
    pemCert += base64Cert.substr(nextIndex, 64) + "\r\n";
    } else {
    pemCert += base64Cert.substr(nextIndex) + "\r\n";
    }
    nextIndex += 64;
    }
    pemCert += "-----END " + label + "-----\r\n";
    return pemCert;
    }

    function convertPemToBinary(pem) {
    var lines = pem.split('\n');
    var encoded = '';
    for(var i = 0;i < lines.length;i++){
    if (lines[i].trim().length > 0 &&
    lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
    lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
    lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
    encoded += lines[i].trim();
    }
    }
    return base64StringToArrayBuffer(encoded);
    }

    function exportPublicKey(keys) {
    return new Promise(function(resolve) {
    window.crypto.subtle.exportKey('spki', keys.publicKey).
    then(function(spki) {
    resolve(convertBinaryToPem(spki, "RSA PUBLIC KEY"));
    });
    });
    }

    function exportPrivateKey(keys) {
    return new Promise(function(resolve) {
    var expK = window.crypto.subtle.exportKey('pkcs8', keys.privateKey);
    expK.then(function(pkcs8) {
    resolve(convertBinaryToPem(pkcs8, "RSA PRIVATE KEY"));
    });
    });
    }

    function exportKeys(keys) {
    return new Promise(function(resolve) {
    exportPublicKey(keys).then(function(pubKey) {
    document.getElementById("pem-public-key").innerText = pubKey;

    exportPrivateKey(keys).then(function(privKey) {
    document.getElementById("pem-private-key").innerText = privKey;
    resolve({publicKey: pubKey, privateKey: privKey});
    });
    });
    });
    }

    function signData(key, data) {
    var buffer = textToArrayBuffer(data);
    console.log();
    return window.crypto.subtle.sign(signAlgorithm, key, buffer);
    }

    function testVerifySig(pub, sig, data) {
    return crypto.subtle.verify(signAlgorithm, pub, sig, data);
    }


    // Do the crypto goodness
    var crypto = window.crypto || window.msCrypto;
    if (crypto.subtle) {
    var keys, signed, __pkey;
    generateRSAKey().then(function(pair) {
    console.log("Pair: ", pair);
    exportKeys(pair).then(function(keys) {
    // console.log(keys);

    // sign
    signData(pair.privateKey, "test").then(function(result) {
    console.log(arraySignatureToBase64(result));
    signed = result;
    testVerifySig(pair.publicKey, result, textToArrayBuffer("test")).then(function(verdict) {
    console.log("Signature verified: "+verdict);
    });
    });

    // load keys and check sig
    var parsedPEM = convertPemToBinary(keys.publicKey);
    crypto.subtle.importKey("spki", parsedPEM, signAlgorithm, true, ["verify"]).
    then(function(key) {
    __pkey = key;
    console.log("Parsed key", key);

    testVerifySig(key, signed, textToArrayBuffer("test")).then(function(verdict) {
    console.log("Signature verified again: "+verdict);
    });
    });
    });
    });
    }