From 0e249b2e6d84956445ac35a2edee363de16f2b1a Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 8 May 2025 14:34:38 -0400 Subject: [PATCH] Work to improve encryption and decryption --- src/lib/ae_utils/ae_utils.ts | 5 +- src/lib/ae_utils/ae_utils__crypto.ts | 63 +++++++++++++++- .../ae_comp__journal_entry_obj_id_view.svelte | 74 ++++++++++++------- 3 files changed, 112 insertions(+), 30 deletions(-) diff --git a/src/lib/ae_utils/ae_utils.ts b/src/lib/ae_utils/ae_utils.ts index ecc42b1e..2f78a9fc 100644 --- a/src/lib/ae_utils/ae_utils.ts +++ b/src/lib/ae_utils/ae_utils.ts @@ -10,7 +10,7 @@ import { to_title_case } from './ae_utils__to_title_case'; import { process_data_string } from './ae_utils__process_data_string'; import { set_obj_prop_display_name } from './ae_utils__set_obj_prop_display_name'; import { return_obj_type_path } from './ae_utils__return_obj_type_path'; -import { encrypt_content, decrypt_content } from './ae_utils__crypto'; +import { combine_iv_and_base64, encrypt_content, encrypt_wrapper, decrypt_content, decrypt_wrapper } from './ae_utils__crypto'; export type key_str = { @@ -264,6 +264,9 @@ export let ae_util = { file_extension_icon: file_extension_icon, set_obj_prop_display_name: set_obj_prop_display_name, return_obj_type_path: return_obj_type_path, + combine_iv_and_base64: combine_iv_and_base64, encrypt_content: encrypt_content, + encrypt_wrapper: encrypt_wrapper, decrypt_content: decrypt_content, + decrypt_wrapper: decrypt_wrapper, }; diff --git a/src/lib/ae_utils/ae_utils__crypto.ts b/src/lib/ae_utils/ae_utils__crypto.ts index ee506536..40fdce30 100644 --- a/src/lib/ae_utils/ae_utils__crypto.ts +++ b/src/lib/ae_utils/ae_utils__crypto.ts @@ -1,3 +1,5 @@ +let log_lvl = 1; // 0 = no logging, 1 = some logging, 2 = all logging + async function generate_iv() { const data = new Uint8Array(16); crypto.getRandomValues(data); @@ -6,7 +8,8 @@ async function generate_iv() { export let encrypt_content = async function encrypt_content( - content: string, keyData: string + content: string, + keyData: string ) { const iv = await generate_iv(); const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData)); @@ -17,10 +20,36 @@ export let encrypt_content = async function encrypt_content( return { base64, iv }; } +export let combine_iv_and_base64 = function combine_iv_and_base64( + base64: string, + iv: Uint8Array + ) { + console.log(`IV: ${iv}; Encrypted: ${base64}`); + + // Combine the IV and encrypted content + const combined = Array.from(iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + base64; + console.log('Combined Data v1:', combined); + + // const ivBase64 = btoa(String.fromCharCode(...iv)); + // const combined = `${ivBase64}:${base64}`; + // console.log('Combined IV and Base64 v2:', combined); + return combined; +} + +export let encrypt_wrapper = async function encrypt_wrapper( + content: string, + keyData: string + ) { + const { base64, iv } = await encrypt_content(content, keyData); + const combined = combine_iv_and_base64(base64, iv); + return combined; +} // This does not handle errors (invalid key/password) well. export let decrypt_content = async function decrypt_content( - base64Content: string, iv: Uint8Array, keyData: string + base64Content: string, + iv: Uint8Array, + keyData: string ) { const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData)); const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['decrypt']); @@ -29,4 +58,34 @@ export let decrypt_content = async function decrypt_content( const decodedContent = new TextDecoder().decode(decryptedContent); // console.log('Decrypted Content:', decodedContent); return decodedContent; +} + +export let split_iv_and_base64 = function split_iv_and_base64( + combined: string + ) { + let [iv_hex, encrypted_base64_string] = combined.split(':'); + let base64 = encrypted_base64_string + let iv = new Uint8Array(iv_hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); + if (log_lvl) { + console.log(`IV: ${iv}; Encrypted: ${base64}`); + } + + // const [ivBase64, base64] = combined.split(':'); + // const iv = Uint8Array.from(atob(ivBase64), c => c.charCodeAt(0)); + // if (log_lvl) { + // console.log(`IV: ${iv}; Encrypted: ${base64}`); + // } + return { iv, base64 }; +} + +export let decrypt_wrapper = async function decrypt_wrapper( + combined: string, + keyData: string + ) { + const { iv, base64 } = split_iv_and_base64(combined); + const decrypted = await decrypt_content(base64, iv, keyData); + if (log_lvl) { + console.log(`IV: ${iv}; Decrypted:`, decrypted); + } + return decrypted; } \ No newline at end of file diff --git a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte index cd2f0794..62478940 100644 --- a/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte +++ b/src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte @@ -487,7 +487,8 @@ $effect(() => { // } async function handle_decrypt_string(encrypted_string: string, passcode: string) { - // log_lvl = 1; + log_lvl = 1; + if (log_lvl) { console.log(`TEST: handle_decrypt_string: ${passcode}`, encrypted_string); } @@ -500,26 +501,33 @@ async function handle_decrypt_string(encrypted_string: string, passcode: string) return false; } - let combined_data = encrypted_string; - let [encryption_iv_hex, encrypted_base64_string] = combined_data.split(':'); - encryption_iv = new Uint8Array(encryption_iv_hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); + let decrypted_string_2 = await ae_util.decrypt_wrapper(encrypted_string, passcode); if (log_lvl) { - console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`); + console.log('TEST: Decrypted string:', decrypted_string_2); } - // Decrypt the string using the journal key - let decrypted_string = ''; - try { - decrypted_string = await ae_util.decrypt_content(encrypted_base64_string, encryption_iv, passcode); - } catch (error) { - console.error('Error decrypting string:', error); - alert('Failed to decrypt string. Please check the passcode.'); - return; - } - if (log_lvl) { - console.log('Decrypted string:', decrypted_string); - } - return decrypted_string; + return decrypted_string_2; + + // let combined_data = encrypted_string; + // let [encryption_iv_hex, encrypted_base64_string] = combined_data.split(':'); + // encryption_iv = new Uint8Array(encryption_iv_hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); + // if (log_lvl) { + // console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`); + // } + + // // Decrypt the string using the journal key + // let decrypted_string = ''; + // try { + // decrypted_string = await ae_util.decrypt_content(encrypted_base64_string, encryption_iv, passcode); + // } catch (error) { + // console.error('Error decrypting string:', error); + // alert('Failed to decrypt string. Please check the passcode.'); + // return; + // } + // if (log_lvl) { + // console.log('Decrypted string:', decrypted_string); + // } + // return decrypted_string; } async function handle_encrypt_string(text_string: string, passcode: string) { @@ -536,16 +544,24 @@ async function handle_encrypt_string(text_string: string, passcode: string) { return false; } + let combined_data_2 = await ae_util.encrypt_wrapper(text_string, passcode); + if (log_lvl) { + console.log('TEST: Encrypted string:', combined_data_2); + } + return combined_data_2; + // Encrypt the string using the journal key - let encrypted_base64 = await ae_util.encrypt_content(text_string, passcode); - let encrypted_base64_string = encrypted_base64.base64; - let encryption_iv = encrypted_base64.iv; - console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`); + // let encrypted_base64 = await ae_util.encrypt_content(text_string, passcode); + // let encrypted_base64_string = encrypted_base64.base64; + // let encryption_iv = encrypted_base64.iv; + // console.log(`IV: ${encryption_iv}; Encrypted: ${encrypted_base64_string}`); + + // const combined_data = ae_util.combine_iv_and_base64(encrypted_base64_string, encryption_iv); // Combine the IV and encrypted content - const combined_data = Array.from(encryption_iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + encrypted_base64_string; + // const combined_data = Array.from(encryption_iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + encrypted_base64_string; - return combined_data; + // return combined_data; } // return new_string and cut_string @@ -1290,8 +1306,9 @@ function handle_cut_string(old_string: string) { // decrypted_content = result; // console.log('TEST: Decrypted content:', decrypted_content); // }); + decrypted_content = await ae_util.decrypt_wrapper(tmp_entry_obj?.content_encrypted, journal_key); - decrypted_content = await handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key); + // decrypted_content = await handle_decrypt_string(tmp_entry_obj?.content_encrypted, journal_key); tmp_entry_obj.content = decrypted_content; console.log('TEST: Decrypted content:', decrypted_content); } else { @@ -1453,7 +1470,8 @@ function handle_cut_string(old_string: string) { // !tmp_entry_obj?.history && if (tmp_entry_obj?.history_encrypted) { - decrypted_history = await handle_decrypt_string(tmp_entry_obj.history_encrypted, journal_key); + decrypted_history = await ae_util.decrypt_wrapper(tmp_entry_obj?.history_encrypted, journal_key); + // decrypted_history = await handle_decrypt_string(tmp_entry_obj.history_encrypted, journal_key); console.log('Decrypted history:', decrypted_history); tmp_entry_obj.history = decrypted_history; } @@ -1489,7 +1507,9 @@ function handle_cut_string(old_string: string) { let history_cleaned: null|string = null; let history_md_html: null|string = null; - decrypted_history = await handle_decrypt_string(tmp_entry_obj.history_encrypted, journal_key); + decrypted_history = await ae_util.decrypt_wrapper(tmp_entry_obj?.history_encrypted, journal_key); + + // decrypted_history = await handle_decrypt_string(tmp_entry_obj.history_encrypted, journal_key); console.log('Decrypted history:', decrypted_history); tmp_entry_obj.history = decrypted_history;