feat: replace async crypto with sync Rust WASM (port of Baileys b5c1741)
Surgically applies the changes from WhiskeySockets/Baileys commit b5c1741
("feat: replace async crypto with sync Rust WASM" by jlucaso1) while
preserving all custom modifications (interactive messages, carousels,
albums, sticker packs, native flow buttons, Prometheus metrics, etc).
Changes:
- Replace async hkdf/md5 (Web Crypto API) with sync re-exports from whatsapp-rust-bridge@0.5.2
- Replace LTHash class with LTHashAntiTampering from WASM
- Replace mutationKeys() with expandAppStateKeys() from WASM
- Remove ~25 unnecessary await keywords across crypto call chain
- Update Buffer→Uint8Array types for MediaDecryptionKeyInfo and internal crypto functions
- Make noise handshake, media retry encrypt/decrypt, and reporting token generation synchronous
Performance impact:
- Eliminates Promise overhead on every HKDF/LTHash operation
- Significant improvement during app state sync (hundreds of mutations per reconnection)
- Sync crypto reduces event loop pressure under high session load
Custom code preserved (zero conflicts):
- messages-send.ts: All interactive message, carousel, album, sticker pack logic intact
- Types/Message.ts: All custom types (NativeFlowButton, Carousel, Album, etc.) intact
- All Prometheus metrics, circuit breakers, session TTL logic intact
https://claude.ai/code/session_01Ffc5YrPuqv8N9SwEuSM8mr
This commit is contained in:
+5
-41
@@ -82,18 +82,18 @@ export function aesDecryptCTR(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8
|
||||
}
|
||||
|
||||
/** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
|
||||
export function aesDecrypt(buffer: Buffer, key: Buffer) {
|
||||
return aesDecryptWithIV(buffer.slice(16, buffer.length), key, buffer.slice(0, 16))
|
||||
export function aesDecrypt(buffer: Uint8Array, key: Uint8Array) {
|
||||
return aesDecryptWithIV(buffer.subarray(16, buffer.length), key, buffer.subarray(0, 16))
|
||||
}
|
||||
|
||||
/** decrypt AES 256 CBC */
|
||||
export function aesDecryptWithIV(buffer: Buffer, key: Buffer, IV: Buffer) {
|
||||
export function aesDecryptWithIV(buffer: Uint8Array, key: Uint8Array, IV: Uint8Array) {
|
||||
const aes = createDecipheriv('aes-256-cbc', key, IV)
|
||||
return Buffer.concat([aes.update(buffer), aes.final()])
|
||||
}
|
||||
|
||||
// encrypt AES 256 CBC; where a random IV is prefixed to the buffer
|
||||
export function aesEncrypt(buffer: Buffer | Uint8Array, key: Buffer) {
|
||||
export function aesEncrypt(buffer: Buffer | Uint8Array, key: Uint8Array) {
|
||||
const IV = randomBytes(16)
|
||||
const aes = createCipheriv('aes-256-cbc', key, IV)
|
||||
return Buffer.concat([IV, aes.update(buffer), aes.final()]) // prefix IV to the buffer
|
||||
@@ -118,43 +118,7 @@ export function sha256(buffer: Buffer) {
|
||||
return createHash('sha256').update(buffer).digest()
|
||||
}
|
||||
|
||||
export function md5(buffer: Buffer) {
|
||||
return createHash('md5').update(buffer).digest()
|
||||
}
|
||||
|
||||
// HKDF key expansion
|
||||
export async function hkdf(
|
||||
buffer: Uint8Array | Buffer,
|
||||
expandedLength: number,
|
||||
info: { salt?: Buffer; info?: string }
|
||||
): Promise<Buffer> {
|
||||
// Normalize to a Uint8Array whose underlying buffer is a regular ArrayBuffer (not ArrayBufferLike)
|
||||
// Cloning via new Uint8Array(...) guarantees the generic parameter is ArrayBuffer which satisfies WebCrypto types.
|
||||
const inputKeyMaterial = new Uint8Array(buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer))
|
||||
|
||||
// Set default values if not provided
|
||||
const salt = info.salt ? new Uint8Array(info.salt) : new Uint8Array(0)
|
||||
const infoBytes = info.info ? new TextEncoder().encode(info.info) : new Uint8Array(0)
|
||||
|
||||
// Import the input key material (cast to BufferSource to appease TS DOM typings)
|
||||
const importedKey = await subtle.importKey('raw', inputKeyMaterial as BufferSource, { name: 'HKDF' }, false, [
|
||||
'deriveBits'
|
||||
])
|
||||
|
||||
// Derive bits using HKDF
|
||||
const derivedBits = await subtle.deriveBits(
|
||||
{
|
||||
name: 'HKDF',
|
||||
hash: 'SHA-256',
|
||||
salt: salt,
|
||||
info: infoBytes
|
||||
},
|
||||
importedKey,
|
||||
expandedLength * 8 // Convert bytes to bits
|
||||
)
|
||||
|
||||
return Buffer.from(derivedBits)
|
||||
}
|
||||
export { hkdf, md5 } from 'whatsapp-rust-bridge'
|
||||
|
||||
export async function derivePairingCodeKey(pairingCode: string, salt: Buffer): Promise<Buffer> {
|
||||
// Convert inputs to formats Web Crypto API can work with
|
||||
|
||||
Reference in New Issue
Block a user