mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-07-30 17:30:40 +00:00
PPAP integration
This commit is contained in:
@@ -0,0 +1,547 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Esiur.Security.Authority.Providers.Ppap;
|
||||
|
||||
/// <summary>
|
||||
/// Per-connection PPAP ML-KEM state. A handler instance must not be reused.
|
||||
/// </summary>
|
||||
public sealed partial class PpapAuthenticationHandler : IAuthenticationHandler,
|
||||
IAuthenticationKeyRotationHandler, IDisposable
|
||||
{
|
||||
enum HandshakeState
|
||||
{
|
||||
InitiatorStart,
|
||||
InitiatorAwaitServerHello,
|
||||
InitiatorAwaitResponderProof,
|
||||
ResponderAwaitClientHello,
|
||||
ResponderAwaitInitiatorProof,
|
||||
ResponderAwaitInitiatorFinished,
|
||||
Complete,
|
||||
Failed,
|
||||
Disposed,
|
||||
}
|
||||
|
||||
readonly object _sync = new();
|
||||
readonly PpapAuthenticationProvider _provider;
|
||||
readonly PpapLocalIdentity _localIdentity;
|
||||
readonly AuthenticationDirection _direction;
|
||||
readonly AuthenticationMode _mode;
|
||||
readonly string _domain;
|
||||
readonly string _expectedInitiatorIdentity;
|
||||
readonly string _expectedResponderIdentity;
|
||||
readonly bool _authenticateInitiator;
|
||||
readonly bool _authenticateResponder;
|
||||
readonly List<byte[]> _transcript = new();
|
||||
|
||||
HandshakeState _state;
|
||||
string _initiatorIdentity;
|
||||
string _responderIdentity;
|
||||
PpapRegistrationRecord _initiatorRegistration;
|
||||
PpapRegistrationRecord _responderRegistration;
|
||||
byte[] _initiatorMask;
|
||||
byte[] _responderMask;
|
||||
byte[] _ephemeralPrivateKey;
|
||||
byte[] _ephemeralSecret;
|
||||
byte[] _initiatorIdentitySecret;
|
||||
byte[] _responderIdentitySecret;
|
||||
byte[] _sessionKey;
|
||||
byte[] _initiatorFinishedKey;
|
||||
byte[] _responderFinishedKey;
|
||||
byte[] _transcriptHash;
|
||||
byte[] _authenticationContext;
|
||||
|
||||
public IAuthenticationProvider Provider => _provider;
|
||||
public string Protocol => PpapProtocol.Name;
|
||||
|
||||
internal PpapAuthenticationHandler(PpapAuthenticationProvider provider,
|
||||
AuthenticationContext context)
|
||||
{
|
||||
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||
_localIdentity = provider.ResolveLocalIdentity(context);
|
||||
_direction = context.Direction;
|
||||
_mode = context.Mode;
|
||||
_domain = PpapCryptography.NormalizeDomain(context.Domain);
|
||||
_expectedInitiatorIdentity = NormalizeOptionalIdentity(context.InitiatorIdentity);
|
||||
_expectedResponderIdentity = NormalizeOptionalIdentity(context.ResponderIdentity);
|
||||
|
||||
if (_direction != AuthenticationDirection.Initiator
|
||||
&& _direction != AuthenticationDirection.Responder)
|
||||
throw new ArgumentOutOfRangeException(nameof(context.Direction));
|
||||
if (_mode != AuthenticationMode.InitializerIdentity
|
||||
&& _mode != AuthenticationMode.ResponderIdentity
|
||||
&& _mode != AuthenticationMode.DualIdentity)
|
||||
throw new ArgumentOutOfRangeException(nameof(context.Mode));
|
||||
|
||||
_authenticateInitiator = _mode == AuthenticationMode.InitializerIdentity
|
||||
|| _mode == AuthenticationMode.DualIdentity;
|
||||
_authenticateResponder = _mode == AuthenticationMode.ResponderIdentity
|
||||
|| _mode == AuthenticationMode.DualIdentity;
|
||||
|
||||
var localIsAuthenticated = _direction == AuthenticationDirection.Initiator
|
||||
? _authenticateInitiator
|
||||
: _authenticateResponder;
|
||||
if (localIsAuthenticated && _localIdentity == null)
|
||||
throw new InvalidOperationException(
|
||||
"This PPAP mode requires a provider-configured local identity.");
|
||||
|
||||
if (_localIdentity != null)
|
||||
{
|
||||
var expectedLocal = _direction == AuthenticationDirection.Initiator
|
||||
? _expectedInitiatorIdentity
|
||||
: _expectedResponderIdentity;
|
||||
if (expectedLocal != null && !string.Equals(expectedLocal,
|
||||
_localIdentity.Identity, StringComparison.Ordinal))
|
||||
throw new InvalidOperationException(
|
||||
"The connection identity does not match the PPAP provider identity.");
|
||||
}
|
||||
|
||||
_state = _direction == AuthenticationDirection.Initiator
|
||||
? HandshakeState.InitiatorStart
|
||||
: HandshakeState.ResponderAwaitClientHello;
|
||||
}
|
||||
|
||||
public AuthenticationResult Process(object authData)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (_state == HandshakeState.Disposed)
|
||||
return Failed();
|
||||
|
||||
try
|
||||
{
|
||||
if (_direction == AuthenticationDirection.Initiator)
|
||||
return ProcessInitiator(authData);
|
||||
return ProcessResponder(authData);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_state = HandshakeState.Failed;
|
||||
ClearHandshakeSecrets(clearSessionKey: true);
|
||||
ClearRotationSecrets();
|
||||
return Failed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationResult ProcessInitiator(object authData)
|
||||
{
|
||||
if (_state == HandshakeState.InitiatorStart)
|
||||
{
|
||||
if (authData != null)
|
||||
throw new InvalidDataException("Unexpected initial PPAP data.");
|
||||
|
||||
if (_authenticateInitiator)
|
||||
_initiatorIdentity = _localIdentity.Identity;
|
||||
|
||||
PpapCryptography.GenerateKeyPair(out _ephemeralPrivateKey,
|
||||
out var ephemeralPublicKey);
|
||||
_initiatorMask = PpapCryptography.RandomBytes(PpapProtocol.IdentityMaskLength);
|
||||
byte[] message = null;
|
||||
try
|
||||
{
|
||||
message = PpapWire.EncodeClientHello(_mode, _domain,
|
||||
ephemeralPublicKey, _initiatorMask);
|
||||
AddTranscript(message);
|
||||
_state = HandshakeState.InitiatorAwaitServerHello;
|
||||
return InProgress(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(ephemeralPublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == HandshakeState.InitiatorAwaitServerHello)
|
||||
{
|
||||
var raw = RequireBytes(authData);
|
||||
var hello = PpapWire.DecodeServerHello(raw, _authenticateResponder);
|
||||
AddTranscript(raw);
|
||||
|
||||
_ephemeralSecret = PpapCryptography.Decapsulate(
|
||||
_ephemeralPrivateKey, hello.EphemeralCiphertext);
|
||||
PpapCryptography.Clear(_ephemeralPrivateKey);
|
||||
_ephemeralPrivateKey = null;
|
||||
_responderMask = hello.ResponderMask;
|
||||
|
||||
byte[] maskedInitiator = null;
|
||||
byte[] responderCiphertext = null;
|
||||
PpapRegistrationDescriptor responderDescriptor = null;
|
||||
|
||||
if (_authenticateInitiator)
|
||||
maskedInitiator = PpapCryptography.MaskIdentity(_domain,
|
||||
_initiatorIdentity, _responderMask, _ephemeralSecret);
|
||||
|
||||
if (_authenticateResponder)
|
||||
{
|
||||
_responderRegistration = _provider.Registrations.ResolveMasked(
|
||||
_domain, _initiatorMask, _ephemeralSecret,
|
||||
hello.MaskedResponderIdentity);
|
||||
ValidateRemoteRegistration(_responderRegistration,
|
||||
_expectedResponderIdentity);
|
||||
_responderIdentity = _responderRegistration.Identity;
|
||||
PpapCryptography.Encapsulate(
|
||||
_responderRegistration.EncapsulationKeyBytes,
|
||||
out responderCiphertext, out _responderIdentitySecret);
|
||||
responderDescriptor = PpapRegistrationDescriptor.FromRecord(
|
||||
_responderRegistration);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var message = PpapWire.EncodeInitiatorProof(maskedInitiator,
|
||||
responderCiphertext, responderDescriptor, _domain,
|
||||
_ephemeralSecret);
|
||||
AddTranscript(message);
|
||||
_state = HandshakeState.InitiatorAwaitResponderProof;
|
||||
return InProgress(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(maskedInitiator);
|
||||
PpapCryptography.Clear(responderCiphertext);
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == HandshakeState.InitiatorAwaitResponderProof)
|
||||
{
|
||||
var proof = PpapWire.DecodeResponderProof(authData,
|
||||
_authenticateInitiator, _domain, _ephemeralSecret);
|
||||
AddTranscript(proof.TranscriptCore);
|
||||
|
||||
if (_authenticateInitiator)
|
||||
{
|
||||
ValidateLocalDescriptor(proof.InitiatorRegistration,
|
||||
_localIdentity);
|
||||
byte[] privateKey = null;
|
||||
byte[] publicKey = null;
|
||||
try
|
||||
{
|
||||
privateKey = _provider.DerivePrivateKey(_localIdentity, _domain,
|
||||
proof.InitiatorRegistration.Nonce,
|
||||
proof.InitiatorRegistration.KdfProfile);
|
||||
publicKey = PpapCryptography.GetPublicKey(privateKey);
|
||||
_initiatorIdentitySecret = PpapCryptography.Decapsulate(
|
||||
privateKey, proof.InitiatorCiphertext);
|
||||
_initiatorRegistration = new PpapRegistrationRecord(
|
||||
proof.InitiatorRegistration.Version, _initiatorIdentity,
|
||||
proof.InitiatorRegistration.Kind,
|
||||
proof.InitiatorRegistration.Nonce, publicKey,
|
||||
proof.InitiatorRegistration.KdfProfile);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(privateKey);
|
||||
PpapCryptography.Clear(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
DeriveHandshakeKeys();
|
||||
var expected = PpapCryptography.ComputeFinished(false,
|
||||
_responderFinishedKey, _transcriptHash);
|
||||
var verified = PpapCryptography.FixedTimeEquals(expected, proof.Finished);
|
||||
PpapCryptography.Clear(expected);
|
||||
PpapCryptography.Clear(proof.Finished);
|
||||
PpapCryptography.Clear(proof.TranscriptCore);
|
||||
if (!verified)
|
||||
throw new InvalidDataException("Responder Finished verification failed.");
|
||||
|
||||
var initiatorFinished = PpapCryptography.ComputeFinished(true,
|
||||
_initiatorFinishedKey, _transcriptHash);
|
||||
try
|
||||
{
|
||||
var message = PpapWire.EncodeInitiatorFinished(initiatorFinished);
|
||||
_state = HandshakeState.Complete;
|
||||
ClearPostConfirmationSecrets();
|
||||
return Succeeded(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(initiatorFinished);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidDataException("Invalid PPAP initiator state.");
|
||||
}
|
||||
|
||||
AuthenticationResult ProcessResponder(object authData)
|
||||
{
|
||||
if (_state == HandshakeState.ResponderAwaitClientHello)
|
||||
{
|
||||
var raw = RequireBytes(authData);
|
||||
var hello = PpapWire.DecodeClientHello(raw);
|
||||
if (hello.Mode != _mode
|
||||
|| !string.Equals(hello.Domain, _domain, StringComparison.Ordinal))
|
||||
throw new InvalidDataException("PPAP context mismatch.");
|
||||
AddTranscript(raw);
|
||||
_initiatorMask = hello.InitiatorMask;
|
||||
|
||||
if (_authenticateResponder)
|
||||
_responderIdentity = _localIdentity.Identity;
|
||||
|
||||
PpapCryptography.Encapsulate(hello.EphemeralKey,
|
||||
out var ephemeralCiphertext, out _ephemeralSecret);
|
||||
_responderMask = PpapCryptography.RandomBytes(
|
||||
PpapProtocol.IdentityMaskLength);
|
||||
byte[] maskedResponder = null;
|
||||
if (_authenticateResponder)
|
||||
maskedResponder = PpapCryptography.MaskIdentity(_domain,
|
||||
_responderIdentity, _initiatorMask, _ephemeralSecret);
|
||||
|
||||
try
|
||||
{
|
||||
var message = PpapWire.EncodeServerHello(ephemeralCiphertext,
|
||||
_responderMask, maskedResponder);
|
||||
AddTranscript(message);
|
||||
_state = HandshakeState.ResponderAwaitInitiatorProof;
|
||||
return InProgress(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(ephemeralCiphertext);
|
||||
PpapCryptography.Clear(maskedResponder);
|
||||
PpapCryptography.Clear(hello.EphemeralKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == HandshakeState.ResponderAwaitInitiatorProof)
|
||||
{
|
||||
var raw = RequireBytes(authData);
|
||||
var proof = PpapWire.DecodeInitiatorProof(raw,
|
||||
_authenticateInitiator, _authenticateResponder, _domain,
|
||||
_ephemeralSecret);
|
||||
AddTranscript(raw);
|
||||
|
||||
if (_authenticateResponder)
|
||||
{
|
||||
ValidateLocalDescriptor(proof.ResponderRegistration,
|
||||
_localIdentity);
|
||||
byte[] privateKey = null;
|
||||
byte[] publicKey = null;
|
||||
try
|
||||
{
|
||||
privateKey = _provider.DerivePrivateKey(_localIdentity, _domain,
|
||||
proof.ResponderRegistration.Nonce,
|
||||
proof.ResponderRegistration.KdfProfile);
|
||||
publicKey = PpapCryptography.GetPublicKey(privateKey);
|
||||
_responderIdentitySecret = PpapCryptography.Decapsulate(
|
||||
privateKey, proof.ResponderCiphertext);
|
||||
_responderRegistration = new PpapRegistrationRecord(
|
||||
proof.ResponderRegistration.Version, _responderIdentity,
|
||||
proof.ResponderRegistration.Kind,
|
||||
proof.ResponderRegistration.Nonce, publicKey,
|
||||
proof.ResponderRegistration.KdfProfile);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(privateKey);
|
||||
PpapCryptography.Clear(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] initiatorCiphertext = null;
|
||||
PpapRegistrationDescriptor initiatorDescriptor = null;
|
||||
if (_authenticateInitiator)
|
||||
{
|
||||
_initiatorRegistration = _provider.Registrations.ResolveMasked(
|
||||
_domain, _responderMask, _ephemeralSecret,
|
||||
proof.MaskedInitiatorIdentity);
|
||||
ValidateRemoteRegistration(_initiatorRegistration,
|
||||
_expectedInitiatorIdentity);
|
||||
_initiatorIdentity = _initiatorRegistration.Identity;
|
||||
PpapCryptography.Encapsulate(
|
||||
_initiatorRegistration.EncapsulationKeyBytes,
|
||||
out initiatorCiphertext, out _initiatorIdentitySecret);
|
||||
initiatorDescriptor = PpapRegistrationDescriptor.FromRecord(
|
||||
_initiatorRegistration);
|
||||
}
|
||||
|
||||
byte[] core = null;
|
||||
byte[] protectedInitiatorDescriptor = null;
|
||||
byte[] responderFinished = null;
|
||||
try
|
||||
{
|
||||
core = PpapWire.EncodeResponderProofCore(initiatorCiphertext,
|
||||
initiatorDescriptor, _domain, _ephemeralSecret,
|
||||
out protectedInitiatorDescriptor);
|
||||
AddTranscript(core);
|
||||
DeriveHandshakeKeys();
|
||||
responderFinished = PpapCryptography.ComputeFinished(false,
|
||||
_responderFinishedKey, _transcriptHash);
|
||||
var message = PpapWire.EncodeResponderProof(initiatorCiphertext,
|
||||
protectedInitiatorDescriptor, responderFinished);
|
||||
_state = HandshakeState.ResponderAwaitInitiatorFinished;
|
||||
return InProgress(message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PpapCryptography.Clear(core);
|
||||
PpapCryptography.Clear(protectedInitiatorDescriptor);
|
||||
PpapCryptography.Clear(initiatorCiphertext);
|
||||
PpapCryptography.Clear(responderFinished);
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == HandshakeState.ResponderAwaitInitiatorFinished)
|
||||
{
|
||||
var remoteFinished = PpapWire.DecodeInitiatorFinished(authData);
|
||||
var expected = PpapCryptography.ComputeFinished(true,
|
||||
_initiatorFinishedKey, _transcriptHash);
|
||||
var verified = PpapCryptography.FixedTimeEquals(expected, remoteFinished);
|
||||
PpapCryptography.Clear(expected);
|
||||
PpapCryptography.Clear(remoteFinished);
|
||||
if (!verified)
|
||||
throw new InvalidDataException("Initiator Finished verification failed.");
|
||||
|
||||
_state = HandshakeState.Complete;
|
||||
ClearPostConfirmationSecrets();
|
||||
return Succeeded(null);
|
||||
}
|
||||
|
||||
throw new InvalidDataException("Invalid PPAP responder state.");
|
||||
}
|
||||
|
||||
void DeriveHandshakeKeys()
|
||||
{
|
||||
_authenticationContext = PpapWire.EncodeAuthenticationContext(_mode,
|
||||
_domain, _initiatorIdentity,
|
||||
_authenticateInitiator ? (PpapIdentityKind?)GetInitiatorKind() : null,
|
||||
_responderIdentity,
|
||||
_authenticateResponder ? (PpapIdentityKind?)GetResponderKind() : null);
|
||||
_transcriptHash = PpapCryptography.ComputeTranscriptHash(
|
||||
_transcript, _authenticationContext);
|
||||
PpapCryptography.DeriveHandshakeKeys(_ephemeralSecret,
|
||||
_initiatorIdentitySecret, _responderIdentitySecret,
|
||||
_transcriptHash, _authenticationContext,
|
||||
out _sessionKey, out _initiatorFinishedKey,
|
||||
out _responderFinishedKey);
|
||||
|
||||
PpapCryptography.Clear(_ephemeralSecret);
|
||||
PpapCryptography.Clear(_initiatorIdentitySecret);
|
||||
PpapCryptography.Clear(_responderIdentitySecret);
|
||||
_ephemeralSecret = null;
|
||||
_initiatorIdentitySecret = null;
|
||||
_responderIdentitySecret = null;
|
||||
}
|
||||
|
||||
PpapIdentityKind GetInitiatorKind()
|
||||
=> _initiatorRegistration?.Kind ?? _localIdentity.Kind;
|
||||
|
||||
PpapIdentityKind GetResponderKind()
|
||||
=> _responderRegistration?.Kind ?? _localIdentity.Kind;
|
||||
|
||||
void ValidateRemoteRegistration(PpapRegistrationRecord record,
|
||||
string expectedIdentity)
|
||||
{
|
||||
if (record == null)
|
||||
throw new InvalidDataException("The masked identity could not be resolved.");
|
||||
if (expectedIdentity != null && !string.Equals(expectedIdentity,
|
||||
record.Identity, StringComparison.Ordinal))
|
||||
throw new InvalidDataException("The resolved identity was not expected.");
|
||||
}
|
||||
|
||||
static void ValidateLocalDescriptor(PpapRegistrationDescriptor descriptor,
|
||||
PpapLocalIdentity identity)
|
||||
{
|
||||
if (descriptor == null || identity == null || descriptor.Kind != identity.Kind)
|
||||
throw new InvalidDataException("The local registration descriptor is invalid.");
|
||||
if (identity.Kind == PpapIdentityKind.PasswordDerived
|
||||
&& !identity.KdfProfile.Equals(descriptor.KdfProfile))
|
||||
throw new InvalidDataException("The local registration KDF profile is not accepted.");
|
||||
}
|
||||
|
||||
void AddTranscript(byte[] message)
|
||||
{
|
||||
if (message == null || message.Length == 0
|
||||
|| message.Length > PpapProtocol.MaximumWireMessageBytes)
|
||||
throw new InvalidDataException("Invalid transcript message.");
|
||||
_transcript.Add((byte[])message.Clone());
|
||||
}
|
||||
|
||||
static byte[] RequireBytes(object data)
|
||||
{
|
||||
if (!(data is byte[] value))
|
||||
throw new InvalidDataException("PPAP data must be a byte array.");
|
||||
return value;
|
||||
}
|
||||
|
||||
AuthenticationResult InProgress(byte[] data)
|
||||
=> new AuthenticationResult(AuthenticationRuling.InProgress, data);
|
||||
|
||||
AuthenticationResult Succeeded(byte[] data)
|
||||
{
|
||||
var local = _direction == AuthenticationDirection.Initiator
|
||||
? _initiatorIdentity : _responderIdentity;
|
||||
var remote = _direction == AuthenticationDirection.Initiator
|
||||
? _responderIdentity : _initiatorIdentity;
|
||||
return new AuthenticationResult(AuthenticationRuling.Succeeded, data,
|
||||
local, remote, _sessionKey);
|
||||
}
|
||||
|
||||
static AuthenticationResult Failed()
|
||||
=> new AuthenticationResult(AuthenticationRuling.Failed, null);
|
||||
|
||||
static string NormalizeOptionalIdentity(string identity)
|
||||
=> identity == null ? null : PpapCryptography.NormalizeIdentity(identity);
|
||||
|
||||
void ClearPostConfirmationSecrets()
|
||||
{
|
||||
PpapCryptography.Clear(_initiatorFinishedKey);
|
||||
PpapCryptography.Clear(_responderFinishedKey);
|
||||
PpapCryptography.Clear(_transcriptHash);
|
||||
PpapCryptography.Clear(_authenticationContext);
|
||||
PpapCryptography.Clear(_initiatorMask);
|
||||
PpapCryptography.Clear(_responderMask);
|
||||
_initiatorFinishedKey = null;
|
||||
_responderFinishedKey = null;
|
||||
_transcriptHash = null;
|
||||
_authenticationContext = null;
|
||||
_initiatorMask = null;
|
||||
_responderMask = null;
|
||||
foreach (var message in _transcript)
|
||||
PpapCryptography.Clear(message);
|
||||
_transcript.Clear();
|
||||
}
|
||||
|
||||
void ClearHandshakeSecrets(bool clearSessionKey)
|
||||
{
|
||||
PpapCryptography.Clear(_ephemeralPrivateKey);
|
||||
PpapCryptography.Clear(_ephemeralSecret);
|
||||
PpapCryptography.Clear(_initiatorIdentitySecret);
|
||||
PpapCryptography.Clear(_responderIdentitySecret);
|
||||
PpapCryptography.Clear(_initiatorFinishedKey);
|
||||
PpapCryptography.Clear(_responderFinishedKey);
|
||||
PpapCryptography.Clear(_transcriptHash);
|
||||
PpapCryptography.Clear(_authenticationContext);
|
||||
if (clearSessionKey)
|
||||
PpapCryptography.Clear(_sessionKey);
|
||||
_ephemeralPrivateKey = null;
|
||||
_ephemeralSecret = null;
|
||||
_initiatorIdentitySecret = null;
|
||||
_responderIdentitySecret = null;
|
||||
_initiatorFinishedKey = null;
|
||||
_responderFinishedKey = null;
|
||||
if (clearSessionKey)
|
||||
_sessionKey = null;
|
||||
foreach (var message in _transcript)
|
||||
PpapCryptography.Clear(message);
|
||||
_transcript.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (_state == HandshakeState.Disposed)
|
||||
return;
|
||||
ClearHandshakeSecrets(clearSessionKey: true);
|
||||
PpapCryptography.Clear(_initiatorMask);
|
||||
PpapCryptography.Clear(_responderMask);
|
||||
PpapCryptography.Clear(_transcriptHash);
|
||||
PpapCryptography.Clear(_authenticationContext);
|
||||
ClearRotationSecrets();
|
||||
_state = HandshakeState.Disposed;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user