Как вызывать функции Schannel из.Net/C#
Я пытаюсь переупорядочить / удалить наборы шифров по причинам соответствия (я хочу использовать 256-битные AES и временные ключи) в.Net. Однако, используя WCF TCP Transport Security, я уступаю весь контроль над безопасностью реализации TLS в Windows и ее предпочтительным шифрам. Я не хочу менять шифры системного уровня.
Я нашел эту отличную страницу Microsoft, в которой перечислено, как это сделать на уровне приложения, используя BCryptEnumContextFunctions, BCryptAddContextFunction, BCryptRemoveContextFunction, но это все C, и у меня нет достаточного опыта P/Invoke, чтобы даже знать, с чего начать. Я погуглил, но никого не нашел.
Ниже приведены фрагменты кода C++ на странице MSDN, и мне нужна помощь в преобразовании их в вызовы.Net P/Invoke:
BCryptEnumContextFunctions
#include <stdio.h>
#include <windows.h>
#include <bcrypt.h>
void main()
{
HRESULT Status = ERROR_SUCCESS;
DWORD cbBuffer = 0;
PCRYPT_CONTEXT_FUNCTIONS pBuffer = NULL;
Status = BCryptEnumContextFunctions(
CRYPT_LOCAL,
L"SSL",
NCRYPT_SCHANNEL_INTERFACE,
&cbBuffer,
&pBuffer);
if(FAILED(Status))
{
printf_s("\n**** Error 0x%x returned by BCryptEnumContextFunctions\n", Status);
goto Cleanup;
}
if(pBuffer == NULL)
{
printf_s("\n**** Error pBuffer returned from BCryptEnumContextFunctions is null");
goto Cleanup;
}
printf_s("\n\n Listing Cipher Suites ");
for(UINT index = 0; index < pBuffer->cFunctions; ++index)
{
printf_s("\n%S", pBuffer->rgpszFunctions[index]);
}
Cleanup:
if (pBuffer != NULL)
{
BCryptFreeBuffer(pBuffer);
}
}
BCryptAddContextFunction
#include <stdio.h>
#include <windows.h>
#include <bcrypt.h>
void main()
{
SECURITY_STATUS Status = ERROR_SUCCESS;
LPWSTR wszCipher = (L"RSA_EXPORT1024_DES_CBC_SHA");
Status = BCryptAddContextFunction(
CRYPT_LOCAL,
L"SSL",
NCRYPT_SCHANNEL_INTERFACE,
wszCipher,
CRYPT_PRIORITY_TOP);
}
BCryptRemoveContextFunction
#include <stdio.h>
#include <windows.h>
#include <bcrypt.h>
void main()
{
SECURITY_STATUS Status = ERROR_SUCCESS;
LPWSTR wszCipher = (L"TLS_RSA_WITH_RC4_128_SHA");
Status = BCryptRemoveContextFunction(
CRYPT_LOCAL,
L"SSL",
NCRYPT_SCHANNEL_INTERFACE,
wszCipher);
}
Может ли кто-нибудь помочь мне преобразовать их в.Net, чтобы я мог вызывать их из управляемого кода для настройки шифров? Спасибо!
Редактировать:
Позже прошлой ночью я попробовал следующее в тестовой программе (до сих пор понятия не имею, что я делаю в P/Invoke):
// I found this in bcrypt.h
const uint CRYPT_LOCAL = 0x00000001;
// I can't find this anywhere in Microsoft's headers in my SDK,
// but I found some random .c file with it in there. No idea
// what this constant actually is according to Microsoft
const uint NCRYPT_SCHANNEL_INTERFACE = 0x00010002;
public static void DoStuff()
{
PCRYPT_CONTEXT_FUNCTIONS pBuffer = new PCRYPT_CONTEXT_FUNCTIONS();
pBuffer.rgpszFunctions = String.Empty.PadRight(1500);
uint cbBuffer = (uint)Marshal.SizeOf(typeof(PCRYPT_CONTEXT_FUNCTIONS));
uint Status = BCryptEnumContextFunctions(
CRYPT_LOCAL,
"SSL",
NCRYPT_SCHANNEL_INTERFACE,
ref cbBuffer,
ref pBuffer);
Console.WriteLine(Status);
Console.WriteLine(pBuffer);
Console.WriteLine(cbBuffer);
Console.WriteLine(pBuffer.cFunctions);
Console.WriteLine(pBuffer.rgpszFunctions);
}
/*
typedef struct _CRYPT_CONTEXT_FUNCTIONS {
ULONG cFunctions;
PWSTR rgpszFunctions;
} CRYPT_CONTEXT_FUNCTIONS, *PCRYPT_CONTEXT_FUNCTIONS;
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PCRYPT_CONTEXT_FUNCTIONS
{
public uint cFunctions;
public string rgpszFunctions;
}
/*
NTSTATUS WINAPI BCryptEnumContextFunctions(
ULONG dwTable,
LPCWSTR pszContext,
ULONG dwInterface,
ULONG *pcbBuffer,
PCRYPT_CONTEXT_FUNCTIONS *ppBuffer
);
*/
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern uint BCryptEnumContextFunctions(uint dwTable, string pszContext, uint dwInterface, ref uint pcbBuffer, ref PCRYPT_CONTEXT_FUNCTIONS ppBuffer);
Прямой вывод единственного метода, с которым я дошел даже до этого:
0
MyClass+PCRYPT_CONTEXT_FUNCTIONS
2400
8934576
[1500 spaces that I initialized rgpszFunctions with, not the cipher functions]
1 ответ
Это плохо документированная библиотека. Например, объявление CRYPT_CONTEXT_FUNCTION_PROVIDERS
на самом деле:
typedef struct _CRYPT_CONTEXT_FUNCTION_PROVIDERS
{
ULONG cProviders;
PWSTR *rgpszProviders;
}
CRYPT_CONTEXT_FUNCTION_PROVIDERS, *PCRYPT_CONTEXT_FUNCTION_PROVIDERS;
Это снято прямо с bcrypt.h
,
В любом случае, вот перевод кода C++ для вас:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode)]
static extern uint BCryptEnumContextFunctions(uint dwTable, string pszContext, uint dwInterface, ref uint pcbBuffer, ref IntPtr ppBuffer);
[DllImport("Bcrypt.dll")]
static extern void BCryptFreeBuffer(IntPtr pvBuffer);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode)]
static extern uint BCryptAddContextFunction(uint dwTable, string pszContext, uint dwInterface, string pszFunction, uint dwPosition);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode)]
static extern uint BCryptRemoveContextFunction(uint dwTable, string pszContext, uint dwInterface, string pszFunction);
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_CONTEXT_FUNCTIONS
{
public uint cFunctions;
public IntPtr rgpszFunctions;
}
const uint CRYPT_LOCAL = 0x00000001;
const uint NCRYPT_SCHANNEL_INTERFACE = 0x00010002;
const uint CRYPT_PRIORITY_TOP = 0x00000000;
const uint CRYPT_PRIORITY_BOTTOM = 0xFFFFFFFF;
public static void DoStuff()
{
uint cbBuffer = 0;
IntPtr ppBuffer = IntPtr.Zero;
uint Status = BCryptEnumContextFunctions(
CRYPT_LOCAL,
"SSL",
NCRYPT_SCHANNEL_INTERFACE,
ref cbBuffer,
ref ppBuffer);
if (Status == 0)
{
CRYPT_CONTEXT_FUNCTIONS functions = (CRYPT_CONTEXT_FUNCTIONS)Marshal.PtrToStructure(ppBuffer, typeof(CRYPT_CONTEXT_FUNCTIONS));
Console.WriteLine(functions.cFunctions);
IntPtr pStr = functions.rgpszFunctions;
for (int i = 0; i < functions.cFunctions; i++)
{
Console.WriteLine(Marshal.PtrToStringUni(Marshal.ReadIntPtr(pStr)));
pStr += IntPtr.Size;
}
BCryptFreeBuffer(ppBuffer);
}
}
static void Main(string[] args)
{
DoStuff();
Console.ReadLine();
}
}
}
На моей машине вывод:
30 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 TLS_DHE_DSS_WITH_AES_256_CBC_SHA TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_RC4_128_MD5 SSL_CK_RC4_128_WITH_MD5 SSL_CK_DES_192_EDE3_CBC_WITH_MD5 TLS_RSA_WITH_NULL_SHA256 TLS_RSA_WITH_NULL_SHA
Я призываю вас разобраться с простым C++, чтобы добиться прогресса. Возьмите пример из MSDN и скомпилируйте его. Запустите его под отладчиком и познакомьтесь с ним. Используйте Visual Studio для поиска определений и объявлений. Например, Visual Studio привел меня прямо к определению NCRYPT_SCHANNEL_INTERFACE
,