refactor(types): Strengthen Type Safety in Signal Handling & Core Utilities (#1764)

* refactor(types): Strengthen Type Safety in Signal Handling & Core Utilities

* chore: revert typescript and move types to libsignal

* chore: update libsignal dependency resolution and checksum

* fix: a minor regression

* chore: update libsignal resolution and checksum
This commit is contained in:
João Lucas de Oliveira Lopes
2025-09-13 09:24:57 -03:00
committed by GitHub
parent e305d4848e
commit 421ca2eb92
9 changed files with 33 additions and 37 deletions
+18 -14
View File
@@ -1,6 +1,5 @@
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto'
/* @ts-ignore */
import * as libsignal from 'libsignal'
import * as curve from 'libsignal/src/curve'
import { KEY_BUNDLE_TYPE } from '../Defaults'
import type { KeyPair } from '../Types'
@@ -13,21 +12,21 @@ export const generateSignalPubKey = (pubKey: Uint8Array | Buffer) =>
export const Curve = {
generateKeyPair: (): KeyPair => {
const { pubKey, privKey } = libsignal.curve.generateKeyPair()
const { pubKey, privKey } = curve.generateKeyPair()
return {
private: Buffer.from(privKey),
// remove version byte
public: Buffer.from((pubKey as Uint8Array).slice(1))
public: Buffer.from(pubKey.slice(1))
}
},
sharedKey: (privateKey: Uint8Array, publicKey: Uint8Array) => {
const shared = libsignal.curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey)
const shared = curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey)
return Buffer.from(shared)
},
sign: (privateKey: Uint8Array, buf: Uint8Array) => libsignal.curve.calculateSignature(privateKey, buf),
sign: (privateKey: Uint8Array, buf: Uint8Array) => curve.calculateSignature(privateKey, buf),
verify: (pubKey: Uint8Array, message: Uint8Array, signature: Uint8Array) => {
try {
libsignal.curve.verifySignature(generateSignalPubKey(pubKey), message, signature)
curve.verifySignature(generateSignalPubKey(pubKey), message, signature)
return true
} catch (error) {
return false
@@ -129,15 +128,18 @@ export async function hkdf(
expandedLength: number,
info: { salt?: Buffer; info?: string }
): Promise<Buffer> {
// Ensure we have a Uint8Array for the key material
const inputKeyMaterial = buffer instanceof Uint8Array ? buffer : new Uint8Array(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
const importedKey = await subtle.importKey('raw', inputKeyMaterial, { name: 'HKDF' }, false, ['deriveBits'])
// 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(
@@ -158,17 +160,19 @@ export async function derivePairingCodeKey(pairingCode: string, salt: Buffer): P
// Convert inputs to formats Web Crypto API can work with
const encoder = new TextEncoder()
const pairingCodeBuffer = encoder.encode(pairingCode)
const saltBuffer = salt instanceof Uint8Array ? salt : new Uint8Array(salt)
const saltBuffer = new Uint8Array(salt instanceof Uint8Array ? salt : new Uint8Array(salt))
// Import the pairing code as key material
const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer, { name: 'PBKDF2' }, false, ['deriveBits'])
const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer as BufferSource, { name: 'PBKDF2' }, false, [
'deriveBits'
])
// Derive bits using PBKDF2 with the same parameters
// 2 << 16 = 131,072 iterations
const derivedBits = await subtle.deriveBits(
{
name: 'PBKDF2',
salt: saltBuffer,
salt: saltBuffer as BufferSource,
iterations: 2 << 16,
hash: 'SHA-256'
},