OpenSSL 和 MS CryptoAPI:不同的数字签名

发布于 2024-12-22 10:54:34 字数 2569 浏览 4 评论 0原文

我使用 makecert 实用程序生成带有私钥的 X509 证书

makecert -n "CN=RootCATest" -r -sv RootCATest.pvk RootCATest.cer 
makecert -sk MyKeyName -iv RootCATest.pvk -n "CN=tempCert" -ic RootCATest.cer -sr currentuser -ss my -sky signature —pe 

,然后使用 OpenSSL 将 RootCATest.pvk 转换为 RootCATest.pem。我提取了公钥:pubRootCATest.pem

我有一个名为“msg”的小文件。 我使用 SHA1 签署该文件。

openssl dgst -sha1 -sign c:\RootCATest.pem -out c:\openssl c:\msg

然后我想使用 MS CryptoAPI 获得相同的数字签名。

这是我的代码(注意:这是理解概念的代码,所以我不会释放分配的内存)

void SwapBytes(BYTE *pv, int n)
{
    BYTE *p = pv;
    int lo, hi;
    for(lo=0, hi=n-1; hi>lo; lo++, hi--)
    {
        BYTE tmp=p[lo];
        p[lo] = p[hi];
        p[hi] = tmp;
    }
}

void sign()
{
    FILE *file;
    BYTE *msg;
    int msg_size;

    HCRYPTPROV hProv;
    HCERTSTORE hStore;
    PCCERT_CONTEXT pCert;
    DWORD dwKeySpec;
    BOOL fCallerFreeProv;
    BYTE  *pSignature;
    DWORD sigLen;

    // Read message bytes from file
    file = fopen("c:\\msg", "r");
    fseek(file, 0, SEEK_END);
    msg_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    msg = new BYTE[msg_size];
    fread(msg, sizeof(BYTE), msg_size, file);
    fclose(file);

    hStore = CertOpenSystemStore(NULL, "My");
    pCert = CryptUIDlgSelectCertificateFromStore(hStore, NULL, NULL, NULL, 0, 0, NULL);
    CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &fCallerFreeProv);
    PrintCryptoProviderName(hProv); // prints Microsoft Strong Cryptographic Provider

    ALG_ID hashAlgId = CALG_SHA1;
    HCRYPTHASH hHash;
    CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
    CryptHashData(hHash, msg, msg_size, 0);

    CryptSignHash(hHash, dwKeySpec, NULL, 0, NULL, &sigLen);
    pSignature = new BYTE[sigLen];
    CryptSignHash(hHash, dwKeySpec, NULL, CRYPT_NOHASHOID, pSignature, &sigLen);

    SwapBytes(pSignature, sigLen); // Here i reverse byte order as I read that MS CryptoAPI uses reversed byte order

    // Write signature bytes to file
    file = fopen("c:\\CryptSignHash", "w");
    fwrite(pSignature, sizeof(BYTE), sigLen, file);
    fclose(file);
}

作为输出,我得到的签名与 OpenSSL 生成的签名完全不同。 我怎样才能获得相同的签名?

我认为有一些时刻需要注意:

  • 我的 msg_size 与文件大小相同。所以它是字节数 符号。在某些网站上,我看到了在字节之间添加空字节的建议 大批。在这种情况下我真的需要它吗?
  • 标志 CRYPT_NOHASHOID。如果没有它,当 OpenSSL 生成的签名为 128 字节时,我会得到大小为 130 字节的签名。所以我认为 CRYPT_NOHASHOID 应该在那里。
  • SwapBytes(...) 我尝试过使用它和不使用它。在这两种情况下我 具有与 OpenSSL 签名完全不同的签名。

I generated X509 certificate with private key using makecert utility

makecert -n "CN=RootCATest" -r -sv RootCATest.pvk RootCATest.cer 
makecert -sk MyKeyName -iv RootCATest.pvk -n "CN=tempCert" -ic RootCATest.cer -sr currentuser -ss my -sky signature —pe 

Then I converted RootCATest.pvk to RootCATest.pem with OpenSSL. And I extracted public key: pubRootCATest.pem

I have small file called 'msg'.
And I sign this file using SHA1.

openssl dgst -sha1 -sign c:\RootCATest.pem -out c:\openssl c:\msg

Then I want to obtain the same digital signature using MS CryptoAPI.

Here is my code (Note: this is the code to understand concepts so I don't free allocated memory)

void SwapBytes(BYTE *pv, int n)
{
    BYTE *p = pv;
    int lo, hi;
    for(lo=0, hi=n-1; hi>lo; lo++, hi--)
    {
        BYTE tmp=p[lo];
        p[lo] = p[hi];
        p[hi] = tmp;
    }
}

void sign()
{
    FILE *file;
    BYTE *msg;
    int msg_size;

    HCRYPTPROV hProv;
    HCERTSTORE hStore;
    PCCERT_CONTEXT pCert;
    DWORD dwKeySpec;
    BOOL fCallerFreeProv;
    BYTE  *pSignature;
    DWORD sigLen;

    // Read message bytes from file
    file = fopen("c:\\msg", "r");
    fseek(file, 0, SEEK_END);
    msg_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    msg = new BYTE[msg_size];
    fread(msg, sizeof(BYTE), msg_size, file);
    fclose(file);

    hStore = CertOpenSystemStore(NULL, "My");
    pCert = CryptUIDlgSelectCertificateFromStore(hStore, NULL, NULL, NULL, 0, 0, NULL);
    CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &fCallerFreeProv);
    PrintCryptoProviderName(hProv); // prints Microsoft Strong Cryptographic Provider

    ALG_ID hashAlgId = CALG_SHA1;
    HCRYPTHASH hHash;
    CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
    CryptHashData(hHash, msg, msg_size, 0);

    CryptSignHash(hHash, dwKeySpec, NULL, 0, NULL, &sigLen);
    pSignature = new BYTE[sigLen];
    CryptSignHash(hHash, dwKeySpec, NULL, CRYPT_NOHASHOID, pSignature, &sigLen);

    SwapBytes(pSignature, sigLen); // Here i reverse byte order as I read that MS CryptoAPI uses reversed byte order

    // Write signature bytes to file
    file = fopen("c:\\CryptSignHash", "w");
    fwrite(pSignature, sizeof(BYTE), sigLen, file);
    fclose(file);
}

As output I get the signature absolutely different from the signature made by OpenSSL.
How can I obtain the same signature?

As I consider there are some moments to pay attention:

  • My msg_size is the same as file size. So it is the number of bytes to
    sign. On some sites I saw recommendations to add a null byte to byte
    array. Do I really need it in such a case?
  • The flag CRYPT_NOHASHOID. Without it I get the signature of size 130 bytes, when the signature made by OpenSSL is 128 bytes. So I think CRYPT_NOHASHOID should be there.
  • SwapBytes(...) I tried with it and without it. And in both cases I
    have signatures absolutely different to OpenSSL signature.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

回首观望 2024-12-29 10:54:34

如何获得相同的签名?

大多数数字签名算法(包括 RSA,我想您在这里使用过)都是不确定的。尝试使用同一个程序对同一个文件进行两次签名,您将得到不同的输出。

这意味着,使用相同的输入运行相同的算法两次将给出不同的签名。这不是问题,只要验证算法仍然设法接受签名算法生成的所有签名(使用合适的密钥)。

这种非确定性对于签名方案的安全性实际上通常是必要的。

要查看两种签名算法是否确实兼容,请尝试使用 MS Crypto API 验证 OpenSSL 签名,并使用 OpenSSL 验证 MS Crypto 签名。 (然后将文件修改一个字节并检查它们是否不再验证。)

How can I obtain the same signature?

Most digital signature algorithms - including RSA, which I suppose you have used here, are non-deterministic. Try signing the same file twice with the same program, and you will get different outputs.

This means, running the same algorithm twice with the same input will give you different signatures. This is not a problem, as long as the verification algorithm still manages to accept all signatures generated by the signing algorithm (with the fitting key).

This non-determinism is often actually necessary for the security of the signature scheme.

To see if your two signature algorithms are actually compatible, try to verify the OpenSSL signature with the MS Crypto API, and to verify the MS Crypto signature with OpenSSL. (Then modify the file by one byte and check that they don't verify anymore.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文