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); }