internal static unsafe CngKey ImportEncryptedPkcs8( ReadOnlySpan <byte> keyBlob, ReadOnlySpan <char> password, CngProvider provider) { SafeNCryptProviderHandle providerHandle = provider.OpenStorageProvider(); SafeNCryptKeyHandle keyHandle; using (SafeUnicodeStringHandle passwordHandle = new SafeUnicodeStringHandle(password)) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[1]; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = passwordHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 1, pBuffers = (IntPtr)buffers, ulVersion = 0, }; ErrorCode errorCode = Interop.NCrypt.NCryptImportKey( providerHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { keyHandle.Dispose(); providerHandle.Dispose(); throw errorCode.ToCryptographicException(); } } CngKey key = new CngKey(providerHandle, keyHandle); key.IsEphemeral = true; return(key); }
OpenNCryptProvider("Microsoft Software Key Storage Provider"); // MS_KEY_STORAGE_PROVIDER internal static unsafe SafeNCryptKeyHandle ImportKeyBlob( string blobType, ReadOnlySpan <byte> keyBlob, bool encrypted = false, ReadOnlySpan <char> password = default) { SafeNCryptKeyHandle keyHandle; ErrorCode errorCode; if (encrypted) { using (var stringHandle = new SafeUnicodeStringHandle(password)) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[1]; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = stringHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 1, pBuffers = (IntPtr)buffers, ulVersion = 0, }; errorCode = Interop.NCrypt.NCryptImportKey( s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, ref desc, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); } } else { errorCode = Interop.NCrypt.NCryptImportKey( s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, IntPtr.Zero, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Debug.Assert(keyHandle != null); SetExportable(keyHandle); return(keyHandle); }
internal static unsafe bool ExportPkcs8KeyBlob( bool allocate, SafeNCryptKeyHandle keyHandle, ReadOnlySpan <char> password, int kdfCount, Span <byte> destination, out int bytesWritten, out byte[]?allocated) { using (SafeUnicodeStringHandle stringHandle = new SafeUnicodeStringHandle(password)) { fixed(byte *oidPtr = s_pkcs12TripleDesOidBytes) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[3]; Interop.NCrypt.PBE_PARAMS pbeParams = default; Span <byte> salt = new Span <byte>(pbeParams.rgbSalt, Interop.NCrypt.PBE_PARAMS.RgbSaltSize); RandomNumberGenerator.Fill(salt); pbeParams.Params.cbSalt = salt.Length; pbeParams.Params.iIterations = kdfCount; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = stringHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } buffers[1] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsAlgOid, cbBuffer = s_pkcs12TripleDesOidBytes.Length, pvBuffer = (IntPtr)oidPtr, }; buffers[2] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsAlgParam, cbBuffer = sizeof(Interop.NCrypt.PBE_PARAMS), pvBuffer = (IntPtr)(&pbeParams), }; Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 3, pBuffers = (IntPtr)buffers, ulVersion = 0, }; Span <byte> empty = default; ErrorCode errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, ref MemoryMarshal.GetReference(empty), 0, out int numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } allocated = null; if (allocate) { allocated = new byte[numBytesNeeded]; destination = allocated; } else if (numBytesNeeded > destination.Length) { bytesWritten = 0; return(false); } errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, ref MemoryMarshal.GetReference(destination), destination.Length, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } if (allocate && numBytesNeeded != destination.Length) { byte[] trimmed = new byte[numBytesNeeded]; destination.Slice(0, numBytesNeeded).CopyTo(trimmed); CryptographicOperations.ZeroMemory(allocated.AsSpan(0, numBytesNeeded)); allocated = trimmed; } bytesWritten = numBytesNeeded; return(true); } } }