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