public void Initialize(string servicePrincipalName, byte[] inBytes, out byte[] outBytes)
        {
            outBytes = null;

            var outputBuffer = new SecurityBufferDescriptor((int)_credential.PackageInfo.MaxTokenSize);

            var credentialAddRefSuccess = false;
            var contextAddRefSuccess    = false;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                _credential.DangerousAddRef(ref credentialAddRefSuccess);
                DangerousAddRef(ref contextAddRefSuccess);
            }
            catch (Exception ex)
            {
                if (credentialAddRefSuccess)
                {
                    _credential.DangerousRelease();
                    credentialAddRefSuccess = false;
                }
                if (contextAddRefSuccess)
                {
                    DangerousRelease();
                    contextAddRefSuccess = false;
                }

                if (!(ex is ObjectDisposedException))
                {
                    throw;
                }
            }
            finally
            {
                try
                {
                    uint result;
                    long timestamp;
                    var  credentialHandle = _credential.Handle;
                    if (inBytes == null || inBytes.Length == 0)
                    {
                        result = NativeMethods.InitializeSecurityContext(
                            ref credentialHandle,
                            IntPtr.Zero,
                            servicePrincipalName,
                            _requestedContextFlags,
                            0,
                            DataRepresentation.Network,
                            IntPtr.Zero,
                            0,
                            ref _handle,
                            ref outputBuffer,
                            out _receivedContextFlags,
                            out timestamp);
                    }
                    else
                    {
                        var serverToken = new SecurityBufferDescriptor(inBytes);

                        try
                        {
                            result = NativeMethods.InitializeSecurityContext(
                                ref credentialHandle,
                                ref _handle,
                                servicePrincipalName,
                                _requestedContextFlags,
                                0,
                                DataRepresentation.Network,
                                ref serverToken,
                                0,
                                ref _handle,
                                ref outputBuffer,
                                out _receivedContextFlags,
                                out timestamp);
                        }
                        finally
                        {
                            serverToken.Free();
                        }
                    }

                    _credential.DangerousRelease();
                    DangerousRelease();

                    if (result != NativeMethods.SEC_E_OK && result != NativeMethods.SEC_I_CONTINUE_NEEDED)
                    {
                        throw Win32Exception.Create(result, "Unable to initialize security context.");
                    }

                    outBytes      = outputBuffer.ToByteArray();
                    IsInitialized = result == NativeMethods.SEC_E_OK;
                }
                finally
                {
                    outputBuffer.Free();
                }
            }
        }
        public void AcceptToken(byte[] inBytes, out byte[] outBytes)
        {
            outBytes = null;

            var outputBuffer = new SecurityBufferDescriptor((int)_credential.PackageInfo.MaxTokenSize);

            var credentialAddRefSuccess = false;
            var contextAddRefSuccess    = false;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                _credential.DangerousAddRef(ref credentialAddRefSuccess);
                DangerousAddRef(ref contextAddRefSuccess);
            }
            catch (Exception ex)
            {
                if (credentialAddRefSuccess)
                {
                    _credential.DangerousRelease();
                    credentialAddRefSuccess = false;
                }
                if (contextAddRefSuccess)
                {
                    DangerousRelease();
                    contextAddRefSuccess = false;
                }

                if (!(ex is ObjectDisposedException))
                {
                    throw;
                }
            }
            finally
            {
                try
                {
                    var flags       = SspiContextFlags.MutualAuth;
                    var clientToken = new SecurityBufferDescriptor(inBytes);

                    uint result;
                    long timestamp;
                    var  credentialHandle = _credential.Handle;
                    if (_handle.IsZero)
                    {
                        result = NativeMethods.AcceptSecurityContext(
                            ref credentialHandle,
                            IntPtr.Zero,
                            ref clientToken,
                            flags,
                            DataRepresentation.Network,
                            ref _handle,
                            ref outputBuffer,
                            out flags,
                            out timestamp);
                    }
                    else
                    {
                        try
                        {
                            result = NativeMethods.AcceptSecurityContext(
                                ref credentialHandle,
                                ref _handle,
                                ref clientToken,
                                flags,
                                DataRepresentation.Network,
                                ref _handle,
                                ref outputBuffer,
                                out flags,
                                out timestamp);
                        }
                        finally
                        {
                            clientToken.Free();
                        }
                    }

                    _credential.DangerousRelease();
                    DangerousRelease();

                    if (result != NativeMethods.SEC_E_OK && result != NativeMethods.SEC_I_CONTINUE_NEEDED)
                    {
                        throw Win32Exception.Create(result, "Unable to initialize security context.");
                    }

                    outBytes      = outputBuffer.ToByteArray();
                    IsInitialized = result == NativeMethods.SEC_E_OK;
                }
                finally
                {
                    outputBuffer.Free();
                }
            }
        }
        public void VerifySignature(byte[] inBytes, out byte[] outBytes)
        {
            bool contextAddRefSuccess = false;

            SecurityPackageContextSizes sizes;

            QueryBufferSizes(out sizes);

            var buffers = new[]
            {
                new SecurityBuffer(new byte[sizes.SecurityTrailer], SecurityBufferType.Token),
                new SecurityBuffer(inBytes, SecurityBufferType.Data),
                new SecurityBuffer(new byte[sizes.BlockSize], SecurityBufferType.Padding)
            };

            var descriptor = new SecurityBufferDescriptor(buffers);

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                DangerousAddRef(ref contextAddRefSuccess);
            }
            catch (Exception ex)
            {
                if (contextAddRefSuccess)
                {
                    DangerousRelease();
                    contextAddRefSuccess = false;
                }

                if (!(ex is ObjectDisposedException))
                {
                    throw;
                }
            }
            finally
            {
                try
                {
                    var status = NativeMethods.VerifySignature(ref _handle, ref descriptor, 0, MakeSignatureQualityOfProtection.None);

                    DangerousRelease();

                    switch ((long)status)
                    {
                    case NativeMethods.SEC_E_OK:
                        outBytes = descriptor.ToByteArray();
                        break;

                    case NativeMethods.SEC_E_OUT_OF_SEQUENCE:
                    case NativeMethods.SEC_E_MESSAGE_ALTERED:
                        outBytes = null;
                        break;

                    default:
                        throw Win32Exception.Create(status, "Unable to encrypt message.");
                    }
                }
                finally
                {
                    descriptor.Free();
                }
            }
        }