[M5] auth+probe: env-gated crypto-key/AES-key trace for F28 follow-up

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<string>? 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) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 17:37:22 -04:00
parent f14580e0db
commit fd38189f43
2 changed files with 16 additions and 2 deletions
@@ -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)
}
+8 -2
View File
@@ -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