From fd38189f43643e823f3f73907ef8a2ad48825dd8 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 5 May 2026 17:37:22 -0400 Subject: [PATCH] [M5] auth+probe: env-gated crypto-key/AES-key trace for F28 follow-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds diagnostic traces in both the Rust authenticator and the .NET reference (under MX_ASB_TRACE_DERIVE / sharedTrace) that dump: - crypto_key length + hex + base64 (shared || passphrase) - derived AES key hex (PBKDF2-SHA1, 16 bytes) Used to confirm during the F28 live-bring-up reconciliation that: 1. crypto_key passphrase suffix bytes [96..176] match between Rust and .NET — both read the same registry passphrase, both UTF-8-encode. 2. crypto_key shared_secret prefix bytes [0..96] DIFFER per run because each session has its own random DH private exponent. This is expected; what matters is the client+server agreement on the value for a single session, which the wire-tested DH math should produce given correct prime/generator/private-key handling. Both traces are gated: - Rust: `MX_ASB_TRACE_DERIVE=1` env var. - .NET: `Action? sharedTrace` field, populated when the authenticator is constructed with a non-null trace callback (the probe's `Console.WriteLine` shim wires this up by default). Workspace: 709 tests still pass. No public-API changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- rust/crates/mxaccess-asb-nettcp/src/auth.rs | 8 ++++++++ src/MxAsbClient/AsbSystemAuthenticator.cs | 10 ++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/rust/crates/mxaccess-asb-nettcp/src/auth.rs b/rust/crates/mxaccess-asb-nettcp/src/auth.rs index b193b30..879bca2 100644 --- a/rust/crates/mxaccess-asb-nettcp/src/auth.rs +++ b/rust/crates/mxaccess-asb-nettcp/src/auth.rs @@ -331,6 +331,14 @@ impl AsbAuthenticator { PBKDF2_ITERATIONS, out.as_mut_slice(), ); + if std::env::var("MX_ASB_TRACE_DERIVE").ok().is_some() { + eprintln!("asb.derive.crypto_key.len={}", crypto_key.len()); + let hex: String = crypto_key.iter().map(|b| format!("{b:02X}")).collect(); + eprintln!("asb.derive.crypto_key.hex={hex}"); + eprintln!("asb.derive.crypto_key.b64={password_b64}"); + let aes_hex: String = out.iter().map(|b| format!("{b:02X}")).collect(); + eprintln!("asb.derive.aes_key.hex={aes_hex}"); + } Ok(out) } diff --git a/src/MxAsbClient/AsbSystemAuthenticator.cs b/src/MxAsbClient/AsbSystemAuthenticator.cs index f306f1f..c335781 100644 --- a/src/MxAsbClient/AsbSystemAuthenticator.cs +++ b/src/MxAsbClient/AsbSystemAuthenticator.cs @@ -150,12 +150,18 @@ internal sealed class AsbSystemAuthenticator private byte[] DeriveAesKey() { - return Rfc2898DeriveBytes.Pbkdf2( - Convert.ToBase64String(CryptoKey), + byte[] cryptoKey = CryptoKey; + byte[] aesKey = Rfc2898DeriveBytes.Pbkdf2( + Convert.ToBase64String(cryptoKey), PasswordSalt, iterations: 1000, HashAlgorithmName.SHA1, outputLength: 16); + sharedTrace?.Invoke($"asb.derive.crypto_key.len={cryptoKey.Length}"); + sharedTrace?.Invoke($"asb.derive.crypto_key.hex={Convert.ToHexString(cryptoKey)}"); + sharedTrace?.Invoke($"asb.derive.crypto_key.b64={Convert.ToBase64String(cryptoKey)}"); + sharedTrace?.Invoke($"asb.derive.aes_key.hex={Convert.ToHexString(aesKey)}"); + return aesKey; } private byte[] CryptoKey