From 64ffe028690c9aff50c03e12305aa0724f82a191 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Sat, 14 Dec 2024 01:55:37 +0200 Subject: [PATCH] fix encryption single extra data --- src/components/Chat/ChatDirect.tsx | 7 ++-- src/components/Chat/ChatGroup.tsx | 20 +++++++---- src/qdn/encryption/group-encryption.ts | 48 +++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/components/Chat/ChatDirect.tsx b/src/components/Chat/ChatDirect.tsx index cb40066..9b3dcbb 100644 --- a/src/components/Chat/ChatDirect.tsx +++ b/src/components/Chat/ChatDirect.tsx @@ -363,7 +363,7 @@ useEffect(() => { const htmlContent = editorRef?.current.getHTML(); const stringified = JSON.stringify(htmlContent); const size = new Blob([stringified]).size; - setMessageSize(size + 100); + setMessageSize(size + 200); }; // Add a listener for the editorRef?.current's content updates @@ -646,12 +646,11 @@ useEffect(() => { )} - {messageSize > 750 && ( { )} + + { useEffect(() => { if (!editorRef?.current) return; - handleUpdateRef.current = throttle(() => { + handleUpdateRef.current = throttle(async () => { + try { const htmlContent = editorRef.current.getHTML(); - const size = new TextEncoder().encode(htmlContent).length; - setMessageSize(size + 100); + const message64 = await objectToBase64(JSON.stringify(htmlContent)) + const secretKeyObject = await getSecretKey(false, true) + const encryptSingle = await encryptChatMessage(message64, secretKeyObject) + setMessageSize((encryptSingle?.length || 0) + 200); + } catch (error) { + // calc size error + } }, 1200); const currentEditor = editorRef.current; @@ -822,13 +828,11 @@ const clearEditorContent = () => { - - - {messageSize > 750 && ( + {messageSize > 750 && ( { )} + + { +export const encryptSingle = async ({ data64, secretKeyObject, typeNumber = 2 }: any) => { // Find the highest key in the secretKeyObject const highestKey = Math.max(...Object.keys(secretKeyObject).filter(item => !isNaN(+item)).map(Number)); const highestKeyObject = secretKeyObject[highestKey]; @@ -188,7 +188,22 @@ export const encryptSingle = async ({ data64, secretKeyObject, typeNumber = 1 }: // Concatenate the highest key, type number, nonce, and encrypted data (new format) const highestKeyStr = highestKey.toString().padStart(10, '0'); // Fixed length of 10 digits - finalEncryptedData = btoa(highestKeyStr + typeNumberStr + nonceBase64 + encryptedDataBase64); + + const highestKeyBytes = new TextEncoder().encode(highestKeyStr.padStart(10, '0')); +const typeNumberBytes = new TextEncoder().encode(typeNumberStr.padStart(3, '0')); + +// Step 3: Concatenate all binary +const combinedBinary = new Uint8Array( + highestKeyBytes.length + typeNumberBytes.length + nonce.length + encryptedData.length +); + // finalEncryptedData = btoa(highestKeyStr) + btoa(typeNumberStr) + nonceBase64 + encryptedDataBase64; + combinedBinary.set(highestKeyBytes, 0); +combinedBinary.set(typeNumberBytes, highestKeyBytes.length); +combinedBinary.set(nonce, highestKeyBytes.length + typeNumberBytes.length); +combinedBinary.set(encryptedData, highestKeyBytes.length + typeNumberBytes.length + nonce.length); + +// Step 4: Base64 encode once + finalEncryptedData = uint8ArrayToBase64(combinedBinary); } return finalEncryptedData; @@ -214,10 +229,8 @@ export const decodeBase64ForUIChatMessages = (messages)=> { } return msgs } - - - export const decryptSingle = async ({ data64, secretKeyObject, skipDecodeBase64 }: any) => { +export const decryptSingle = async ({ data64, secretKeyObject, skipDecodeBase64 }: any) => { // First, decode the base64-encoded input (if skipDecodeBase64 is not set) const decodedData = skipDecodeBase64 ? data64 : atob(data64); @@ -249,6 +262,28 @@ export const decodeBase64ForUIChatMessages = (messages)=> { encryptedDataBase64 = decodeForNumber.slice(10); // The remaining part is the encrypted data } else { if (hasTypeNumber) { + // const typeNumberStr = new TextDecoder().decode(typeNumberBytes); + if(decodeForNumber.slice(10, 13) === '002'){ + const decodedBinary = base64ToUint8Array(decodedData); + const highestKeyBytes = decodedBinary.slice(0, 10); // if ASCII digits only + const highestKeyStr = new TextDecoder().decode(highestKeyBytes); + +const nonce = decodedBinary.slice(13, 13 + 24); +const encryptedData = decodedBinary.slice(13 + 24); +const highestKey = parseInt(highestKeyStr, 10); + +const messageKey = base64ToUint8Array(secretKeyObject[+highestKey].messageKey); +const decryptedBytes = nacl.secretbox.open(encryptedData, nonce, messageKey); + + // Check if decryption was successful + if (!decryptedBytes) { + throw new Error("Decryption failed"); + } + + // Convert the decrypted Uint8Array back to a Base64 string + return uint8ArrayToBase64(decryptedBytes); + + } // New format: Extract type number and nonce typeNumberStr = possibleTypeNumberStr; // Extract type number nonceBase64 = decodeForNumber.slice(13, 45); // Extract nonce (next 32 characters after type number) @@ -280,6 +315,9 @@ export const decodeBase64ForUIChatMessages = (messages)=> { // Convert the decrypted Uint8Array back to a Base64 string return uint8ArrayToBase64(decryptedData); }; + + + export const decryptGroupEncryptionWithSharingKey = async ({ data64EncryptedData, key }: any) => {