From bc5031c1949ce497540088c75b6f7fd7c5c4d305 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 12 May 2023 14:53:55 +0300 Subject: [PATCH 1/9] initial working code for group encryption --- .../core/components/qdn-action-encryption.js | 99 ++++++++++++- .../core/components/qdn-action-types.js | 3 + .../plugins/core/qdn/browser/browser.src.js | 135 +++++++++++++++++- 3 files changed, 234 insertions(+), 3 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index 98b26c67..f7446651 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -101,4 +101,101 @@ export const encryptData = ({ data64, recipientPublicKey }) => { console.log({ error }) throw new Error("Error in encrypting data") } -} \ No newline at end of file +} + +export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { + console.log({ recipientPublicKeys, data64 }) + const Uint8ArrayData = base64ToUint8Array(data64) + + if (!(Uint8ArrayData instanceof Uint8Array)) { + throw new Error("The Uint8ArrayData you've submitted is invalid") + } + + try { + const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey + if (!privateKey) { + throw new Error("Unable to retrieve keys") + } + + // Generate a random symmetric key for the message. + const messageKey = new Uint8Array(32); + window.crypto.getRandomValues(messageKey); + + // Encrypt the message with the symmetric key. + const nonce = new Uint8Array(24); + window.crypto.getRandomValues(nonce); + + const encryptedData = nacl.secretbox(Uint8ArrayData, nonce, messageKey); + console.log('front', { encryptedData }) + // Encrypt the symmetric key for each recipient. + let encryptedKeys = []; + recipientPublicKeys.forEach((recipientPublicKey) => { + const publicKeyUnit8Array = window.parent.Base58.decode(recipientPublicKey) + + const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(publicKeyUnit8Array) + + const sharedSecret = new Uint8Array(32) + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) + + // Encrypt the symmetric key with the shared secret. + const keyNonce = new Uint8Array(24); + window.crypto.getRandomValues(keyNonce); + const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret); + + console.log('100', { keyNonce, recipientPublicKey, encryptedKey }) + + encryptedKeys.push({ + recipientPublicKey, + keyNonce, + encryptedKey + }); + }); + + const str = "qortalEncryptedData"; + const strEncoder = new TextEncoder(); + const strUint8Array = strEncoder.encode(str); + console.log('hello4') + // Combine all data into a single Uint8Array. + // Calculate size of combinedData + let combinedDataSize = strUint8Array.length + nonce.length + encryptedData.length + 4; + let encryptedKeysSize = 0; + + encryptedKeys.forEach((key) => { + encryptedKeysSize += key.keyNonce.length + key.encryptedKey.length; + }); + + combinedDataSize += encryptedKeysSize; + + let combinedData = new Uint8Array(combinedDataSize); + + combinedData.set(strUint8Array); + combinedData.set(nonce, strUint8Array.length); + combinedData.set(encryptedData, strUint8Array.length + nonce.length); + console.log('encrypt start', strUint8Array.length + nonce.length) + console.log('encryptedLength2', encryptedData.length) + // Initialize offset for encryptedKeys + let encryptedKeysOffset = strUint8Array.length + nonce.length + encryptedData.length; + console.log('encrypt end', encryptedKeysOffset) + encryptedKeys.forEach((key) => { + combinedData.set(key.keyNonce, encryptedKeysOffset); + console.log('key.keyNonce', key.keyNonce.length) + encryptedKeysOffset += key.keyNonce.length; + + combinedData.set(key.encryptedKey, encryptedKeysOffset); + console.log('key.encryptedKey', key.encryptedKey.length) + encryptedKeysOffset += key.encryptedKey.length; + }); + const countArray = new Uint8Array(new Uint32Array([recipientPublicKeys.length]).buffer); + console.log({ countArray }) + combinedData.set(countArray, combinedData.length - 4); + console.log('totalLength 2', combinedData.length) + const uint8arrayToData64 = uint8ArrayToBase64(combinedData) + + return uint8arrayToData64; + + } catch (error) { + console.log({ error }) + throw new Error("Error in encrypting data") + } +} diff --git a/plugins/plugins/core/components/qdn-action-types.js b/plugins/plugins/core/components/qdn-action-types.js index 666d67f2..f4eb4f16 100644 --- a/plugins/plugins/core/components/qdn-action-types.js +++ b/plugins/plugins/core/components/qdn-action-types.js @@ -43,5 +43,8 @@ export const ENCRYPT_DATA = 'ENCRYPT_DATA' // DECRYPT_DATA export const DECRYPT_DATA = 'DECRYPT_DATA' +// DECRYPT_DATA_GROUP +export const DECRYPT_DATA_GROUP = 'DECRYPT_DATA_GROUP' + // SAVE_FILE export const SAVE_FILE = 'SAVE_FILE' \ No newline at end of file diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index c01bd5d5..494a566c 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -24,7 +24,7 @@ import { QORT_DECIMALS } from '../../../../../crypto/api/constants'; import nacl from '../../../../../crypto/api/deps/nacl-fast.js' import ed2curve from '../../../../../crypto/api/deps/ed2curve.js' import { mimeToExtensionMap } from '../../components/qdn-action-constants'; -import { base64ToUint8Array, encryptData, fileToBase64, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; +import { base64ToUint8Array, encryptData, encryptDataGroup, fileToBase64, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); class WebBrowser extends LitElement { @@ -623,6 +623,118 @@ class WebBrowser extends LitElement { break } } + + case actions.DECRYPT_DATA_GROUP: { + const requiredFields = ['encryptedData', 'publicKeys']; + const missingFields = []; + + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + + if (missingFields.length > 0) { + const missingFieldsString = missingFields.join(', '); + const errorMsg = `Missing fields: ${missingFieldsString}` + let data = {}; + data['error'] = errorMsg; + response = JSON.stringify(data); + break + } + + const { encryptedData: data64EncryptedData, publicKeys } = data + console.log({ publicKeys, data64EncryptedData }) + try { + const allCombined = base64ToUint8Array(data64EncryptedData); + console.log('total length', allCombined.length) + const str = "qortalEncryptedData"; + const strEncoder = new TextEncoder(); + const strUint8Array = strEncoder.encode(str); + + // Extract the nonce + const nonceStartPosition = strUint8Array.length; + const nonceEndPosition = nonceStartPosition + 24; // Nonce is 24 bytes + const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition); + + // Calculate count first + const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) + const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); + console.log({ countArray }) + const count = new Uint32Array(countArray.buffer)[0]; + console.log({ count }) + + // Then use count to calculate encryptedData + const encryptedDataStartPosition = nonceEndPosition; // start position of encryptedData + console.log({ encryptedDataStartPosition }) + const encryptedDataEndPosition = allCombined.length - ((count * (24 + 32 + 16)) + 4); + console.log({ encryptedDataEndPosition }) + const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); + console.log('back', { encryptedData }) + console.log({ encryptedLength: encryptedData.length }) + + // Extract the encrypted keys + const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * (24 + 48))); + + const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey + const senderPublicKey = window.parent.Base58.decode(publicKeys[0]) // Assuming the sender's public key is the first one + + if (!privateKey || !senderPublicKey) { + data['error'] = "Unable to retrieve keys" + response = JSON.stringify(data); + break + } + + const recipientPrivateKeyUint8Array = privateKey + const senderPublicKeyUint8Array = senderPublicKey + + const convertedPrivateKey = ed2curve.convertSecretKey(recipientPrivateKeyUint8Array) + const convertedPublicKey = ed2curve.convertPublicKey(senderPublicKeyUint8Array) + + const sharedSecret = new Uint8Array(32) + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) + console.log({ sharedSecret }) + for (let i = 0; i < count; i++) { + const keyNonce = combinedKeys.slice(i * (24 + 48), i * (24 + 48) + 24); + const encryptedKey = combinedKeys.slice(i * (24 + 48) + 24, (i + 1) * (24 + 48)); + console.log({ keyNonce, encryptedKey }) + // Decrypt the symmetric key. + const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); + console.log({ decryptedKey }) + + // If decryption was successful, decryptedKey will not be null. + if (decryptedKey) { + // Decrypt the data using the symmetric key. + const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey); + + // If decryption was successful, decryptedData will not be null. + if (decryptedData) { + console.log({ decryptedData }) + const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData) + console.log({ decryptedDataToBase64 }) + + response = JSON.stringify(decryptedDataToBase64); + + break; + } + } + } + + if (!response) { + const data = {}; + data['error'] = "Unable to decrypt data"; + response = JSON.stringify(data); + } + } catch (error) { + console.log({ error }) + const data = {}; + const errorMsg = error.message || "Error in decrypting data" + data['error'] = errorMsg; + response = JSON.stringify(data); + } + break; + } + case actions.GET_LIST_ITEMS: { const requiredFields = ['list_name']; const missingFields = []; @@ -895,7 +1007,7 @@ class WebBrowser extends LitElement { break } - if (data.encrypt) { + if (data.encrypt && (!data.type || data.type !== 'group')) { try { const encryptDataResponse = encryptData({ data64, recipientPublicKey: data.recipientPublicKey @@ -913,6 +1025,25 @@ class WebBrowser extends LitElement { } } + if (data.encrypt && data.type && data.type === 'group') { + try { + const encryptDataResponse = encryptDataGroup({ + data64, recipientPublicKeys: data.recipientPublicKeys + }) + if (encryptDataResponse) { + data64 = encryptDataResponse + } + + } catch (error) { + const obj = {}; + const errorMsg = error.message || 'Upload failed due to failed encryption'; + obj['error'] = errorMsg; + response = JSON.stringify(obj); + break + } + + } + const res2 = await showModalAndWait( From 53a3e0e183fa7604fc4d4e09703ba2f2b19f63a9 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 12 May 2023 23:09:15 +0300 Subject: [PATCH 2/9] clean up code --- .../core/components/qdn-action-encryption.js | 29 ++++------ .../plugins/core/qdn/browser/browser.src.js | 57 ++++--------------- 2 files changed, 22 insertions(+), 64 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index f7446651..742b4610 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -103,8 +103,8 @@ export const encryptData = ({ data64, recipientPublicKey }) => { } } -export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { - console.log({ recipientPublicKeys, data64 }) +export const encryptDataGroup = ({ data64, publicKeys }) => { + const publicKeysDuplicateFree = [...new Set(publicKeys)]; const Uint8ArrayData = base64ToUint8Array(data64) if (!(Uint8ArrayData instanceof Uint8Array)) { @@ -121,15 +121,15 @@ export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { const messageKey = new Uint8Array(32); window.crypto.getRandomValues(messageKey); - // Encrypt the message with the symmetric key. const nonce = new Uint8Array(24); window.crypto.getRandomValues(nonce); + // Encrypt the data with the symmetric key. const encryptedData = nacl.secretbox(Uint8ArrayData, nonce, messageKey); - console.log('front', { encryptedData }) + // Encrypt the symmetric key for each recipient. let encryptedKeys = []; - recipientPublicKeys.forEach((recipientPublicKey) => { + publicKeysDuplicateFree.forEach((recipientPublicKey) => { const publicKeyUnit8Array = window.parent.Base58.decode(recipientPublicKey) const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) @@ -138,12 +138,12 @@ export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { const sharedSecret = new Uint8Array(32) nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - // Encrypt the symmetric key with the shared secret. + const keyNonce = new Uint8Array(24); window.crypto.getRandomValues(keyNonce); - const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret); - console.log('100', { keyNonce, recipientPublicKey, encryptedKey }) + // Encrypt the symmetric key with the shared secret. + const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret); encryptedKeys.push({ recipientPublicKey, @@ -155,7 +155,7 @@ export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { const str = "qortalEncryptedData"; const strEncoder = new TextEncoder(); const strUint8Array = strEncoder.encode(str); - console.log('hello4') + // Combine all data into a single Uint8Array. // Calculate size of combinedData let combinedDataSize = strUint8Array.length + nonce.length + encryptedData.length + 4; @@ -172,30 +172,23 @@ export const encryptDataGroup = ({ data64, recipientPublicKeys }) => { combinedData.set(strUint8Array); combinedData.set(nonce, strUint8Array.length); combinedData.set(encryptedData, strUint8Array.length + nonce.length); - console.log('encrypt start', strUint8Array.length + nonce.length) - console.log('encryptedLength2', encryptedData.length) + // Initialize offset for encryptedKeys let encryptedKeysOffset = strUint8Array.length + nonce.length + encryptedData.length; - console.log('encrypt end', encryptedKeysOffset) encryptedKeys.forEach((key) => { combinedData.set(key.keyNonce, encryptedKeysOffset); - console.log('key.keyNonce', key.keyNonce.length) encryptedKeysOffset += key.keyNonce.length; combinedData.set(key.encryptedKey, encryptedKeysOffset); - console.log('key.encryptedKey', key.encryptedKey.length) encryptedKeysOffset += key.encryptedKey.length; }); - const countArray = new Uint8Array(new Uint32Array([recipientPublicKeys.length]).buffer); - console.log({ countArray }) + const countArray = new Uint8Array(new Uint32Array([publicKeysDuplicateFree.length]).buffer); combinedData.set(countArray, combinedData.length - 4); - console.log('totalLength 2', combinedData.length) const uint8arrayToData64 = uint8ArrayToBase64(combinedData) return uint8arrayToData64; } catch (error) { - console.log({ error }) throw new Error("Error in encrypting data") } } diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index 494a566c..effadb7e 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -625,7 +625,7 @@ class WebBrowser extends LitElement { } case actions.DECRYPT_DATA_GROUP: { - const requiredFields = ['encryptedData', 'publicKeys']; + const requiredFields = ['encryptedData']; const missingFields = []; requiredFields.forEach((field) => { @@ -643,11 +643,9 @@ class WebBrowser extends LitElement { break } - const { encryptedData: data64EncryptedData, publicKeys } = data - console.log({ publicKeys, data64EncryptedData }) + const { encryptedData: data64EncryptedData } = data try { const allCombined = base64ToUint8Array(data64EncryptedData); - console.log('total length', allCombined.length) const str = "qortalEncryptedData"; const strEncoder = new TextEncoder(); const strUint8Array = strEncoder.encode(str); @@ -660,47 +658,35 @@ class WebBrowser extends LitElement { // Calculate count first const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); - console.log({ countArray }) const count = new Uint32Array(countArray.buffer)[0]; - console.log({ count }) // Then use count to calculate encryptedData const encryptedDataStartPosition = nonceEndPosition; // start position of encryptedData - console.log({ encryptedDataStartPosition }) const encryptedDataEndPosition = allCombined.length - ((count * (24 + 32 + 16)) + 4); - console.log({ encryptedDataEndPosition }) const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); - console.log('back', { encryptedData }) - console.log({ encryptedLength: encryptedData.length }) // Extract the encrypted keys const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * (24 + 48))); const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - const senderPublicKey = window.parent.Base58.decode(publicKeys[0]) // Assuming the sender's public key is the first one + const publicKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey - if (!privateKey || !senderPublicKey) { + if (!privateKey || !publicKey) { data['error'] = "Unable to retrieve keys" response = JSON.stringify(data); break } - const recipientPrivateKeyUint8Array = privateKey - const senderPublicKeyUint8Array = senderPublicKey - - const convertedPrivateKey = ed2curve.convertSecretKey(recipientPrivateKeyUint8Array) - const convertedPublicKey = ed2curve.convertPublicKey(senderPublicKeyUint8Array) + const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(publicKey) const sharedSecret = new Uint8Array(32) nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - console.log({ sharedSecret }) for (let i = 0; i < count; i++) { const keyNonce = combinedKeys.slice(i * (24 + 48), i * (24 + 48) + 24); const encryptedKey = combinedKeys.slice(i * (24 + 48) + 24, (i + 1) * (24 + 48)); - console.log({ keyNonce, encryptedKey }) // Decrypt the symmetric key. const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); - console.log({ decryptedKey }) // If decryption was successful, decryptedKey will not be null. if (decryptedKey) { @@ -709,12 +695,8 @@ class WebBrowser extends LitElement { // If decryption was successful, decryptedData will not be null. if (decryptedData) { - console.log({ decryptedData }) const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData) - console.log({ decryptedDataToBase64 }) - response = JSON.stringify(decryptedDataToBase64); - break; } } @@ -952,6 +934,7 @@ class WebBrowser extends LitElement { return; case actions.PUBLISH_QDN_RESOURCE: { + console.log({ data }) // optional fields: encrypt:boolean recipientPublicKey:string const requiredFields = ['service', 'name']; const missingFields = []; @@ -994,9 +977,9 @@ class WebBrowser extends LitElement { identifier = 'default'; } - if (data.encrypt && !data.recipientPublicKey) { + if (data.encrypt && (!data.publicKeys || (Array.isArray(data.publicKeys) && data.publicKeys.length === 0))) { let data = {}; - data['error'] = "Encrypting data requires the recipient's public key"; + data['error'] = "Encrypting data requires public keys"; response = JSON.stringify(data); break } @@ -1007,28 +990,10 @@ class WebBrowser extends LitElement { break } - if (data.encrypt && (!data.type || data.type !== 'group')) { - try { - const encryptDataResponse = encryptData({ - data64, recipientPublicKey: data.recipientPublicKey - }) - if (encryptDataResponse.encryptedData) { - data64 = encryptDataResponse.encryptedData - } - - } catch (error) { - const obj = {}; - const errorMsg = error.message || 'Upload failed due to failed encryption'; - obj['error'] = errorMsg; - response = JSON.stringify(obj); - break - } - - } - if (data.encrypt && data.type && data.type === 'group') { + if (data.encrypt) { try { const encryptDataResponse = encryptDataGroup({ - data64, recipientPublicKeys: data.recipientPublicKeys + data64, publicKeys: data.publicKeys }) if (encryptDataResponse) { data64 = encryptDataResponse From 52d2f67e214031a1c4365fbefe979b8c16f13261 Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 13 May 2023 01:47:40 +0300 Subject: [PATCH 3/9] only one nonce --- .../core/components/qdn-action-encryption.js | 56 ++++++++++++------- .../plugins/core/qdn/browser/browser.src.js | 24 ++++---- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index 742b4610..d91fd4b5 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -127,6 +127,10 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { // Encrypt the data with the symmetric key. const encryptedData = nacl.secretbox(Uint8ArrayData, nonce, messageKey); + // Generate a keyNonce outside of the loop. + const keyNonce = new Uint8Array(24); + window.crypto.getRandomValues(keyNonce); + // Encrypt the symmetric key for each recipient. let encryptedKeys = []; publicKeysDuplicateFree.forEach((recipientPublicKey) => { @@ -136,20 +140,15 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { const convertedPublicKey = ed2curve.convertPublicKey(publicKeyUnit8Array) const sharedSecret = new Uint8Array(32) + // the length of the sharedSecret will be 32 + 16 + // When you're encrypting data using nacl.secretbox, it's adding an authentication tag to the result, which is 16 bytes long. This tag is used for verifying the integrity and authenticity of the data when it is decrypted + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - - const keyNonce = new Uint8Array(24); - window.crypto.getRandomValues(keyNonce); - // Encrypt the symmetric key with the shared secret. const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret); - encryptedKeys.push({ - recipientPublicKey, - keyNonce, - encryptedKey - }); + encryptedKeys.push(encryptedKey); }); const str = "qortalEncryptedData"; @@ -158,11 +157,11 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { // Combine all data into a single Uint8Array. // Calculate size of combinedData - let combinedDataSize = strUint8Array.length + nonce.length + encryptedData.length + 4; + let combinedDataSize = strUint8Array.length + nonce.length + keyNonce.length + encryptedData.length + 4; let encryptedKeysSize = 0; encryptedKeys.forEach((key) => { - encryptedKeysSize += key.keyNonce.length + key.encryptedKey.length; + encryptedKeysSize += key.length; }); combinedDataSize += encryptedKeysSize; @@ -171,24 +170,43 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { combinedData.set(strUint8Array); combinedData.set(nonce, strUint8Array.length); - combinedData.set(encryptedData, strUint8Array.length + nonce.length); + combinedData.set(keyNonce, strUint8Array.length + nonce.length); + combinedData.set(encryptedData, strUint8Array.length + nonce.length + keyNonce.length); // Initialize offset for encryptedKeys - let encryptedKeysOffset = strUint8Array.length + nonce.length + encryptedData.length; + let encryptedKeysOffset = strUint8Array.length + nonce.length + encryptedData.length + keyNonce.length; encryptedKeys.forEach((key) => { - combinedData.set(key.keyNonce, encryptedKeysOffset); - encryptedKeysOffset += key.keyNonce.length; - - combinedData.set(key.encryptedKey, encryptedKeysOffset); - encryptedKeysOffset += key.encryptedKey.length; + combinedData.set(key, encryptedKeysOffset); + encryptedKeysOffset += key.length; }); const countArray = new Uint8Array(new Uint32Array([publicKeysDuplicateFree.length]).buffer); combinedData.set(countArray, combinedData.length - 4); const uint8arrayToData64 = uint8ArrayToBase64(combinedData) - return uint8arrayToData64; } catch (error) { throw new Error("Error in encrypting data") } } + + +export function uint8ArrayStartsWith(uint8Array, string) { + const stringEncoder = new TextEncoder(); + const stringUint8Array = stringEncoder.encode(string); + + if (uint8Array.length < stringUint8Array.length) { + return false; + } + + for (let i = 0; i < stringUint8Array.length; i++) { + if (uint8Array[i] !== stringUint8Array[i]) { + return false; + } + } + + return true; +} + +export function decryptDeprecatedSingle() { + +} \ No newline at end of file diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index effadb7e..13f20f8e 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -24,7 +24,7 @@ import { QORT_DECIMALS } from '../../../../../crypto/api/constants'; import nacl from '../../../../../crypto/api/deps/nacl-fast.js' import ed2curve from '../../../../../crypto/api/deps/ed2curve.js' import { mimeToExtensionMap } from '../../components/qdn-action-constants'; -import { base64ToUint8Array, encryptData, encryptDataGroup, fileToBase64, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; +import { base64ToUint8Array, encryptData, encryptDataGroup, fileToBase64, uint8ArrayStartsWith, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); class WebBrowser extends LitElement { @@ -585,6 +585,8 @@ class WebBrowser extends LitElement { try { const uint8Array = base64ToUint8Array(encryptedData) + const startsWithQortalEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalEncryptedData"); + const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalGroupEncryptedData"); const combinedData = uint8Array const str = "qortalEncryptedData"; const strEncoder = new TextEncoder(); @@ -642,7 +644,6 @@ class WebBrowser extends LitElement { response = JSON.stringify(data); break } - const { encryptedData: data64EncryptedData } = data try { const allCombined = base64ToUint8Array(data64EncryptedData); @@ -655,19 +656,24 @@ class WebBrowser extends LitElement { const nonceEndPosition = nonceStartPosition + 24; // Nonce is 24 bytes const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition); + // Extract the shared keyNonce + const keyNonceStartPosition = nonceEndPosition; + const keyNonceEndPosition = keyNonceStartPosition + 24; // Nonce is 24 bytes + const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition); + // Calculate count first const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); const count = new Uint32Array(countArray.buffer)[0]; // Then use count to calculate encryptedData - const encryptedDataStartPosition = nonceEndPosition; // start position of encryptedData - const encryptedDataEndPosition = allCombined.length - ((count * (24 + 32 + 16)) + 4); + const encryptedDataStartPosition = keyNonceEndPosition; // start position of encryptedData + const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4); const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); // Extract the encrypted keys - const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * (24 + 48))); - + // 32+16 = 48 + const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48)); const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey const publicKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey @@ -679,15 +685,12 @@ class WebBrowser extends LitElement { const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) const convertedPublicKey = ed2curve.convertPublicKey(publicKey) - const sharedSecret = new Uint8Array(32) nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) for (let i = 0; i < count; i++) { - const keyNonce = combinedKeys.slice(i * (24 + 48), i * (24 + 48) + 24); - const encryptedKey = combinedKeys.slice(i * (24 + 48) + 24, (i + 1) * (24 + 48)); + const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48); // Decrypt the symmetric key. const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); - // If decryption was successful, decryptedKey will not be null. if (decryptedKey) { // Decrypt the data using the symmetric key. @@ -934,7 +937,6 @@ class WebBrowser extends LitElement { return; case actions.PUBLISH_QDN_RESOURCE: { - console.log({ data }) // optional fields: encrypt:boolean recipientPublicKey:string const requiredFields = ['service', 'name']; const missingFields = []; From cb9d5e44a938b03c02fd1f390459c35544dc1859 Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 13 May 2023 02:47:32 +0300 Subject: [PATCH 4/9] added string check --- .../core/components/qdn-action-encryption.js | 94 +++++++++- .../plugins/core/qdn/browser/browser.src.js | 174 ++++-------------- 2 files changed, 131 insertions(+), 137 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index d91fd4b5..3a3adfb6 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -207,6 +207,98 @@ export function uint8ArrayStartsWith(uint8Array, string) { return true; } -export function decryptDeprecatedSingle() { +export function decryptDeprecatedSingle(uint8Array, publicKey) { + const combinedData = uint8Array + const str = "qortalEncryptedData"; + const strEncoder = new TextEncoder(); + const strUint8Array = strEncoder.encode(str); + const strData = combinedData.slice(0, strUint8Array.length); + const nonce = combinedData.slice(strUint8Array.length, strUint8Array.length + 24); + const _encryptedData = combinedData.slice(strUint8Array.length + 24); + + const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey + const _publicKey = window.parent.Base58.decode(publicKey) + + if (!privateKey || !_publicKey) { + + throw new Error("Unable to retrieve keys") + } + + const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(_publicKey) + const sharedSecret = new Uint8Array(32); + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) + + const _chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result + const _decryptedData = nacl.secretbox.open(_encryptedData, nonce, _chatEncryptionSeed) + if (!_decryptedData) { + throw new Error("Unable to decrypt") + } + const decryptedDataToBase64 = uint8ArrayToBase64(_decryptedData) + return decryptedDataToBase64 +} + +export function decryptGroupData(data64EncryptedData) { + const allCombined = base64ToUint8Array(data64EncryptedData); + const str = "qortalEncryptedData"; + const strEncoder = new TextEncoder(); + const strUint8Array = strEncoder.encode(str); + + // Extract the nonce + const nonceStartPosition = strUint8Array.length; + const nonceEndPosition = nonceStartPosition + 24; // Nonce is 24 bytes + const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition); + + // Extract the shared keyNonce + const keyNonceStartPosition = nonceEndPosition; + const keyNonceEndPosition = keyNonceStartPosition + 24; // Nonce is 24 bytes + const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition); + + // Calculate count first + const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) + const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); + const count = new Uint32Array(countArray.buffer)[0]; + + // Then use count to calculate encryptedData + const encryptedDataStartPosition = keyNonceEndPosition; // start position of encryptedData + const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4); + const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); + + // Extract the encrypted keys + // 32+16 = 48 + const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48)); + const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey + const publicKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey + + if (!privateKey || !publicKey) { + throw new Error("Unable to retrieve keys") + } + + const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(publicKey) + const sharedSecret = new Uint8Array(32) + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) + for (let i = 0; i < count; i++) { + const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48); + // Decrypt the symmetric key. + const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); + // If decryption was successful, decryptedKey will not be null. + if (decryptedKey) { + // Decrypt the data using the symmetric key. + const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey); + + // If decryption was successful, decryptedData will not be null. + if (decryptedData) { + console.log({ decryptedData }) + return decryptedData + + } + } + } + + if (!response) { + throw new Erorr("Unable to decrypt data") + + } } \ No newline at end of file diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index 13f20f8e..f04aa31c 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -24,7 +24,7 @@ import { QORT_DECIMALS } from '../../../../../crypto/api/constants'; import nacl from '../../../../../crypto/api/deps/nacl-fast.js' import ed2curve from '../../../../../crypto/api/deps/ed2curve.js' import { mimeToExtensionMap } from '../../components/qdn-action-constants'; -import { base64ToUint8Array, encryptData, encryptDataGroup, fileToBase64, uint8ArrayStartsWith, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; +import { base64ToUint8Array, decryptDeprecatedSingle, decryptGroupData, encryptData, encryptDataGroup, fileToBase64, uint8ArrayStartsWith, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); class WebBrowser extends LitElement { @@ -563,161 +563,63 @@ class WebBrowser extends LitElement { } case actions.DECRYPT_DATA: { - const requiredFields = ['encryptedData', 'publicKey']; - const missingFields = []; - requiredFields.forEach((field) => { - if (!data[field]) { - missingFields.push(field); - } - }); - - if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(', '); - const errorMsg = `Missing fields: ${missingFieldsString}` - let data = {}; - data['error'] = errorMsg; - response = JSON.stringify(data); - break - } const { encryptedData, publicKey } = data try { + let data = {}; + if (!encryptedData) { + const errorMsg = `Missing fields: encryptedData` + + data['error'] = errorMsg; + response = JSON.stringify(data); + break + + } const uint8Array = base64ToUint8Array(encryptedData) const startsWithQortalEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalEncryptedData"); - const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalGroupEncryptedData"); - const combinedData = uint8Array - const str = "qortalEncryptedData"; - const strEncoder = new TextEncoder(); - const strUint8Array = strEncoder.encode(str); - const strData = combinedData.slice(0, strUint8Array.length); - const nonce = combinedData.slice(strUint8Array.length, strUint8Array.length + 24); - const _encryptedData = combinedData.slice(strUint8Array.length + 24); + if (startsWithQortalEncryptedData) { - const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - const _publicKey = window.parent.Base58.decode(publicKey) + if (!publicKey) { + const errorMsg = `Missing fields: publicKey` - if (!privateKey || !_publicKey) { - data['error'] = "Unable to retrieve keys" - response = JSON.stringify(data); - break - } - - const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(_publicKey) - const sharedSecret = new Uint8Array(32); - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - - const _chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result - const _decryptedData = nacl.secretbox.open(_encryptedData, nonce, _chatEncryptionSeed) - const decryptedDataToBase64 = uint8ArrayToBase64(_decryptedData) - response = JSON.stringify(decryptedDataToBase64); - - break; - } catch (error) { - console.log({ error }) - const data = {}; - const errorMsg = error.message || "Error in decrypting data" - data['error'] = errorMsg; - response = JSON.stringify(data); - break - } - } - - case actions.DECRYPT_DATA_GROUP: { - const requiredFields = ['encryptedData']; - const missingFields = []; - - requiredFields.forEach((field) => { - if (!data[field]) { - missingFields.push(field); - } - }); - - if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(', '); - const errorMsg = `Missing fields: ${missingFieldsString}` - let data = {}; - data['error'] = errorMsg; - response = JSON.stringify(data); - break - } - const { encryptedData: data64EncryptedData } = data - try { - const allCombined = base64ToUint8Array(data64EncryptedData); - const str = "qortalEncryptedData"; - const strEncoder = new TextEncoder(); - const strUint8Array = strEncoder.encode(str); - - // Extract the nonce - const nonceStartPosition = strUint8Array.length; - const nonceEndPosition = nonceStartPosition + 24; // Nonce is 24 bytes - const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition); - - // Extract the shared keyNonce - const keyNonceStartPosition = nonceEndPosition; - const keyNonceEndPosition = keyNonceStartPosition + 24; // Nonce is 24 bytes - const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition); - - // Calculate count first - const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) - const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); - const count = new Uint32Array(countArray.buffer)[0]; - - // Then use count to calculate encryptedData - const encryptedDataStartPosition = keyNonceEndPosition; // start position of encryptedData - const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4); - const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); - - // Extract the encrypted keys - // 32+16 = 48 - const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48)); - const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - const publicKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey - - if (!privateKey || !publicKey) { - data['error'] = "Unable to retrieve keys" - response = JSON.stringify(data); - break - } - - const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(publicKey) - const sharedSecret = new Uint8Array(32) - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - for (let i = 0; i < count; i++) { - const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48); - // Decrypt the symmetric key. - const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); - // If decryption was successful, decryptedKey will not be null. - if (decryptedKey) { - // Decrypt the data using the symmetric key. - const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey); - - // If decryption was successful, decryptedData will not be null. - if (decryptedData) { - const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData) - response = JSON.stringify(decryptedDataToBase64); - break; - } + data['error'] = errorMsg; + response = JSON.stringify(data); + break } + + + const decryptedDataToBase64 = decryptDeprecatedSingle(uint8Array, publicKey) + response = JSON.stringify(decryptedDataToBase64); + break; + + + } + const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalGroupEncryptedData"); + + if (startsWithQortalGroupEncryptedData) { + + const decryptedData = decryptGroupData(encryptedData) + const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData) + response = JSON.stringify(decryptedDataToBase64); + break; + } - if (!response) { - const data = {}; - data['error'] = "Unable to decrypt data"; - response = JSON.stringify(data); - } + const errorMsg = "Unable to decrypt" + data['error'] = errorMsg; + response = JSON.stringify(data); + break } catch (error) { console.log({ error }) const data = {}; const errorMsg = error.message || "Error in decrypting data" data['error'] = errorMsg; response = JSON.stringify(data); + break } - break; } case actions.GET_LIST_ITEMS: { From adc8ba42a0fed3b35d80ea16404e83e38d0d388f Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 13 May 2023 03:33:18 +0300 Subject: [PATCH 5/9] added to multiple --- plugins/plugins/core/qdn/browser/browser.src.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index f04aa31c..9889d87e 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -1007,9 +1007,9 @@ class WebBrowser extends LitElement { response = JSON.stringify(data); break } - if (data.encrypt && !data.recipientPublicKey) { + if (data.encrypt && (!data.publicKeys || (Array.isArray(data.publicKeys) && data.publicKeys.length === 0))) { let data = {}; - data['error'] = "Encrypting data requires the recipient's public key"; + data['error'] = "Encrypting data requires public keys"; response = JSON.stringify(data); break } @@ -1068,13 +1068,14 @@ class WebBrowser extends LitElement { throw new Error("Only encrypted data can go into private services") } + if (data.encrypt) { try { - const encryptDataResponse = encryptData({ - data64, recipientPublicKey: data.recipientPublicKey + const encryptDataResponse = encryptDataGroup({ + data64, publicKeys: data.publicKeys }) - if (encryptDataResponse.encryptedData) { - data64 = encryptDataResponse.encryptedData + if (encryptDataResponse) { + data64 = encryptDataResponse } } catch (error) { From cfe9a0c0a3987db54ac0b456cbbf7deeaa343053 Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 13 May 2023 03:39:18 +0300 Subject: [PATCH 6/9] added ui user public key --- plugins/plugins/core/components/qdn-action-encryption.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index 3a3adfb6..eeaa37f6 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -104,7 +104,12 @@ export const encryptData = ({ data64, recipientPublicKey }) => { } export const encryptDataGroup = ({ data64, publicKeys }) => { - const publicKeysDuplicateFree = [...new Set(publicKeys)]; + const userPublicKey = window.parent.Base58.decode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey) + let combinedPublicKeys = publicKeys + if (userPublicKey) { + combinedPublicKeys = [...publicKeys, userPublicKey] + } + const publicKeysDuplicateFree = [...new Set(combinedPublicKeys)]; const Uint8ArrayData = base64ToUint8Array(data64) if (!(Uint8ArrayData instanceof Uint8Array)) { From 430413c572e1f820c7bb88332a73983d46de6647 Mon Sep 17 00:00:00 2001 From: Phillip Date: Thu, 25 May 2023 21:39:48 +0300 Subject: [PATCH 7/9] fix base58 publicKey --- plugins/plugins/core/components/qdn-action-encryption.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index eeaa37f6..cd990395 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -104,11 +104,12 @@ export const encryptData = ({ data64, recipientPublicKey }) => { } export const encryptDataGroup = ({ data64, publicKeys }) => { - const userPublicKey = window.parent.Base58.decode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey) + const userPublicKey = window.parent.reduxStore.getState().app.selectedAddress.base58PublicKey let combinedPublicKeys = publicKeys if (userPublicKey) { combinedPublicKeys = [...publicKeys, userPublicKey] } + const publicKeysDuplicateFree = [...new Set(combinedPublicKeys)]; const Uint8ArrayData = base64ToUint8Array(data64) From 4ee98333141c302ddf37b0afb0c6133d9aaf5e3f Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 3 Jun 2023 18:22:16 +0300 Subject: [PATCH 8/9] added file option to encript --- .../plugins/core/components/qdn-action-encryption.js | 4 ++-- plugins/plugins/core/qdn/browser/browser.src.js | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index cd990395..a017d95e 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -157,7 +157,7 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { encryptedKeys.push(encryptedKey); }); - const str = "qortalEncryptedData"; + const str = "qortalGroupEncryptedData"; const strEncoder = new TextEncoder(); const strUint8Array = strEncoder.encode(str); @@ -247,7 +247,7 @@ export function decryptDeprecatedSingle(uint8Array, publicKey) { export function decryptGroupData(data64EncryptedData) { const allCombined = base64ToUint8Array(data64EncryptedData); - const str = "qortalEncryptedData"; + const str = "qortalGroupEncryptedData"; const strEncoder = new TextEncoder(); const strUint8Array = strEncoder.encode(str); diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js index 9889d87e..f0ebaed0 100644 --- a/plugins/plugins/core/qdn/browser/browser.src.js +++ b/plugins/plugins/core/qdn/browser/browser.src.js @@ -566,7 +566,6 @@ class WebBrowser extends LitElement { const { encryptedData, publicKey } = data - try { let data = {}; if (!encryptedData) { @@ -579,7 +578,6 @@ class WebBrowser extends LitElement { } const uint8Array = base64ToUint8Array(encryptedData) const startsWithQortalEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalEncryptedData"); - if (startsWithQortalEncryptedData) { if (!publicKey) { @@ -598,7 +596,6 @@ class WebBrowser extends LitElement { } const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalGroupEncryptedData"); - if (startsWithQortalGroupEncryptedData) { const decryptedData = decryptGroupData(encryptedData) @@ -893,6 +890,9 @@ class WebBrowser extends LitElement { response = JSON.stringify(data); break } + if (data.file) { + data64 = await fileToBase64(data.file) + } if (data.encrypt) { try { @@ -1067,10 +1067,14 @@ class WebBrowser extends LitElement { if (!data.encrypt && service.endsWith("_PRIVATE")) { throw new Error("Only encrypted data can go into private services") } + if (data.file) { + data64 = await fileToBase64(data.file) + } if (data.encrypt) { try { + const encryptDataResponse = encryptDataGroup({ data64, publicKeys: data.publicKeys }) From 27843d8970e1c4ab1ab56d90ee8cd68f0a5164c7 Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 8 Jul 2023 02:24:39 +0300 Subject: [PATCH 9/9] fixed bug when open sender's encrypted data --- .../core/components/qdn-action-encryption.js | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/plugins/plugins/core/components/qdn-action-encryption.js b/plugins/plugins/core/components/qdn-action-encryption.js index a017d95e..b7b416f6 100644 --- a/plugins/plugins/core/components/qdn-action-encryption.js +++ b/plugins/plugins/core/components/qdn-action-encryption.js @@ -98,7 +98,6 @@ export const encryptData = ({ data64, recipientPublicKey }) => { recipientPublicKey } } catch (error) { - console.log({ error }) throw new Error("Error in encrypting data") } } @@ -156,14 +155,16 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { encryptedKeys.push(encryptedKey); }); - const str = "qortalGroupEncryptedData"; const strEncoder = new TextEncoder(); const strUint8Array = strEncoder.encode(str); + // Convert sender's public key to Uint8Array and add to the message + const senderPublicKeyUint8Array = window.parent.Base58.decode(userPublicKey); + // Combine all data into a single Uint8Array. // Calculate size of combinedData - let combinedDataSize = strUint8Array.length + nonce.length + keyNonce.length + encryptedData.length + 4; + let combinedDataSize = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length + 4; let encryptedKeysSize = 0; encryptedKeys.forEach((key) => { @@ -177,10 +178,11 @@ export const encryptDataGroup = ({ data64, publicKeys }) => { combinedData.set(strUint8Array); combinedData.set(nonce, strUint8Array.length); combinedData.set(keyNonce, strUint8Array.length + nonce.length); - combinedData.set(encryptedData, strUint8Array.length + nonce.length + keyNonce.length); + combinedData.set(senderPublicKeyUint8Array, strUint8Array.length + nonce.length + keyNonce.length); + combinedData.set(encryptedData, strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length); // Initialize offset for encryptedKeys - let encryptedKeysOffset = strUint8Array.length + nonce.length + encryptedData.length + keyNonce.length; + let encryptedKeysOffset = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length; encryptedKeys.forEach((key) => { combinedData.set(key, encryptedKeysOffset); encryptedKeysOffset += key.length; @@ -261,13 +263,18 @@ export function decryptGroupData(data64EncryptedData) { const keyNonceEndPosition = keyNonceStartPosition + 24; // Nonce is 24 bytes const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition); + // Extract the sender's public key + const senderPublicKeyStartPosition = keyNonceEndPosition; + const senderPublicKeyEndPosition = senderPublicKeyStartPosition + 32; // Public keys are 32 bytes + const senderPublicKey = allCombined.slice(senderPublicKeyStartPosition, senderPublicKeyEndPosition); + // Calculate count first const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes) const countArray = allCombined.slice(countStartPosition, countStartPosition + 4); const count = new Uint32Array(countArray.buffer)[0]; // Then use count to calculate encryptedData - const encryptedDataStartPosition = keyNonceEndPosition; // start position of encryptedData + const encryptedDataStartPosition = senderPublicKeyEndPosition; // start position of encryptedData const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4); const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition); @@ -275,20 +282,21 @@ export function decryptGroupData(data64EncryptedData) { // 32+16 = 48 const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48)); const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - const publicKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey - if (!privateKey || !publicKey) { + if (!privateKey) { throw new Error("Unable to retrieve keys") } const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(publicKey) + const convertedSenderPublicKey = ed2curve.convertPublicKey(senderPublicKey) const sharedSecret = new Uint8Array(32) - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedSenderPublicKey) for (let i = 0; i < count; i++) { const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48); + // Decrypt the symmetric key. const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret); + // If decryption was successful, decryptedKey will not be null. if (decryptedKey) { // Decrypt the data using the symmetric key. @@ -296,15 +304,11 @@ export function decryptGroupData(data64EncryptedData) { // If decryption was successful, decryptedData will not be null. if (decryptedData) { - console.log({ decryptedData }) - return decryptedData + return decryptedData } } } - if (!response) { - throw new Erorr("Unable to decrypt data") - - } -} \ No newline at end of file + throw new Error("Unable to decrypt data") +}