From 6dff127cab16a5642a73417f36a2c27c51c7b2cb Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Thu, 20 Nov 2025 15:06:09 +0800 Subject: [PATCH] skip outgoing messages for decryption --- examples/pingpong.nim | 3 +++ src/chat_sdk/conversations/private_v1.nim | 18 ++++++++++++++++++ src/chat_sdk/errors.nim | 1 + src/naxolotl/naxolotl.nim | 23 ++++++++++++++++++----- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/examples/pingpong.nim b/examples/pingpong.nim index 75c8cf9..7dd497a 100644 --- a/examples/pingpong.nim +++ b/examples/pingpong.nim @@ -31,7 +31,10 @@ proc main() {.async.} = let sIdent = Identity(name: "saro", privateKey: sKey) # Create Clients + info "create saro client" var saro = newClient(cfg_saro, sIdent) + + info "create raya client" var raya = newClient(cfg_raya, Identity(name: "raya", privateKey: rKey)) var ri = 0 diff --git a/src/chat_sdk/conversations/private_v1.nim b/src/chat_sdk/conversations/private_v1.nim index 543704e..2abdf52 100644 --- a/src/chat_sdk/conversations/private_v1.nim +++ b/src/chat_sdk/conversations/private_v1.nim @@ -72,8 +72,16 @@ proc calcMsgId(self: PrivateV1, msgBytes: seq[byte]): string = proc encrypt*(convo: PrivateV1, plaintext: var seq[byte]): EncryptedPayload = + info "encrypt metadata" + info "Doubleratchet DH Self: ", dhSelf = convo.doubleratchet.dhSelf + info "dh self public:" , dhSelfPub = convo.doubleratchet.dhSelf.public + info "dhRemote: ", dhRemote = convo.doubleratchet.dhRemote + let (header, ciphertext) = convo.doubleratchet.encrypt(plaintext) #TODO: Associated Data + info "encrypt done" + info "header dh public: ", dhPub = header.dhPublic + result = EncryptedPayload(doubleratchet: proto_types.DoubleRatchet( dh: toSeq(header.dhPublic), msgNum: header.msgNumber, @@ -93,6 +101,16 @@ proc decrypt*(convo: PrivateV1, enc: EncryptedPayload): Result[seq[byte], ChatEr prevChainLen: dr.prevChainLen ) copyMem(addr header.dhPublic[0], unsafeAddr dr.dh[0], dr.dh.len) # TODO: Avoid this copy + + info "decrypt metadata" + info "header dh public: ", dhPub = header.dhPublic + info "Doubleratchet DH Remote: ", dhRemote = convo.doubleratchet.dhRemote + info "dh self:", dhSelf = convo.doubleratchet.dhSelf + info "dh self public:" , dhSelfPub = convo.doubleratchet.dhSelf.public + + 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 553282c..d3db434 100644 --- a/src/naxolotl/naxolotl.nim +++ b/src/naxolotl/naxolotl.nim @@ -16,8 +16,8 @@ const maxSkip = 10 type Doubleratchet* = object - dhSelf: PrivateKey - dhRemote: PublicKey + dhSelf*: PrivateKey + dhRemote*: PublicKey rootKey: RootKey chainKeySend: ChainKey @@ -73,8 +73,9 @@ func kdfChain(self: Doubleratchet, chainKey: ChainKey): (MessageKey, ChainKey) = return(msgKey, chainKey) -func dhRatchetSend(self: var Doubleratchet) = +proc dhRatchetSend(self: var Doubleratchet) = # Perform DH Ratchet step when receiving a new peer key. + info "dhRatchetSend DH Self: ", dhSelf = self.dhSelf let dhOutput : DhDerivedKey = dhExchange(self.dhSelf, self.dhRemote).get() let (newRootKey, newChainKeySend) = kdfRoot(self, self.rootKey, dhOutput) self.rootKey = newRootKey @@ -82,6 +83,8 @@ func dhRatchetSend(self: var Doubleratchet) = self.msgCountSend = 0 proc dhRatchetRecv(self: var Doubleratchet, remotePublickey: PublicKey ) = + info "dh ratchet happens" + info "dhRatchetRecv DH Remote: ", dhRemote = remotePublickey self.prevChainLen = self.msgCountSend self.msgCountSend = 0 self.msgCountRecv = 0 @@ -96,7 +99,7 @@ proc dhRatchetRecv(self: var Doubleratchet, remotePublickey: PublicKey ) = self.dhSelf = generateKeypair().get()[0] let dhOutputPost = self.dhSelf.dhExchange(self.dhRemote).get() - (self.rootKey, self.chainKeyRecv) = kdfRoot(self, self.rootKey, dhOutputPost) + (self.rootKey, self.chainKeySend) = kdfRoot(self, self.rootKey, dhOutputPost) proc skipMessageKeys(self: var Doubleratchet, until: MsgCount): Result[(), string] = @@ -138,9 +141,15 @@ proc encrypt(self: var Doubleratchet, plaintext: var seq[byte], associatedData: proc decrypt*(self: var Doubleratchet, header: DrHeader, ciphertext: CipherText, associatedData: openArray[byte] ) : Result[seq[byte], NaxolotlError] = + info "double ratchet decrypt", header = $header + info "dhRemote: ", dhRemote = self.dhRemote + info "dhSelf: ", dhSelf = self.dhSelf + info "dhSelf public: ", dhSelf = self.dhSelf.public let peerPublic = header.dhPublic + info "peerPublic: ", peerPublic = peerPublic + var msgKey : MessageKey # Check Skipped Keys @@ -176,8 +185,12 @@ proc encrypt*(self: var Doubleratchet, plaintext: var seq[byte]) : (DrHeader, Ci encrypt(self, plaintext,@[]) -func initDoubleratchet*(sharedSecret: array[32, byte], dhSelf: PrivateKey, dhRemote: PublicKey, isSending: bool = true): Doubleratchet = +proc initDoubleratchet*(sharedSecret: array[32, byte], dhSelf: PrivateKey, dhRemote: PublicKey, isSending: bool = true): Doubleratchet = + info "Initializing Double Ratchet" + info "DH Self: ", dhSelf = dhSelf + info "DH Self public: ", dhSelf = dhSelf.public + info "DH Remote: ", dhRemote = dhRemote result = Doubleratchet( dhSelf: dhSelf, dhRemote: dhRemote,