MCPcopy Create free account
hub / github.com/cameri/nostream / nip44Decrypt

Function nip44Decrypt

src/utils/nip44.ts:116–150  ·  view source on GitHub ↗
(payload: string, conversationKey: Buffer)

Source from the content-addressed store, hash-verified

114 * Validates version byte, payload sizes, and MAC before decrypting.
115 */
116export function nip44Decrypt(payload: string, conversationKey: Buffer): string {
117 if (!payload || payload[0] === '#') {
118 throw new Error('unknown version')
119 }
120 if (payload.length < 132 || payload.length > 87472) {
121 throw new Error('invalid payload size')
122 }
123
124 const data = Buffer.from(payload, 'base64')
125 if (data.length < 99 || data.length > 65603) {
126 throw new Error('invalid data size')
127 }
128
129 const version = data[0]
130 if (version !== 2) {
131 throw new Error(`unknown version ${version}`)
132 }
133
134 const nonce = data.subarray(1, 33)
135 const ciphertext = data.subarray(33, data.length - 32)
136 const mac = data.subarray(data.length - 32)
137
138 const { chachaKey, chachaNonce, hmacKey } = getMessageKeys(conversationKey, nonce)
139
140 const expectedMac = createHmac('sha256', hmacKey).update(nonce).update(ciphertext).digest()
141 if (!timingSafeEqual(expectedMac, mac)) {
142 throw new Error('invalid MAC')
143 }
144
145 const iv = Buffer.concat([Buffer.alloc(4), chachaNonce])
146 const decipher = createDecipheriv('chacha20', chachaKey, iv)
147 const padded = Buffer.concat([decipher.update(ciphertext), decipher.final()])
148
149 return unpad(padded)
150}
151
152/**
153 * Validate the structural format of a NIP-44 v2 payload without decrypting it.

Callers 1

nip44.spec.tsFile · 0.90

Calls 2

getMessageKeysFunction · 0.85
unpadFunction · 0.85

Tested by

no test coverage detected