diff --git a/src/nostr/crypto.ts b/src/nostr/crypto.ts index a64802f7..ca70da6c 100644 --- a/src/nostr/crypto.ts +++ b/src/nostr/crypto.ts @@ -1,42 +1,36 @@ -import { l } from '@log' import { secp256k1 } from '@noble/curves/secp256k1' import { randomBytes } from '@noble/hashes/utils' -import { isErr } from '@util' +import { l } from '@src/logger' +import { isErr } from '@src/util' import { Buffer } from 'buffer/' -import cjs from 'crypto-js' +import { AES, enc, lib, mode } from 'crypto-js' -const { AES, enc, lib, mode } = cjs - -// eslint-disable-next-line @typescript-eslint/require-await, require-await -export async function encrypt(privkey: string, pubkey: string, text: string) { +function getEncKey(privkey: string, pubkey: string) { const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) - const normalizedKey = getNormalizedX(key) - const iv = Uint8Array.from(randomBytes(16)) - const cryptoKey = new Uint8Array(Buffer.from(normalizedKey)) - const ciphertext = AES.encrypt(text, - byteArrayToWordArray(cryptoKey), - { iv: byteArrayToWordArray(iv), mode: mode.CBC, } - ) - const ctb64 = Buffer.from(wordArrayToByteArray(ciphertext.ciphertext)).toString('base64') + return key.slice(1, 33) +} +export function encrypt(privkey: string, pubkey: string, text: string) { + const iv = randomBytes(16) + const cryptoKey = getEncKey(privkey, pubkey) + const ciphertext = AES.encrypt( + text, + bytesToWordArr(cryptoKey), + { iv: bytesToWordArr(iv), mode: mode.CBC } + ).ciphertext + const ctb64 = enc.Base64.stringify(ciphertext) const ivb64 = Buffer.from(iv).toString('base64') return `${ctb64}?iv=${ivb64}` } - -// eslint-disable-next-line @typescript-eslint/require-await, require-await -export async function decrypt(privkey: string, pubkey: string, data: string) { +export function decrypt(privkey: string, pubkey: string, data: string) { const [ctb64, ivb64] = data.split('?iv=') - const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) - const normalizedKey = getNormalizedX(key) const iv = Buffer.from(ivb64, 'base64') - const cryptoKey = new Uint8Array(Buffer.from(normalizedKey)) + const cryptoKey = getEncKey(privkey, pubkey) const ciphertext = Buffer.from(ctb64, 'base64') try { const decrypted = AES.decrypt( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - /// @ts-expect-error - { ciphertext: byteArrayToWordArray(Uint8Array.from(ciphertext)) }, - byteArrayToWordArray(cryptoKey), - { iv: byteArrayToWordArray(Uint8Array.from(iv)), mode: mode.CBC } + lib.CipherParams.create({ ciphertext: bytesToWordArr(ciphertext) }), + bytesToWordArr(cryptoKey), + { iv: bytesToWordArr(iv), mode: mode.CBC } ) return decrypted.toString(enc.Utf8) } catch (e) { @@ -44,12 +38,7 @@ export async function decrypt(privkey: string, pubkey: string, data: string) { return '' } } - -function getNormalizedX(key: Uint8Array): Uint8Array { - return key.slice(1, 33) -} - -function byteArrayToWordArray(ba: Uint8Array) { +function bytesToWordArr(ba: Uint8Array) { const wa: number[] = [] for (let i = 0; i < ba.length; i++) { wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i) @@ -57,17 +46,3 @@ function byteArrayToWordArray(ba: Uint8Array) { return lib.WordArray.create(wa, ba.length) } -function wordArrayToByteArray(wordArray: cjs.lib.WordArray) { - const len = wordArray.words.length - const u8_array = new Uint8Array(len << 2) - let offset = 0 - let word - for (let i = 0; i < len; i++) { - word = wordArray.words[i] - u8_array[offset++] = word >> 24 - u8_array[offset++] = (word >> 16) & 0xff - u8_array[offset++] = (word >> 8) & 0xff - u8_array[offset++] = word & 0xff - } - return u8_array -} \ No newline at end of file diff --git a/src/screens/Payment/Processing.tsx b/src/screens/Payment/Processing.tsx index b77797be..ab40fe29 100644 --- a/src/screens/Payment/Processing.tsx +++ b/src/screens/Payment/Processing.tsx @@ -203,7 +203,7 @@ export default function ProcessingScreen({ navigation, route }: TProcessingPageP return } const msg = `${userNostrNpub || nostr.senderName} (sender not verified) just sent you ${amount} Sat in Ecash using ${enutsPubkey}!\n\n ${token}` - const cipherTxt = await encrypt(sk, nostr.receiverNpub, msg) + const cipherTxt = encrypt(sk, nostr.receiverNpub, msg) const event = { kind: EventKind.DirectMessage, tags: [['p', nostr.receiverNpub]], diff --git a/src/screens/Payment/Receive/nostrDM/index.tsx b/src/screens/Payment/Receive/nostrDM/index.tsx index defbe88c..7e1a10fb 100644 --- a/src/screens/Payment/Receive/nostrDM/index.tsx +++ b/src/screens/Payment/Receive/nostrDM/index.tsx @@ -41,14 +41,14 @@ export default function NostrDMScreen({ navigation, route }: TNostrReceivePagePr const setDmsCB = useCallback((newDms: INostrDm[]) => setDms(newDms), []) // decrypt dm, check for uniq cashu token and set dms state - const handleDm = async (sk: string, e: NostrEvent) => { + const handleDm = (sk: string, e: NostrEvent) => { if (!sk.length) { l('can not handle dms, empy key!') return } const tokenMinLength = 25 // decrypt content - const decrypted = await decrypt(sk, e.pubkey, e.content) + const decrypted = decrypt(sk, e.pubkey, e.content) // remove newlines (can be attached to the cashu token) and create an array of words const words = decrypted.replace(/\n/g, ' ').split(' ') // check each word of content @@ -86,14 +86,14 @@ export default function NostrDMScreen({ navigation, route }: TNostrReceivePagePr kinds: [EventKind.DirectMessage, EventKind.SetMetadata], skipVerification: Config.skipVerification }) - sub?.on('event', async (e: NostrEvent) => { + sub?.on('event', (e: NostrEvent) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (+e.kind === EventKind.SetMetadata) { setDmProfiles(prev => prev.some(x => x[0] === e.pubkey) ? prev : [...prev, [e.pubkey, parseProfileContent(e)]]) } // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (+e.kind === EventKind.DirectMessage) { - await handleDm(sk || '', e) + handleDm(sk || '', e) } }) sub?.on('eose', () => {