Siarhei Fedartsou
Siarhei Fedartsou

Reputation: 1873

Digital signature with CryptVerifySignature

I want to implement digital signature app using CryptVerifySignature. I've written this code(with help of MSDN example):

#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 function must sign content of file and write signature and public key to another file. CheckSign must return true if sign is right. But I don't understand why my code doesn't work. CheckDigSign in _tmain must return true, but it returns false. Can anybody help me pls?

Upvotes: 0

Views: 4087

Answers (1)

WhozCraig
WhozCraig

Reputation: 66244

I took your entire code sample, hacked it up a little, and used CreateFile, ReadFile, and WriteFile for all the file I/O. It works. The signature file with the appended public key checked against the source file just fine.

I therefore suspect it is the method of reading/writing your files, and specifically, the "w" and "r" vs. "wb" and "rb" that is horking over your bytes. Try changing those and see what you come up with.

For reference, the modified code is below, and there is NO error checking in the changes I made, so DON'T use this for anything special as it is literally worth less than the paper its printed on (i.e. nothing).

#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;
}

Upvotes: 4

Related Questions