【问题标题】:OpenSSL and MS CryptoAPI: different digital signaturesOpenSSL 和 MS CryptoAPI:不同的数字签名
【发布时间】:2012-01-24 06:30:36
【问题描述】:

我使用 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 签名完全不同的签名。

【问题讨论】:

  • 进入签名的数据和签名本身有许多不同的格式。这是您必须正确处理的部分。
  • 现在,使用 RSA_verify 来验证这个签名,如果它是可验证的,那么它是相同的。

标签: openssl cryptography rsa cryptoapi mscapi


【解决方案1】:

我怎样才能获得相同的签名?

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

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

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

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

【讨论】:

  • 保罗,我设法获得了相同的签名。但我改变了任务。
  • 我使用 MS CryptoAPI 生成密钥和签名,并使用 OpenSSL 进行验证。反之亦然。而且签名是独一无二的!所以我想我已经处理了确定性 RSA。
  • 如果相同的数据由相同的私钥签名,签名将始终相同,因为填充不是随机的。
  • 不知道为什么你被否决了......我相当肯定你所说的一切都是正确的。
  • RSA 是非确定性的。 en.wikipedia.org/wiki/RSA_(cryptosystem)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多