/* * Copyright (c) 2022. * Author Peter Placzek (tada5hi) * For the full copyright and license information, * view the LICENSE file that was distributed with this source code. */ import {box, BoxKeyPair, randomBytes, secretbox} from "tweetnacl"; import {decodeBase64, decodeUTF8, encodeBase64, encodeUTF8} from 'tweetnacl-util'; /* Public Key Encryption */ export function createPublicEncryptionNonce() : Uint8Array { return randomBytes(box.nonceLength); } export function createPublicEncryptionKeyPair() : Record<'privateKey' | 'publicKey', string> { const keyPair : BoxKeyPair = box.keyPair(); return { privateKey: encodeBase64(keyPair.secretKey), publicKey: encodeBase64(keyPair.publicKey) } } export function createPublicEncryptionKeyPairFromPrivateKey(privateKey: string) : Record<'privateKey' | 'publicKey', string> { const privateKeyUint8 : Uint8Array = decodeUTF8(privateKey); const keyPair : BoxKeyPair = box.keyPair.fromSecretKey(privateKeyUint8); return { privateKey: encodeBase64(keyPair.secretKey), publicKey: encodeBase64(keyPair.publicKey) } } export function encryptPublicEncryptionMessage(message: string, publicKey: string, privateKey: string) : string { const nonce = createPublicEncryptionNonce(); const messageUint8 : Uint8Array = decodeUTF8(message); const publicKeyUint8 : Uint8Array = decodeBase64(publicKey); const privateKeyKeyUint8 : Uint8Array = decodeBase64(privateKey); const encrypted = box(messageUint8, nonce, publicKeyUint8, privateKeyKeyUint8); const combined : Uint8Array = new Uint8Array(nonce.length + encrypted.length); combined.set(nonce); combined.set(encrypted, nonce.length); return encodeBase64(combined); } export function decryptPublicEncryptionMessage(messageWithNonce: string, publicKey: string, privateKey: string) : string { const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce); const nonce = messageWithNonceAsUint8Array.slice(0, box.nonceLength); const message = messageWithNonceAsUint8Array.slice( box.nonceLength, messageWithNonce.length ); const publicKeyUint8 : Uint8Array = decodeBase64(publicKey); const privateKeyKeyUint8 : Uint8Array = decodeBase64(privateKey); const decrypted : Uint8Array | null = box.open(message, nonce, publicKeyUint8, privateKeyKeyUint8); if(!decrypted) { throw new Error('Could not decrypt message...'); } return encodeUTF8(decrypted); } /* Secret Key Encryption */ export function createSymmetricEncryptionNonce() : Uint8Array { return randomBytes(secretbox.nonceLength); } export function createSymmetricEncryptionKey() : string { return encodeBase64(randomBytes(secretbox.keyLength)) } export function encryptMessageSymmetric(message: string, secretKey: string) { const keyUint8Array = decodeBase64(secretKey); const nonce = createSymmetricEncryptionNonce(); const messageUint8 = decodeUTF8(message); const out = secretbox(messageUint8, nonce, keyUint8Array); const combined = new Uint8Array(nonce.length + out.length); combined.set(nonce); combined.set(out, nonce.length); return encodeBase64(combined); } export function decryptMessageSymmetric(messageWithNonce: string, secretKey: string) { const keyUint8Array = decodeBase64(secretKey); const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce); const nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength); const message = messageWithNonceAsUint8Array.slice( secretbox.nonceLength, messageWithNonce.length ); const decrypted = secretbox.open(message, nonce, keyUint8Array); if (!decrypted) { throw new Error("Could not decrypt message"); } return encodeUTF8(decrypted); }