fix: handle invalid signatureKeyPublic types in sender-key-state AND fix handling chain key objects for skmsg group message decryption (#1760)

* fix: handle invalid signatureKeyPublic types in sender-key-state

- added extra check to ensure signatureKeyPublic is either a base64 string or a Buffer
- fallback to empty buffer when unexpected object type is received
- prevents ERR_INVALID_ARG_TYPE error in Buffer.from

* fix: lint

* adjusted based on  @jlucaso1 recommmendation

* fix: handle chain key objects for skmsg group message decryption

previously, some sender chain keys were stored or retrieved as plain objects
(e.g. { '0': 85, '1': 100, ... }) instead of Buffers. this caused
"ERR_INVALID_ARG_TYPE" during initial decryption of skmsg group messages.

this fixes any chain key object is converted to a proper Buffer
before being passed to SenderChainKey.

* fix: add more robust checks and fallbacks

* hacky fix(sender-key-state): normalize signing pubkey as Buffer with 0x05 prefix

a little hacky fix that ensures getSigningKeyPublic always returns a proper Buffer to satisfy libsignal.
adds a fallback to prepend 0x05 when only a 32-byte key is present, avoiding
"Invalid public key" errors and TS type issues around Uint8Array vs Buffer.
This commit is contained in:
αѕтяσχ11
2025-09-13 09:04:26 +01:00
committed by GitHub
parent 88ec0c4db2
commit f0dcc30e0f
3 changed files with 46 additions and 30 deletions
+4 -2
View File
@@ -10,12 +10,14 @@ export class SenderChainKey {
constructor(iteration: number, chainKey: any) {
this.iteration = iteration
if (chainKey instanceof Buffer) {
if (Buffer.isBuffer(chainKey)) {
this.chainKey = chainKey
} else if (chainKey instanceof Uint8Array) {
this.chainKey = Buffer.from(chainKey)
} else if (chainKey && typeof chainKey === 'object') {
this.chainKey = Buffer.from(Object.values(chainKey))
} else {
this.chainKey = Buffer.from(chainKey || [])
this.chainKey = Buffer.alloc(0)
}
}
+40 -26
View File
@@ -30,17 +30,25 @@ export class SenderKeyState {
constructor(
id?: number | null,
iteration?: number | null,
chainKey?: Uint8Array | null,
signatureKeyPair?: { public: Uint8Array; private: Uint8Array } | null,
signatureKeyPublic?: Uint8Array | null,
signatureKeyPrivate?: Uint8Array | null,
chainKey?: Uint8Array | null | string,
signatureKeyPair?: { public: Uint8Array | string; private: Uint8Array | string } | null,
signatureKeyPublic?: Uint8Array | string | null,
signatureKeyPrivate?: Uint8Array | string | null,
senderKeyStateStructure?: SenderKeyStateStructure | null
) {
const toBuffer = (val: any) => {
if (!val) return Buffer.alloc(0)
if (typeof val === 'string') return Buffer.from(val, 'base64')
if (val instanceof Uint8Array || Array.isArray(val)) return Buffer.from(val)
return Buffer.alloc(0)
}
if (senderKeyStateStructure) {
if (!Array.isArray(senderKeyStateStructure.senderMessageKeys)) {
this.senderKeyStateStructure = { ...senderKeyStateStructure, senderMessageKeys: [] }
} else {
this.senderKeyStateStructure = senderKeyStateStructure
this.senderKeyStateStructure = {
...senderKeyStateStructure,
senderMessageKeys: Array.isArray(senderKeyStateStructure.senderMessageKeys)
? senderKeyStateStructure.senderMessageKeys
: []
}
} else {
if (signatureKeyPair) {
@@ -52,19 +60,12 @@ export class SenderKeyState {
const senderChainKeyStructure: SenderChainKeyStructure = {
iteration: iteration || 0,
seed: chainKey || Buffer.alloc(0)
seed: chainKey ? toBuffer(chainKey) : Buffer.alloc(0)
}
const signingKeyStructure: SenderSigningKeyStructure = {
public:
typeof signatureKeyPublic === 'string'
? Buffer.from(signatureKeyPublic, 'base64')
: signatureKeyPublic || Buffer.alloc(0)
}
if (signatureKeyPrivate) {
signingKeyStructure.private =
typeof signatureKeyPrivate === 'string' ? Buffer.from(signatureKeyPrivate, 'base64') : signatureKeyPrivate
public: toBuffer(signatureKeyPublic),
private: signatureKeyPrivate ? toBuffer(signatureKeyPrivate) : undefined
}
this.senderKeyStateStructure = {
@@ -95,16 +96,29 @@ export class SenderKeyState {
}
public getSigningKeyPublic(): Buffer {
const publicKey = this.senderKeyStateStructure.senderSigningKey.public
if (publicKey instanceof Buffer) {
return publicKey
} else if (publicKey instanceof Uint8Array) {
return Buffer.from(publicKey)
} else if (typeof publicKey === 'string') {
return Buffer.from(publicKey, 'base64')
let key = this.senderKeyStateStructure.senderSigningKey.public
// normalize into Buffer
if (!(key instanceof Buffer)) {
if (key instanceof Uint8Array) {
key = Buffer.from(key)
} else if (typeof key === 'string') {
key = Buffer.from(key, 'base64')
} else {
key = Buffer.from(key || [])
}
}
return Buffer.from(publicKey || [])
const publicKey = key as Buffer
if (publicKey.length === 32) {
const fixed = Buffer.alloc(33)
fixed[0] = 0x05
publicKey.copy(fixed, 1)
return fixed
}
return publicKey
}
public getSigningKeyPrivate(): Buffer | undefined {