Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 41x 41x 41x 41x 41x 41x 13x 13x 13x 416x 13x 41x 14x 14x 13x 13x 13x 13x 13x 13x 12x 1x 1x 13x 13x 13x 13x 1x 12x 12x 10x 2x | import { getSharedSecret } from '@noble/secp256k1'; import { hexToBytes, base64ToBytes, concatByteArrays } from 'micro-stacks/common'; import { aes256CbcDecrypt } from 'micro-stacks/crypto-aes'; import { sharedSecretToKeys } from '../common/shared-secret'; import { hmacSha256 } from 'micro-stacks/crypto-hmac-sha'; import type { DecryptECIESOptions } from '../common/types'; export function equalConstTime(b1: Uint8Array, b2: Uint8Array) { Iif (b1.length !== b2.length) { return false; } let res = 0; for (let i = 0; i < b1.length; i++) { res |= b1[i] ^ b2[i]; // jshint ignore:line } return res === 0; } /** * Decrypt content encrypted using ECIES * * @param options {DecryptECIESOptions} * iv (initialization vector), cipherText (cipher text), * mac (message authentication code), ephemeralPublicKey * wasString (boolean indicating with or not to return a byte array or string on decrypt) * @return plaintext * @throws {Error} if unable to decrypt * @private * @ignore */ export async function decryptECIES(options: DecryptECIESOptions): Promise<Uint8Array | string> { const { privateKey, cipherObject } = options; if (!cipherObject.ephemeralPK) throw Error('No ephemeralPK found in cipher object'); const ephemeralPK = cipherObject.ephemeralPK; let sharedSecret = getSharedSecret(privateKey, ephemeralPK, true); // Trim the compressed mode prefix byte sharedSecret = sharedSecret.slice(1); const sharedKeys = sharedSecretToKeys(sharedSecret); const ivBuffer = hexToBytes(cipherObject.iv); let cipherTextBuffer: Uint8Array; if (!cipherObject.cipherTextEncoding || cipherObject.cipherTextEncoding === 'hex') { cipherTextBuffer = hexToBytes(cipherObject.cipherText); } else if (cipherObject.cipherTextEncoding === 'base64') { cipherTextBuffer = base64ToBytes(cipherObject.cipherText); } else E{ throw new Error(`Unexpected cipherTextEncoding "${cipherObject.cipherText}"`); } const macData = concatByteArrays([ivBuffer, hexToBytes(ephemeralPK), cipherTextBuffer]); const actualMac = hmacSha256(sharedKeys.hmacKey, macData); const expectedMac = hexToBytes(cipherObject.mac); if (!equalConstTime(expectedMac, actualMac)) { throw new Error('Decryption failed: failure in MAC check'); } const plainText = await aes256CbcDecrypt(ivBuffer, sharedKeys.encryptionKey, cipherTextBuffer); if (cipherObject.wasString) { return new TextDecoder().decode(plainText); } else { return plainText; } } |