@@ -178,16 +178,14 @@ module Crypto =
178 let info = Encoding.UTF8.GetBytes(Constants.hkdfInfo)
178 let info = Encoding.UTF8.GetBytes(Constants.hkdfInfo)
179 HKDF.DeriveKey(HashAlgorithmName.SHA256, rawSecret, 32, salt, info)
179 HKDF.DeriveKey(HashAlgorithmName.SHA256, rawSecret, 32, salt, info)
181− // Blob layout v2: [ephPub(32) | nonce(24) | ciphertext]
181+ // Blob layout: [ephPub(32) | nonce(24) | ciphertext]
182 // encrypted payload: [senderPub(32) | signature(64) | compressed]
182 // encrypted payload: [senderPub(32) | signature(64) | compressed]
183 // signature signs (recipientPub ++ compressed) — prevents forwarding
183 // signature signs (recipientPub ++ compressed) — prevents forwarding
184− // Legacy layout: [ephPub(32) | nonce(24) | ciphertext | senderPub(32) | signature(64)]
185 let private ephPubLen = 32
184 let private ephPubLen = 32
186 let private nonceLen = 24
185 let private nonceLen = 24
187 let private pubLen = 32
186 let private pubLen = 32
188 let private sigLen = 64
187 let private sigLen = 64
189 let private headerLen = ephPubLen + nonceLen
188 let private headerLen = ephPubLen + nonceLen
190− let private legacyTrailerLen = pubLen + sigLen
191 let private minBlobLen = headerLen + pubLen + sigLen + 16 // inner fields + AEAD tag
189 let private minBlobLen = headerLen + pubLen + sigLen + 16 // inner fields + AEAD tag
193 let private deriveSymKey recipientPrivKey ephPub =
191 let private deriveSymKey recipientPrivKey ephPub =
@@ -226,50 +224,22 @@ module Crypto =
227 let ephPub = blob.[.. ephPubLen - 1]
225 let ephPub = blob.[.. ephPubLen - 1]
228 let nonce = blob.[ephPubLen .. headerLen - 1]
226 let nonce = blob.[ephPubLen .. headerLen - 1]
227+ let ciphertext = blob.[headerLen ..]
228+ let key = deriveSymKey recipientPrivKey ephPub
229+ let decrypted = aeadDecrypt ciphertext nonce key
230− // Try v2 format: entire payload after header is ciphertext
233− let ciphertext = blob.[headerLen ..]
234− let key = deriveSymKey recipientPrivKey ephPub
235− let decrypted = aeadDecrypt ciphertext nonce key
237− if decrypted.Length < pubLen + sigLen then
231+ if decrypted.Length < pubLen + sigLen then
240− let senderPub = decrypted.[.. pubLen - 1]
234+ let senderPub = decrypted.[.. pubLen - 1]
241− let signature = decrypted.[pubLen .. pubLen + sigLen - 1]
235+ let signature = decrypted.[pubLen .. pubLen + sigLen - 1]
242− let compressed = decrypted.[pubLen + sigLen ..]
236+ let compressed = decrypted.[pubLen + sigLen ..]
244− let recipientPub = recipientPrivKey.[32..63]
238+ let recipientPub = recipientPrivKey.[32..63]
245− let signedData = Array.append recipientPub compressed
239+ let signedData = Array.append recipientPub compressed
247− if verifyDetached signature signedData senderPub then
241+ if verifyDetached signature signedData senderPub then
248− let plaintext = LZ4Pickler.Unpickle(compressed)
242+ let plaintext = LZ4Pickler.Unpickle(compressed)
249− Some(Encoding.UTF8.GetString(plaintext), toHex senderPub)
243+ Some(Encoding.UTF8.GetString(plaintext), toHex senderPub)
255− | Some _ -> v2Result
257− // Fall back to legacy format: trailer has senderPub + signature in plaintext
259− if blob.Length < headerLen + 16 + legacyTrailerLen then
262− let ciphertext = blob.[headerLen .. blob.Length - legacyTrailerLen - 1]
263− let senderPub = blob.[blob.Length - legacyTrailerLen .. blob.Length - sigLen - 1]
264− let signature = blob.[blob.Length - sigLen ..]
266− if not (verifyDetached signature ciphertext senderPub) then
269− let key = deriveSymKey recipientPrivKey ephPub
270− let decrypted = aeadDecrypt ciphertext nonce key
271− let plaintext = LZ4Pickler.Unpickle(decrypted)
272− Some(Encoding.UTF8.GetString(plaintext), toHex senderPub)
274− log $"decrypt error: {ex.Message}"