使用CryptVerifySignature进行数字签名

时间:2012-10-03 17:27:30

标签: c++ winapi cryptography digital-signature

我想使用CryptVerifySignature实现数字签名应用。我已经编写了这段代码(在MSDN示例的帮助下):

#define Check(condition, message) if (!(condition)) { fprintf(stderr, "%s\n", message); goto Exit; };
void DigSign(const char* inputFileName, const char* signFileName)
{

    HCRYPTPROV hProv;
    BYTE *pbBuffer= NULL;
    DWORD dwBufferLen = 0;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    HCRYPTKEY hPubKey;
    BYTE *pbKeyBlob;        
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD dwBlobLen;

    FILE* inputFile = NULL;

    Check((inputFile = fopen(inputFileName, "r")) != NULL, "File does not exists");
    dwBufferLen = GetFileSize(inputFile);
    Check(pbBuffer = (BYTE*)malloc(dwBufferLen + 1), "cannot allocate memory");

    fread(pbBuffer, 1, dwBufferLen, inputFile);
    pbBuffer[dwBufferLen] = '\0';
    fclose(inputFile);


    //-------------------------------------------------------------------
    // Acquire a cryptographic provider context handle.

    Check(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0), "Error during CryptAcquireContext.");


    if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) 
    {
        if(NTE_NO_KEY == GetLastError())
        {
            Check(CryptGenKey(hProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKey), "Could not create a user public key.\n");
        }
        else
        {
            goto Exit;
        }
    }

    Check(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwBlobLen), "Error computing BLOB length.");
    Check(pbKeyBlob = (BYTE*)malloc(dwBlobLen), "Out of memory. \n");
    Check(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen), "Error during CryptExportKey.");

    //-------------------------------------------------------------------
    // Create the hash object.
    Check(CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash), "Error during CryptCreateHash.");

    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    Check(CryptHashData(hHash, pbBuffer, dwBufferLen, 0), "Error during CryptHashData.");

    //-------------------------------------------------------------------
    // Determine the size of the signature and allocate memory.

    dwSigLen= 0;
    Check(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, NULL, &dwSigLen), "Error during CryptSignHash.");

    //-------------------------------------------------------------------
    // Allocate memory for the signature buffer.
    Check(pbSignature = (BYTE *)malloc(dwSigLen), "Out of memory.");

    //-------------------------------------------------------------------
    // Sign the hash object.
    Check(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen), "Error during CryptSignHash.");

    FILE* f = fopen(signFileName, "w");
    fwrite(pbSignature, dwSigLen, 1, f);
    printf("W: %.128s\n", pbSignature);
    fwrite(pbKeyBlob, dwBlobLen, 1, f);
    printf("W: %.148s\n", pbKeyBlob);
    fclose(f);
    //-------------------------------------------------------------------
    // Destroy the hash object.

    if(hHash) 
        CryptDestroyHash(hHash);

    free(pbSignature);
    free(pbKeyBlob);

    if(hProv) 
        CryptReleaseContext(hProv, 0);

Exit:;
}


bool CheckDigSign(const char* inputFileName, const char* signFileName, const char* userName)
{
    bool result = false;
    HCRYPTPROV hProv;
    BYTE *pbBuffer= (BYTE *)"The data that is to be hashed and signed.";
    DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    HCRYPTKEY hPubKey;
    BYTE *pbKeyBlob;        
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD dwBlobLen;

    FILE* inputFile = NULL;

    Check((inputFile = fopen(inputFileName, "r")) != NULL, "File does not exists");
    dwBufferLen = GetFileSize(inputFile);
    Check(pbBuffer = (BYTE*)malloc(dwBufferLen + 1), "cannot allocate memory");

    fread(pbBuffer, 1, dwBufferLen, inputFile);
    pbBuffer[dwBufferLen] = '\0';
    fclose(inputFile);


    FILE* signFile = NULL;
    Check((signFile = fopen(signFileName, "r")) != NULL, "File does not exists");
    DWORD dwSignFileLen = GetFileSize(signFile);
    dwSigLen = 128;
    pbSignature = (BYTE*)malloc(dwSigLen);
    dwBlobLen = dwSignFileLen - dwSigLen;
    pbKeyBlob = (BYTE*)malloc(dwBlobLen);
    fread(pbSignature, 1, dwSigLen, signFile);
    fread(pbKeyBlob, 1, dwBlobLen, signFile);
    fclose(signFile);



    printf("R: %.128s\n", pbSignature);
    printf("R: %.148s\n", pbKeyBlob);

    Check(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0), "Error during CryptAcquireContext.");

    Check(CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey), "Public key import failed.");

    //-------------------------------------------------------------------
    // Create a new hash object.
    Check(CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash), "Error during CryptCreateHash.");

    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    Check(CryptHashData(hHash, pbBuffer, dwBufferLen, 0), "Error during CryptHashData.");

    //-------------------------------------------------------------------
    // Validate the digital signature.

    result = CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey, NULL, 0); 
    printf("%u %x", GetLastError(), GetLastError());
    //-------------------------------------------------------------------
    // Free memory to be used to store signature.

    if(pbSignature)
        free(pbSignature);

    //-------------------------------------------------------------------
    // Destroy the hash object.

    if(hHash) 
        CryptDestroyHash(hHash);

    //-------------------------------------------------------------------
    // Release the provider handle.

    if(hProv) 
        CryptReleaseContext(hProv, 0);

Exit:
    return result;
}


int _tmain(int argc, _TCHAR* argv[])
{


    DigSign("test3.txt", "test.sig");
    printf("TEST: %u\n", CheckDigSign("test3.txt", "test.sig", ""));
}

DigSign功能必须签署文件内容并将签名和公钥写入另一个文件。如果符号正确,CheckSign必须返回true。但我不明白为什么我的代码不起作用。 _tmain中的CheckDigSign必须返回true,但返回false。有人可以帮我吗?

1 个答案:

答案 0 :(得分:4)

我拿了你的整个代码示例,将其破解了一点,并对所有文件I / O使用了CreateFile,ReadFile和WriteFile。有用。对源文件检查附加公钥的签名文件就好了。

因此我怀疑这是读取/写入文件的方法,特别是“w”和“r”与“wb”和“rb”之间的字节。尝试改变它们,看看你想出了什么。

作为参考,修改后的代码如下,并且我所做的更改没有错误检查,所以不要将它用于任何特殊的东西,因为它实际上比它打印的纸张价值低(即没有)。

#define Check(condition, message) if (!(condition)) { fprintf(stderr, "%s\n", message); goto Exit; };
void DigSign(const char* inputFileName, const char* signFileName)
{

    HCRYPTPROV hProv;
    BYTE *pbBuffer= NULL;
    DWORD dwBufferLen = 0;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    BYTE *pbKeyBlob;        
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD dwBlobLen;

    FILE* inputFile = NULL;

    HANDLE hFileInput = CreateFile(inputFileName,   // file to open
                         GENERIC_READ,              // open for reading
                         FILE_SHARE_READ,           // share for reading
                         NULL,                      // default security
                         OPEN_EXISTING,             // existing file only
                         FILE_ATTRIBUTE_NORMAL,     // normal file
                         NULL);    

    dwBufferLen = GetFileSize(hFileInput, NULL);
    Check(pbBuffer = (BYTE*)malloc(dwBufferLen + 1), "cannot allocate memory");

    DWORD dwBytesRead = 0L;
    ReadFile(hFileInput, pbBuffer, dwBufferLen, &dwBytesRead, NULL);
    pbBuffer[dwBufferLen] = 0;
    CloseHandle(hFileInput);


    //-------------------------------------------------------------------
    // Acquire a cryptographic provider context handle.

    Check(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0), "Error during CryptAcquireContext.");


    if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) 
    {
        if(NTE_NO_KEY == GetLastError())
        {
            Check(CryptGenKey(hProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKey), "Could not create a user public key.\n");
        }
        else
        {
            goto Exit;
        }
    }

    Check(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwBlobLen), "Error computing BLOB length.");
    Check(pbKeyBlob = (BYTE*)malloc(dwBlobLen), "Out of memory. \n");
    Check(CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen), "Error during CryptExportKey.");

    //-------------------------------------------------------------------
    // Create the hash object.
    Check(CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash), "Error during CryptCreateHash.");

    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    Check(CryptHashData(hHash, pbBuffer, dwBufferLen, 0), "Error during CryptHashData.");

    //-------------------------------------------------------------------
    // Determine the size of the signature and allocate memory.

    dwSigLen= 0;
    Check(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, NULL, &dwSigLen), "Error during CryptSignHash.");

    //-------------------------------------------------------------------
    // Allocate memory for the signature buffer.
    Check(pbSignature = (BYTE *)malloc(dwSigLen), "Out of memory.");

    //-------------------------------------------------------------------
    // Sign the hash object.
    Check(CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen), "Error during CryptSignHash.");

    HANDLE hFileSign = CreateFile(signFileName, // name of the write
                         GENERIC_WRITE,         // open for writing
                         0,                     // do not share
                         NULL,                  // default security
                         CREATE_NEW,            // create new file only
                         FILE_ATTRIBUTE_NORMAL, // normal file
                         NULL);                  // no attr. template

    DWORD dwBytesWritten = 0;
    WriteFile(hFileSign, pbSignature, dwSigLen, &dwBytesWritten, NULL);
    WriteFile(hFileSign, pbKeyBlob, dwBlobLen, &dwBytesWritten, NULL);
    CloseHandle(hFileSign);

    printf("W: %.128s\n", pbSignature);
    printf("W: %.148s\n", pbKeyBlob);

    //-------------------------------------------------------------------
    // Destroy the hash object.

    if(hHash) 
        CryptDestroyHash(hHash);

    free(pbSignature);
    free(pbKeyBlob);

    if(hProv) 
        CryptReleaseContext(hProv, 0);

Exit:;
}


bool CheckDigSign(const char* inputFileName, const char* signFileName, const char* userName)
{
    BOOL result = false;
    HCRYPTPROV hProv;
    BYTE *pbBuffer= (BYTE *)"The data that is to be hashed and signed.";
    DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
    HCRYPTHASH hHash;
    HCRYPTKEY hPubKey;
    BYTE *pbKeyBlob;        
    BYTE *pbSignature;
    DWORD dwSigLen;
    DWORD dwBlobLen;

    HANDLE hFileInput = CreateFile(inputFileName,   // file to open
                         GENERIC_READ,              // open for reading
                         FILE_SHARE_READ,           // share for reading
                         NULL,                      // default security
                         OPEN_EXISTING,             // existing file only
                         FILE_ATTRIBUTE_NORMAL,     // normal file
                         NULL);

    dwBufferLen = GetFileSize(hFileInput, NULL);
    Check(pbBuffer = (BYTE*)malloc(dwBufferLen + 1), "cannot allocate memory");

    DWORD dwBytesRead = 0;
    ReadFile(hFileInput, pbBuffer, dwBufferLen, &dwBytesRead, NULL);
    pbBuffer[dwBufferLen] = 0;
    CloseHandle(hFileInput);

    HANDLE hFileSig = CreateFile(signFileName,      // file to open
                         GENERIC_READ,              // open for reading
                         FILE_SHARE_READ,           // share for reading
                         NULL,                      // default security
                         OPEN_EXISTING,             // existing file only
                         FILE_ATTRIBUTE_NORMAL,     // normal file
                         NULL);

    DWORD dwSignFileLen = GetFileSize(hFileSig, NULL);
    dwSigLen = 128;
    pbSignature = (BYTE*)malloc(dwSigLen);
    dwBlobLen = dwSignFileLen - dwSigLen;
    pbKeyBlob = (BYTE*)malloc(dwBlobLen);
    ReadFile(hFileSig, pbSignature, dwSigLen, &dwBytesRead, NULL);
    ReadFile(hFileSig, pbKeyBlob, dwBlobLen, &dwBytesRead, NULL);
    CloseHandle(hFileSig);

    printf("R: %.128s\n", pbSignature);
    printf("R: %.148s\n", pbKeyBlob);

    Check(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0), "Error during CryptAcquireContext.");
    Check(CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey), "Public key import failed.");

    //-------------------------------------------------------------------
    // Create a new hash object.
    Check(CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash), "Error during CryptCreateHash.");

    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.
    Check(CryptHashData(hHash, pbBuffer, dwBufferLen, 0), "Error during CryptHashData.");

    //-------------------------------------------------------------------
    // Validate the digital signature.

    result = CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey, NULL, 0); 
    printf("%u %x", GetLastError(), GetLastError());
    //-------------------------------------------------------------------
    // Free memory to be used to store signature.

    if(pbSignature)
        free(pbSignature);

    //-------------------------------------------------------------------
    // Destroy the hash object.

    if(hHash) 
        CryptDestroyHash(hHash);

    //-------------------------------------------------------------------
    // Release the provider handle.

    if(hProv) 
        CryptReleaseContext(hProv, 0);

Exit:
    return !!result;
}


int _tmain(int argc, _TCHAR* argv[])
{
    if (argc == 3)
    {
        DigSign(argv[1], argv[2]);
        printf("TEST: %u\n", CheckDigSign(argv[1], argv[2],""));
        return 0;
    }
    return 1;
}