From 3fd522fa109b8ddbaa4e00ac09d2f4747489f24e Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 23 Jun 2026 10:31:37 -0400 Subject: [PATCH] =?UTF-8?q?docs(grpc-events):=20Path=20B=20=E2=80=94=20Exc?= =?UTF-8?q?hangeKey=20ECDH=20clears=202=20of=203=20layers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records that the pure-managed P-256 ExchangeKey works (cleared the v8 client-key check; error advanced to 132/171 AuthenticationFailed). The remaining layer is the 26-byte credential-token KDF, which requires recovering the native key derivation. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC --- .../grpc-event-query-capture.md | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/reverse-engineering/grpc-event-query-capture.md b/docs/reverse-engineering/grpc-event-query-capture.md index cb56466..a95e4a8 100644 --- a/docs/reverse-engineering/grpc-event-query-capture.md +++ b/docs/reverse-engineering/grpc-event-query-capture.md @@ -229,3 +229,28 @@ size) — using .NET `ECDiffieHellman`, establish the client key, then reissue t Open question for Path B: whether merely *completing* the ECDH key agreement registers the client key (so the zeroed openParameters token still rides through), or whether the token must also be derived from the shared secret (full KDF/cipher RE). + +### Path B started 2026-06-23 — ExchangeKey ECDH works; cleared 2 of 3 layers + +Implemented `HistoryService.ExchangeKey` as a **pure-managed P-256 ECDH** key exchange +(`HistorianNativeHandshake.BuildExchangeKeyClientHello` / `DeriveExchangeKeySecret`, .NET +`ECDiffieHellman` over `nistP256`; wire format `"ECK1" + u32(32) + X(32) + Y(32)`) and wired it into +`HistorianGrpcHandshake.OpenSession(eventConnection: true)` ahead of the v8 `OpenConnection`, +on the same context-key handle. Live result against the server: the **`ExchangeKey` RPC succeeds** +(the server accepted our public key), and the v8 `OpenConnection` error **moved one layer deeper**: + +``` +Path A (no ExchangeKey): 132/34 "Failed to get client key" +Path B (ExchangeKey ECDH): 132/171 AuthenticationFailed "EstablishConnection — Authentication failed" +``` + +So the ECDH cleared the client-key check; the remaining blocker is **authentication**: the 26-byte +v8 credential token must be a *valid* value derived from the ECDH shared secret (not zeros). This is +the token KDF/cipher — the part that is not yet reverse-engineered and that would require analyzing +AVEVA's native ExchangeKey/credential crypto to recover the derivation (the .NET-shipped result stays +pure managed either way). The "Path B-lite" hypothesis (zeroed token rides through after key +agreement) is therefore disproven at the auth layer — 2 of 3 layers are cleared, the 3rd is the +credential-token derivation. ExchangeKey + the v8 serializer are committed and ready; the orchestrator +stays on v6 (set `eventConnection: true` to re-arm once the token KDF lands). The token-loop routing +guardrail (`HistorianGrpcHandshakeRoutingTests`) was scoped to the closure so the legitimate +ExchangeKey call is allowed while still pinning that the Negotiate token loop never routes there.