From 523dca43e18b902a4efb2e8bbc796ae32668cf26 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Fri, 28 Nov 2025 16:09:02 +0800 Subject: [PATCH 1/2] fix: outgoing messages should not be decrypted --- src/chat_sdk/conversations/private_v1.nim | 4 ++++ src/chat_sdk/errors.nim | 1 + src/naxolotl/naxolotl.nim | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/chat_sdk/conversations/private_v1.nim b/src/chat_sdk/conversations/private_v1.nim index 7554bc9..08c6deb 100644 --- a/src/chat_sdk/conversations/private_v1.nim +++ b/src/chat_sdk/conversations/private_v1.nim @@ -94,6 +94,10 @@ proc decrypt*(convo: PrivateV1, enc: EncryptedPayload): Result[seq[byte], ChatEr ) copyMem(addr header.dhPublic[0], unsafeAddr dr.dh[0], dr.dh.len) # TODO: Avoid this copy + if convo.doubleratchet.dhSelf.public == header.dhPublic: + info "outgoing message, no need to decrypt" + return err(ChatError(code: errDecryptOutgoing, context: "Attempted to decrypt outgoing message")) + convo.doubleratchet.decrypt(header, dr.ciphertext, @[]).mapErr(proc(e: NaxolotlError): ChatError = ChatError(code: errWrapped, context: repr(e) )) diff --git a/src/chat_sdk/errors.nim b/src/chat_sdk/errors.nim index e7b8008..a838439 100644 --- a/src/chat_sdk/errors.nim +++ b/src/chat_sdk/errors.nim @@ -8,6 +8,7 @@ type ErrorCode* = enum errTypeError errWrapped + errDecryptOutgoing proc `$`*(x: ChatError): string = diff --git a/src/naxolotl/naxolotl.nim b/src/naxolotl/naxolotl.nim index f2b0fb8..0458126 100644 --- a/src/naxolotl/naxolotl.nim +++ b/src/naxolotl/naxolotl.nim @@ -16,7 +16,7 @@ const maxSkip = 10 type Doubleratchet* = object - dhSelf: PrivateKey + dhSelf*: PrivateKey dhRemote: PublicKey rootKey: RootKey From 622fe0a78b6796019c15e0ee1ba2451128ab4432 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Mon, 1 Dec 2025 14:39:49 +0800 Subject: [PATCH 2/2] chore: not expose private dh key. --- src/chat_sdk/conversations/private_v1.nim | 8 ++++---- src/chat_sdk/errors.nim | 2 -- src/naxolotl/naxolotl.nim | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/chat_sdk/conversations/private_v1.nim b/src/chat_sdk/conversations/private_v1.nim index 08c6deb..5b31f4a 100644 --- a/src/chat_sdk/conversations/private_v1.nim +++ b/src/chat_sdk/conversations/private_v1.nim @@ -94,10 +94,6 @@ proc decrypt*(convo: PrivateV1, enc: EncryptedPayload): Result[seq[byte], ChatEr ) copyMem(addr header.dhPublic[0], unsafeAddr dr.dh[0], dr.dh.len) # TODO: Avoid this copy - if convo.doubleratchet.dhSelf.public == header.dhPublic: - info "outgoing message, no need to decrypt" - return err(ChatError(code: errDecryptOutgoing, context: "Attempted to decrypt outgoing message")) - convo.doubleratchet.decrypt(header, dr.ciphertext, @[]).mapErr(proc(e: NaxolotlError): ChatError = ChatError(code: errWrapped, context: repr(e) )) @@ -194,6 +190,10 @@ proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T, let enc = decode(bytes, EncryptedPayload).valueOr: raise newException(ValueError, fmt"Failed to decode EncryptedPayload: {repr(error)}") + if convo.doubleratchet.dhSelfPublic() == enc.doubleratchet.dh: + info "outgoing message, no need to handle", convo = convo.id() + return + let plaintext = convo.decrypt(enc).valueOr: error "decryption failed", error = error return diff --git a/src/chat_sdk/errors.nim b/src/chat_sdk/errors.nim index a838439..f4751b0 100644 --- a/src/chat_sdk/errors.nim +++ b/src/chat_sdk/errors.nim @@ -8,8 +8,6 @@ type ErrorCode* = enum errTypeError errWrapped - errDecryptOutgoing - proc `$`*(x: ChatError): string = fmt"ChatError(code={$x.code}, context: {x.context})" diff --git a/src/naxolotl/naxolotl.nim b/src/naxolotl/naxolotl.nim index 0458126..ad2efa6 100644 --- a/src/naxolotl/naxolotl.nim +++ b/src/naxolotl/naxolotl.nim @@ -16,7 +16,7 @@ const maxSkip = 10 type Doubleratchet* = object - dhSelf*: PrivateKey + dhSelf: PrivateKey dhRemote: PublicKey rootKey: RootKey @@ -187,3 +187,6 @@ func initDoubleratchet*(sharedSecret: array[32, byte], dhSelf: PrivateKey, dhRem if isSending: result.dhRatchetSend() + +func dhSelfPublic*(self: Doubleratchet): PublicKey = + self.dhSelf.public \ No newline at end of file