forked from trent_larson/crowd-funder-for-time-pwa
add encryption & decryption for the sensitive identity & mnemonic in SQL DB
This commit is contained in:
@@ -159,7 +159,7 @@ export const nextDerivationPath = (origDerivPath: string) => {
|
||||
};
|
||||
|
||||
// Base64 encoding/decoding utilities for browser
|
||||
function base64ToArrayBuffer(base64: string): Uint8Array {
|
||||
export function base64ToArrayBuffer(base64: string): Uint8Array {
|
||||
const binaryString = atob(base64);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
@@ -168,7 +168,7 @@ function base64ToArrayBuffer(base64: string): Uint8Array {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
const binary = String.fromCharCode(...new Uint8Array(buffer));
|
||||
return btoa(binary);
|
||||
}
|
||||
@@ -178,7 +178,7 @@ const IV_LENGTH = 12;
|
||||
const KEY_LENGTH = 256;
|
||||
const ITERATIONS = 100000;
|
||||
|
||||
// Encryption helper function
|
||||
// Message encryption helper function, used for onboarding meeting messages
|
||||
export async function encryptMessage(message: string, password: string) {
|
||||
const encoder = new TextEncoder();
|
||||
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
||||
@@ -226,7 +226,7 @@ export async function encryptMessage(message: string, password: string) {
|
||||
return btoa(JSON.stringify(result));
|
||||
}
|
||||
|
||||
// Decryption helper function
|
||||
// Message decryption helper function, used for onboarding meeting messages
|
||||
export async function decryptMessage(encryptedJson: string, password: string) {
|
||||
const decoder = new TextDecoder();
|
||||
const { salt, iv, encrypted } = JSON.parse(atob(encryptedJson));
|
||||
@@ -311,17 +311,17 @@ export async function testMessageEncryptionDecryption() {
|
||||
}
|
||||
}
|
||||
|
||||
// Simple encryption/decryption using Node's crypto
|
||||
// Simple encryption using Node's crypto, used for the initial encryption of the identity and mnemonic
|
||||
export async function simpleEncrypt(
|
||||
text: string,
|
||||
secret: string,
|
||||
): Promise<string> {
|
||||
secret: ArrayBuffer,
|
||||
): Promise<ArrayBuffer> {
|
||||
const iv = crypto.getRandomValues(new Uint8Array(16));
|
||||
|
||||
// Derive a 256-bit key from the secret using SHA-256
|
||||
const keyData = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(secret),
|
||||
secret,
|
||||
);
|
||||
const key = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
@@ -342,14 +342,15 @@ export async function simpleEncrypt(
|
||||
result.set(iv);
|
||||
result.set(new Uint8Array(encrypted), iv.length);
|
||||
|
||||
return btoa(String.fromCharCode(...result));
|
||||
return result.buffer;
|
||||
}
|
||||
|
||||
// Simple decryption using Node's crypto, used for the default decryption of identity and mnemonic
|
||||
export async function simpleDecrypt(
|
||||
encryptedText: string,
|
||||
secret: string,
|
||||
encryptedText: ArrayBuffer,
|
||||
secret: ArrayBuffer,
|
||||
): Promise<string> {
|
||||
const data = Uint8Array.from(atob(encryptedText), (c) => c.charCodeAt(0));
|
||||
const data = new Uint8Array(encryptedText);
|
||||
|
||||
// Extract IV and encrypted data
|
||||
const iv = data.slice(0, 16);
|
||||
@@ -358,7 +359,7 @@ export async function simpleDecrypt(
|
||||
// Derive the same 256-bit key from the secret using SHA-256
|
||||
const keyData = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(secret),
|
||||
secret,
|
||||
);
|
||||
const key = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
@@ -381,18 +382,20 @@ export async function simpleDecrypt(
|
||||
export async function testSimpleEncryptionDecryption() {
|
||||
try {
|
||||
const testMessage = "Hello, this is a test message! 🚀";
|
||||
const testSecret = "myTestSecret123";
|
||||
const testSecret = crypto.getRandomValues(new Uint8Array(32));
|
||||
|
||||
logger.log("Original message:", testMessage);
|
||||
|
||||
// Test encryption
|
||||
logger.log("Encrypting...");
|
||||
const encrypted = await simpleEncrypt(testMessage, testSecret);
|
||||
logger.log("Encrypted result:", encrypted);
|
||||
const encryptedBase64 = arrayBufferToBase64(encrypted);
|
||||
logger.log("Encrypted result:", encryptedBase64);
|
||||
|
||||
// Test decryption
|
||||
logger.log("Decrypting...");
|
||||
const decrypted = await simpleDecrypt(encrypted, testSecret);
|
||||
const encryptedArrayBuffer = base64ToArrayBuffer(encryptedBase64);
|
||||
const decrypted = await simpleDecrypt(encryptedArrayBuffer, testSecret);
|
||||
logger.log("Decrypted result:", decrypted);
|
||||
|
||||
// Verify
|
||||
@@ -403,7 +406,7 @@ export async function testSimpleEncryptionDecryption() {
|
||||
// Test with wrong secret
|
||||
logger.log("\nTesting with wrong secret...");
|
||||
try {
|
||||
await simpleDecrypt(encrypted, "wrongSecret");
|
||||
await simpleDecrypt(encryptedArrayBuffer, new Uint8Array(32));
|
||||
logger.log("Incorrectly decrypted with wrong secret ❌");
|
||||
} catch (error) {
|
||||
logger.log("Correctly failed to decrypt with wrong secret ✅");
|
||||
|
||||
Reference in New Issue
Block a user