internal override unsafe NCryptKeyOrCryptProviderSafeHandle OpenExisting(string keyName, out KeySpec keySpec)
        {
            keySpec = KeySpec.NONE;
            const int DOES_NOT_EXIST = unchecked ((int)0x80090016);
            NCryptKeyOrCryptProviderSafeHandle provider;

            if (!AdvApi32.CryptAcquireContext(out provider, keyName, _providerName, ProviderType.PROV_RSA_AES, 0u))
            {
                var result = Marshal.GetLastWin32Error();
                if (result == DOES_NOT_EXIST)
                {
                    return(null);
                }
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            const uint PP_KEYSPEC    = 0x27;
            uint *     keySpecBuffer = stackalloc uint[1];
            var        dataLength    = (uint)Marshal.SizeOf(typeof(uint));

            if (!AdvApi32.CryptGetProvParam(provider, PP_KEYSPEC, keySpecBuffer, ref dataLength, 0u))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            keySpec = (KeySpec)(*keySpecBuffer);
            return(provider);
        }
        internal override NCryptKeyOrCryptProviderSafeHandle CreateKey(string keyName, int keySize, Algorithm algorithm, bool overwrite, KeyUsage keyUsage, out KeySpec keySpec)
        {
            const int ALREADY_EXISTS = unchecked ((int)0x8009000f);

            if (algorithm != Algorithm.RSA)
            {
                throw new ArgumentException("CAPI does not support algorithms other than RSA.", nameof(algorithm));
            }
            NCryptKeyOrCryptProviderSafeHandle provider;

            if (!AdvApi32.CryptAcquireContext(out provider, keyName, _providerName, ProviderType.PROV_RSA_AES, CryptAcquireContextFlags.CRYPT_NEWKEYSET))
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == ALREADY_EXISTS && overwrite)
                {
                    if (!AdvApi32.CryptAcquireContext(out provider, keyName, _providerName, ProviderType.PROV_RSA_AES, CryptAcquireContextFlags.CRYPT_DELETEKEYSET))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    if (!AdvApi32.CryptAcquireContext(out provider, keyName, _providerName, ProviderType.PROV_RSA_AES, CryptAcquireContextFlags.CRYPT_NEWKEYSET))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            var flags        = CryptGenKeyFlags.CRYPT_EXPORTABLE;
            var keySizeFlags = ((uint)keySize & 0xFFFFU) << 16;
            var genKeyFlags  = ((ushort)flags) | keySizeFlags;
            CryptKeySafeHandle key;
            KeySpec            algorithmKeySpec;

            switch (keyUsage)
            {
            case KeyUsage.KeyExchange:
                algorithmKeySpec = KeySpec.AT_KEYEXCHANGE;
                break;

            case KeyUsage.Signature:
                algorithmKeySpec = KeySpec.AT_SIGNATURE;
                break;

            default:
                throw new ArgumentException(nameof(keyUsage));
            }
            if (!AdvApi32.CryptGenKey(provider, algorithmKeySpec, genKeyFlags, out key))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            key.Close();
            keySpec = algorithmKeySpec;
            return(provider);
        }