Благодаря этому замечательному веб-сайту, который я только что нашел: referenceouce.microsoft.com , я смог разобрать, что делает C # API при проверке подписи и импорте ключа.
Очевидно, мне нужен ncrypt / bcrypt, и подпись проверяется по хешу, а не по самим данным:
public bool VerifyData(Stream data, byte[] signature) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
using (BCryptHashAlgorithm hashAlgorithm = new BCryptHashAlgorithm(HashAlgorithm, BCryptNative.ProviderName.MicrosoftPrimitiveProvider)) {
hashAlgorithm.HashStream(data);
byte[] hashValue = hashAlgorithm.HashFinal();
return VerifyHash(hashValue, signature);
}
}
[SecuritySafeCritical]
public override bool VerifyHash(byte[] hash, byte[] signature) {
if (hash == null) {
throw new ArgumentNullException("hash");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
// We need to get the raw key handle to verify the signature. Asserting here is safe since verifiation
// is not a protected operation, and we do not expose the handle to the user code.
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
// This looks odd, but Key.Handle is really a duplicate so we need to dispose it
using (SafeNCryptKeyHandle keyHandle = Key.Handle) {
CodeAccessPermission.RevertAssert();
return NCryptNative.VerifySignature(keyHandle, hash, signature);
}
}
Вот нативное решение для тех, кому это нужно:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
char key[72] = { 69,67,83,49,32,0,0,0,227,146,138,255,218,235,122,141,44,110,211,95,59,227,226,163,81,188,242,115,60,171,46,141,221,117,169,139,42,143,67,85,144,242,232,188,22,158,230,15,110,6,214,252,252,242,224,241,110,186,1,244,176,65,88,184,94,19,98,174,158,7,154,152 };
char sign[64] = { 165,50,54,149,14,175,128,54,21,30,129,165,137,203,45,123,180,121,118,20,15,61,253,186,65,129,21,26,54,84,40,205,103,254,108,34,126,205,116,183,44,189,5,180,28,119,228,70,127,116,227,248,232,144,53,226,185,251,217,179,148,88,208,152 };
char message[] = { 1, 2, 3, 4, 5 };
BOOL crypt_init(char* key, unsigned long key_len)
{
HCRYPTPROV hProv = NULL;
BCRYPT_ALG_HANDLE hHashAlg = NULL, hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
PBYTE pbHash = NULL;
PBYTE pbHashObject = NULL;
DWORD cbHashObject = 0,
cbHash = 0,
cbData = 0;
NTSTATUS status;
if (ERROR_SUCCESS != NCryptOpenStorageProvider(&hProv, NULL, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
NCRYPT_KEY_HANDLE keyHandle;
if (ERROR_SUCCESS != NCryptImportKey(hProv, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, &keyHandle, (PBYTE)key, 72, 0)) {
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hHashAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)))
{
printf("BCryptOpenAlgorithmProvider failed - err=0x%x.\n", status);
return false;
}
if(!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
if (NULL == pbHashObject) {
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0))) {
printf("BCryptGetProperty failed - err=0x%x.\n", status);
return FALSE;
}
pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
if (NULL == pbHash)
{
printf("memory allocation failed\n");
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptCreateHash(hHashAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0)))
{
printf("BCryptCreateHash failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptHashData(hHash, (PBYTE)message, sizeof(message), 0)))
{
printf("BCryptHashData failed - err=0x%x.\n", status);
return FALSE;
}
if (!BCRYPT_SUCCESS(status = BCryptFinishHash(hHash, pbHash, cbHash, 0)))
{
printf("BCryptFinishHash failed - err=0x%x.\n", status);
return FALSE;
}
if(ERROR_SUCCESS != NCryptVerifySignature(keyHandle, NULL, pbHash, cbHash, (PBYTE) sign, sizeof(sign), 0)) {
printf("BCryptVerifySignature failed - err=0x%x.\n", status);
return FALSE;
}
return TRUE;
}
int main() {
crypt_init(key, 72);
}