Microsoft Cryptographic API是否允许从字节流中创建ECDSA密钥?

时间:2017-08-15 14:37:58

标签: c++ cryptography cryptoapi cng

所以我正在考虑使用哪个加密C ++库(我已经想出如何在C#中做等效)来验证许可文件签名哈希。

阅读CNG的Microsoft文档似乎无法从字节流中生成代码中的ECDSA密钥,尽管这可能是RSA密钥(我认为,不是100%肯定)。

因为我想在代码字节流生成中,我查看了crypto ++并且我设法编译了测试套件但是cryptolib.lib是一个超大的90兆字节,我面临一系列链接错误,只是尝试做一些基本的事情。所以我现在不太热衷于加密++。

所以我想回到使用微软在其桌面Windows操作系统中提供的东西,但我回到了原来的问题,即代码字节流生成的密钥没有。

专家能否确认这是不可能的?此外,他们可以建议替代方案,我很高兴用一根长的(2048?)钥匙回到RSA。

以下代码为我编译并运行。它可以在MSDN article - Signing Data with CNG找到。我想知道它是否可以改编。此代码(a)是否即时创建ECDSA密钥(b)将哈希(c)保存密钥签名到证书存储区(d)检索密钥并验证签名哈希。如果是这样,我猜它的演示代码。我需要的是硬编码的ECDSA密钥的示例,而不是动态创建的密钥。

// CngECDSA.cpp : Defines the entry point for the console application.
// Based on https://msdn.microsoft.com/en-us/library/windows/desktop/aa376304(v=vs.85).aspx

#include "stdafx.h"

#include <Windows.h>
#include <stdint.h>
#include <Bcrypt.h>
#include <ncrypt.h>

#pragma comment(lib, "bcrypt")  
#pragma comment(lib, "ncrypt")


#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)

static const  BYTE rgbMsg[] =
{
    0x04, 0x87, 0xec, 0x66, 0xa8, 0xbf, 0x17, 0xa6,
    0xe3, 0x62, 0x6f, 0x1a, 0x55, 0xe2, 0xaf, 0x5e,
    0xbc, 0x54, 0xa4, 0xdc, 0x68, 0x19, 0x3e, 0x94,
};

BYTE value[] =
{ 0x02,0x00,0x00,0x00 };

void __cdecl wmain(
    int                      argc,
    __in_ecount(argc) LPWSTR *wargv)
{
    NCRYPT_PROV_HANDLE      hProv = NULL;
    NCRYPT_KEY_HANDLE       hKey = NULL;
    BCRYPT_KEY_HANDLE       hTmpKey = NULL;
    SECURITY_STATUS         secStatus = ERROR_SUCCESS;
    BCRYPT_ALG_HANDLE       hHashAlg = NULL,
        hSignAlg = NULL;
    BCRYPT_HASH_HANDLE      hHash = NULL;
    NTSTATUS                status = STATUS_UNSUCCESSFUL;
    DWORD                   cbData = 0,
        cbHash = 0,
        cbBlob = 0,
        cbSignature = 0,
        cbHashObject = 0;
    PBYTE                   pbHashObject = NULL;
    PBYTE                   pbHash = NULL,
        pbBlob = NULL,
        pbSignature = NULL;

    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(wargv);

    //open an algorithm handle
    if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
        &hHashAlg,
        BCRYPT_SHA1_ALGORITHM,
        NULL,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
        goto Cleanup;
    }

    if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
        &hSignAlg,
        BCRYPT_ECDSA_P256_ALGORITHM,
        NULL,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
        goto Cleanup;
    }

    //calculate the size of the buffer to hold the hash object
    if (!NT_SUCCESS(status = BCryptGetProperty(
        hHashAlg,
        BCRYPT_OBJECT_LENGTH,
        (PBYTE)&cbHashObject,
        sizeof(DWORD),
        &cbData,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    //allocate the hash object on the heap
    pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
    if (NULL == pbHashObject)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    //calculate the length of the hash
    if (!NT_SUCCESS(status = BCryptGetProperty(
        hHashAlg,
        BCRYPT_HASH_LENGTH,
        (PBYTE)&cbHash,
        sizeof(DWORD),
        &cbData,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    //allocate the hash buffer on the heap
    pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
    if (NULL == pbHash)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    //create a hash
    if (!NT_SUCCESS(status = BCryptCreateHash(
        hHashAlg,
        &hHash,
        pbHashObject,
        cbHashObject,
        NULL,
        0,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptCreateHash\n", status);
        goto Cleanup;
    }


    //hash some data
    if (!NT_SUCCESS(status = BCryptHashData(
        hHash,
        (PBYTE)rgbMsg,
        sizeof(rgbMsg),
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptHashData\n", status);
        goto Cleanup;
    }

    //close the hash
    if (!NT_SUCCESS(status = BCryptFinishHash(
        hHash,
        pbHash,
        cbHash,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptFinishHash\n", status);
        goto Cleanup;
    }

    //open handle to KSP
    if (FAILED(secStatus = NCryptOpenStorageProvider(
        &hProv,
        MS_KEY_STORAGE_PROVIDER,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptOpenStorageProvider\n", secStatus);
        goto Cleanup;
    }

    //create a persisted key
    if (FAILED(secStatus = NCryptCreatePersistedKey(
        hProv,
        &hKey,
        NCRYPT_ECDSA_P256_ALGORITHM,
        L"my ecc key",
        0,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptCreatePersistedKey\n", secStatus);
        goto Cleanup;
    }

    //create key on disk
    if (FAILED(secStatus = NCryptFinalizeKey(hKey, 0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptFinalizeKey\n", secStatus);
        goto Cleanup;
    }

    //sign the hash
    if (FAILED(secStatus = NCryptSignHash(
        hKey,
        NULL,
        pbHash,
        cbHash,
        NULL,
        0,
        &cbSignature,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
        goto Cleanup;
    }


    //allocate the signature buffer
    pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature);
    if (NULL == pbSignature)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    if (FAILED(secStatus = NCryptSignHash(
        hKey,
        NULL,
        pbHash,
        cbHash,
        pbSignature,
        cbSignature,
        &cbSignature,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
        goto Cleanup;
    }

    if (FAILED(secStatus = NCryptExportKey(
        hKey,
        NULL,
        BCRYPT_ECCPUBLIC_BLOB,
        NULL,
        NULL,
        0,
        &cbBlob,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
        goto Cleanup;
    }

    pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
    if (NULL == pbBlob)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    if (FAILED(secStatus = NCryptExportKey(
        hKey,
        NULL,
        BCRYPT_ECCPUBLIC_BLOB,
        NULL,
        pbBlob,
        cbBlob,
        &cbBlob,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
        goto Cleanup;
    }

    if (!NT_SUCCESS(status = BCryptImportKeyPair(
        hSignAlg,
        NULL,
        BCRYPT_ECCPUBLIC_BLOB,
        &hTmpKey,
        pbBlob,
        cbBlob,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status);
        goto Cleanup;
    }

    if (!NT_SUCCESS(status = BCryptVerifySignature(
        hTmpKey,
        NULL,
        pbHash,
        cbHash,
        pbSignature,
        cbSignature,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
        goto Cleanup;
    }

    wprintf(L"Success!\n");

Cleanup:

    if (hHashAlg)
    {
        BCryptCloseAlgorithmProvider(hHashAlg, 0);
    }

    if (hSignAlg)
    {
        BCryptCloseAlgorithmProvider(hSignAlg, 0);
    }

    if (hHash)
    {
        BCryptDestroyHash(hHash);
    }

    if (pbHashObject)
    {
        HeapFree(GetProcessHeap(), 0, pbHashObject);
    }

    if (pbHash)
    {
        HeapFree(GetProcessHeap(), 0, pbHash);
    }

    if (pbSignature)
    {
        HeapFree(GetProcessHeap(), 0, pbSignature);
    }

    if (pbBlob)
    {
        HeapFree(GetProcessHeap(), 0, pbBlob);
    }

    if (hTmpKey)
    {
        BCryptDestroyKey(hTmpKey);
    }

    if (hKey)
    {
        NCryptDeleteKey(hKey, 0);
    }

    if (hProv)
    {
        NCryptFreeObject(hProv);
    }
}

为了清楚起见,我的目标是384位并且与OpenSsl和C#curvename的兼容性是NIST推荐的曲线secp384r1 – {1.3.132.0.34}而且我将使用SHA256哈希两次(就像BitCoin一样)。

0 个答案:

没有答案