diff --git a/crypto.html b/crypto.html index b434df26..316be3c4 100644 --- a/crypto.html +++ b/crypto.html @@ -235,7 +235,7 @@ // Crypto - function pbkdf2(password, salt, iterations, length) { + async function pbkdf2(password, salt, iterations, length) { const importAlg = { name: 'PBKDF2' }; @@ -252,19 +252,19 @@ length: length }; - return window.crypto.subtle.importKey('raw', password, importAlg, false, ['deriveKey']) - .then((importedKey) => { - return window.crypto.subtle.deriveKey(deriveAlg, importedKey, aesOptions, true, ['encrypt']); - }).then((derivedKey) => { - return window.crypto.subtle.exportKey('raw', derivedKey); - }).then((exportedKey) => { - return new ByteData(exportedKey); - }).catch((err) => { - console.error(err); - }); + try { + const importedKey = await window.crypto.subtle.importKey( + 'raw', password, importAlg, false, ['deriveKey']); + const derivedKey = await window.crypto.subtle.deriveKey( + deriveAlg, importedKey, aesOptions, true, ['encrypt']); + const exportedKey = await window.crypto.subtle.exportKey('raw', derivedKey); + return new ByteData(exportedKey); + } catch (err) { + console.log(err); + } } - function aesEncrypt(data, encKey, macKey) { + async function aesEncrypt(data, encKey, macKey) { const keyOptions = { name: 'AES-CBC' }; @@ -276,30 +276,26 @@ window.crypto.getRandomValues(encOptions.iv); const ivData = new ByteData(encOptions.iv.buffer); - let ctData, macData; - return window.crypto.subtle.importKey('raw', encKey.arr.buffer, keyOptions, false, ['encrypt']) - .then((importedKey) => { - return window.crypto.subtle.encrypt(encOptions, importedKey, data); - }).then((encryptedBuffer) => { - ctData = new ByteData(encryptedBuffer); - if (!macKey) { - return null; - } + try { + const importedKey = await window.crypto.subtle.importKey( + 'raw', encKey.arr.buffer, keyOptions, false, ['encrypt']); + const encryptedBuffer = await window.crypto.subtle.encrypt(encOptions, importedKey, data); + const ctData = new ByteData(encryptedBuffer); + let type = encTypes.AesCbc256_B64; + let macData; + if (macKey) { const dataForMac = buildDataForMac(ivData.arr, ctData.arr); - return computeMac(dataForMac.buffer, macKey.arr.buffer); - }).then((macBuffer) => { - let type = encTypes.AesCbc256_B64; - if (macBuffer) { - type = encTypes.AesCbc256_HmacSha256_B64; - macData = new ByteData(macBuffer); - } - return new Cipher(type, ivData, ctData, macData); - }).catch((err) => { - console.error(err); - }); + const macBuffer = await computeMac(dataForMac.buffer, macKey.arr.buffer); + type = encTypes.AesCbc256_HmacSha256_B64; + macData = new ByteData(macBuffer); + } + return new Cipher(type, ivData, ctData, macData); + } catch (err) { + console.error(err); + } } - function aesDecrypt(cipher, encKey, macKey) { + async function aesDecrypt(cipher, encKey, macKey) { const keyOptions = { name: 'AES-CBC' }; @@ -309,84 +305,60 @@ iv: cipher.iv.arr.buffer }; - const checkMacPromise = new Promise((resolve) => { - if (cipher.encType == encTypes.AesCbc256_B64) { - resolve(false); - return; - } - if (!macKey) { - throw 'MAC key not provided.'; - } - resolve(true); - }); - - return checkMacPromise - .then((checkMac) => { - if (!checkMac) { - return null; + try { + const checkMac = cipher.encType != encTypes.AesCbc256_B64; + if (checkMac) { + if (!macKey) { + throw 'MAC key not provided.'; } const dataForMac = buildDataForMac(cipher.iv.arr, cipher.ct.arr); - return computeMac(dataForMac.buffer, macKey.arr.buffer) - }) - .then((macBuffer) => { - if (!macBuffer) { - return true; - } - return macsEqual(cipher.mac.arr.buffer, macBuffer, macKey.arr.buffer); - }).then((macsMatch) => { - if (macsMatch === false) { + const macBuffer = await computeMac(dataForMac.buffer, macKey.arr.buffer); + const macsMatch = await macsEqual(cipher.mac.arr.buffer, macBuffer, macKey.arr.buffer); + if (!macsMatch) { throw 'MAC check failed.'; } - return window.crypto.subtle.importKey('raw', encKey.arr.buffer, keyOptions, false, ['decrypt']); - }).then((importedKey) => { + const importedKey = await window.crypto.subtle.importKey( + 'raw', encKey.arr.buffer, keyOptions, false, ['decrypt']); return window.crypto.subtle.decrypt(decOptions, importedKey, cipher.ct.arr.buffer); - }).catch((err) => { - console.error(err); - }); + } + } catch (err) { + console.error(err); + } } - function computeMac(data, key) { + async function computeMac(data, key) { const alg = { name: 'HMAC', hash: { name: 'SHA-256' } }; - - return window.crypto.subtle.importKey('raw', key, alg, false, ['sign']) - .then((importedKey) => { - return window.crypto.subtle.sign(alg, importedKey, data); - }); + const importedKey = await window.crypto.subtle.importKey('raw', key, alg, false, ['sign']); + return window.crypto.subtle.sign(alg, importedKey, data); } - function macsEqual(mac1Data, mac2Data, key) { + async function macsEqual(mac1Data, mac2Data, key) { const alg = { name: 'HMAC', hash: { name: 'SHA-256' } }; - let mac1, importedMacKey; - return window.crypto.subtle.importKey('raw', key, alg, false, ['sign']) - .then((importedKey) => { - importedMacKey = importedKey; - return window.crypto.subtle.sign(alg, importedMacKey, mac1Data); - }).then((mac) => { - mac1 = mac; - return window.crypto.subtle.sign(alg, importedMacKey, mac2Data); - }).then((mac2) => { - if (mac1.byteLength !== mac2.byteLength) { - return false; - } + const importedMacKey = await window.crypto.subtle.importKey('raw', key, alg, false, ['sign']); + const mac1 = await window.crypto.subtle.sign(alg, importedMacKey, mac1Data); + const mac2 = await window.crypto.subtle.sign(alg, importedMacKey, mac2Data); - const arr1 = new Uint8Array(mac1); - const arr2 = new Uint8Array(mac2); + if (mac1.byteLength !== mac2.byteLength) { + return false; + } - for (let i = 0; i < arr2.length; i++) { - if (arr1[i] !== arr2[i]) { - return false; - } - } + const arr1 = new Uint8Array(mac1); + const arr2 = new Uint8Array(mac2); - return true; - }); + for (let i = 0; i < arr2.length; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + + return true; } function buildDataForMac(ivArr, ctArr) { @@ -396,7 +368,7 @@ return dataForMac; } - function generateRsaKeypair() { + async function generateRsaKeypair() { const rsaOptions = { name: 'RSA-OAEP', modulusLength: 2048, @@ -404,22 +376,17 @@ hash: { name: 'SHA-1' } }; - let keypair, publicKey; - return window.crypto.subtle.generateKey(rsaOptions, true, ['encrypt', 'decrypt']) - .then((generatedKey) => { - keypair = generatedKey; - return window.crypto.subtle.exportKey('spki', keypair.publicKey); - }).then((exportedKey) => { - publicKey = new ByteData(exportedKey); - return window.crypto.subtle.exportKey('pkcs8', keypair.privateKey); - }).then((exportedKey) => { - return { - publicKey: publicKey, - privateKey: new ByteData(exportedKey) - }; - }).catch((err) => { - console.error(err); - }); + try { + const keyPair = await window.crypto.subtle.generateKey(rsaOptions, true, ['encrypt', 'decrypt']); + const publicKey = new ByteData(await window.crypto.subtle.exportKey('spki', keyPair.publicKey)); + const privateKey = new ByteData(await window.crypto.subtle.exportKey('pkcs8', keyPair.privateKey)); + return { + publicKey: publicKey, + privateKey: privateKey + }; + } catch (err) { + console.error(err); + } } async function stretchKey(key) { @@ -488,31 +455,27 @@ } }, watch: { - masterKey(newValue) { + async masterKey(newValue) { const self = this; if (!newValue || !newValue.arr || !self.masterPasswordBuffer) { return new ByteData(); } - pbkdf2(newValue.arr.buffer, self.masterPasswordBuffer, 1, 256) - .then((masterKeyHash) => { - self.masterKeyHash = masterKeyHash; - }); + self.masterKeyHash = await pbkdf2(newValue.arr.buffer, self.masterPasswordBuffer, 1, 256); } }, methods: { - generateKeys() { + async generateKeys() { const self = this; const symKey = new Uint8Array(512 / 8); window.crypto.getRandomValues(symKey); self.symKey = new SymmetricCryptoKey(symKey); - generateRsaKeypair().then((keypair) => { - self.publicKey = keypair.publicKey; - self.privateKey = keypair.privateKey; - }); + const keyPair = await generateRsaKeypair(); + self.publicKey = keyPair.publicKey; + self.privateKey = keyPair.privateKey; } } }); @@ -523,16 +486,13 @@ email: vm.emailBuffer, iterations: vm.pbkdf2Iterations }; - }, (newVal, oldVal) => { + }, async (newVal, oldVal) => { if (!newVal.masterPassword || !newVal.email || !newVal.iterations || newVal.iterations < 1) { vm.masterKey = new ByteData(); return; } - pbkdf2(newVal.masterPassword, newVal.email, newVal.iterations, 256) - .then((masterKey) => { - vm.masterKey = masterKey; - }); + vm.masterKey = await pbkdf2(newVal.masterPassword, newVal.email, newVal.iterations, 256); }); vm.$watch(() => { @@ -540,20 +500,16 @@ symKey: vm.symKey, secret: vm.secretBuffer }; - }, (newVal, oldVal) => { + }, async (newVal, oldVal) => { if (!newVal.symKey || !newVal.secret) { vm.protectedSecret = new Cipher(); vm.unprotectedSecret = ''; return; } - aesEncrypt(newVal.secret, newVal.symKey.encKey, newVal.symKey.macKey) - .then((cipher) => { - vm.protectedSecret = cipher; - return aesDecrypt(vm.protectedSecret, newVal.symKey.encKey, newVal.symKey.macKey); - }).then((secret) => { - vm.unprotectedSecret = toUtf8(secret); - }); + vm.protectedSecret = await aesEncrypt(newVal.secret, newVal.symKey.encKey, newVal.symKey.macKey); + const secret = await aesDecrypt(vm.protectedSecret, newVal.symKey.encKey, newVal.symKey.macKey); + vm.unprotectedSecret = toUtf8(secret); }); vm.$watch(() => { @@ -561,19 +517,15 @@ masterKey: vm.masterKey, symKey: vm.symKey }; - }, (newVal, oldVal) => { + }, async (newVal, oldVal) => { if (!newVal.masterKey || !newVal.masterKey.arr || !newVal.symKey || !newVal.symKey.key) { vm.protectedSymKey = new Cipher(); return; } - aesEncrypt(newVal.symKey.key.arr, newVal.masterKey, null) - .then((cipher) => { - vm.protectedSymKey = cipher; - return aesDecrypt(vm.protectedSymKey, newVal.masterKey, null); - }).then((unprotectedSymKey) => { - vm.unprotectedSymKey = new ByteData(unprotectedSymKey); - }); + vm.protectedSymKey = await aesEncrypt(newVal.symKey.key.arr, newVal.masterKey, null); + const unprotectedSymKey = await aesDecrypt(vm.protectedSymKey, newVal.masterKey, null); + vm.unprotectedSymKey = new ByteData(unprotectedSymKey); }); vm.$watch(() => { @@ -581,19 +533,17 @@ symKey: vm.symKey, privateKey: vm.privateKey }; - }, (newVal, oldVal) => { + }, async (newVal, oldVal) => { if (!newVal.symKey || !newVal.symKey.key || !newVal.privateKey || !newVal.privateKey.arr) { vm.protectedPrivateKey = new Cipher(); return; } - aesEncrypt(newVal.privateKey.arr, newVal.symKey.encKey, newVal.symKey.macKey) - .then((cipher) => { - vm.protectedPrivateKey = cipher; - return aesDecrypt(vm.protectedPrivateKey, newVal.symKey.encKey, newVal.symKey.macKey); - }).then((unprotectedPrivateKey) => { - vm.unprotectedPrivateKey = new ByteData(unprotectedPrivateKey); - }); + vm.protectedPrivateKey = await aesEncrypt(newVal.privateKey.arr, newVal.symKey.encKey, + newVal.symKey.macKey); + const unprotectedPrivateKey = await aesDecrypt(vm.protectedPrivateKey, newVal.symKey.encKey, + newVal.symKey.macKey); + vm.unprotectedPrivateKey = new ByteData(unprotectedPrivateKey); }); // Set default values