2011-12-20 67 views
5

我使用makecert效用OpenSSL和MS的CryptoAPI:不同的數字簽名

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 

然後我轉換RootCATest.pvk到RootCATest.pem使用OpenSSL生成X509證書與私鑰。我提取公鑰:pubRootCATest.pem

我有一個小文件叫'味精'。 我使用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簽名完全不同的簽名。
+0

對於進入簽名的數據以及簽名本身,有很多不同的格式。這是你必須正確的部分。 – 2011-12-20 22:09:04

+0

現在,使用RSA_verify驗證此簽名,如果它是可驗證的,則它是相同的。 – doptimusprime 2013-04-11 05:23:35

回答

-1

如何獲得相同的簽名?

大多數數字簽名算法 - 包括RSA,我猜你在這裏使用過,都是非確定性的。嘗試使用相同的程序對相同的文件進行兩次簽名,並且您將獲得不同的輸出。

這意味着,使用相同的輸入運行相同的算法兩次會給你不同的簽名。這不是問題,只要驗證算法仍然設法接受簽名算法(使用擬合密鑰)生成的所有簽名。

這種非確定性對於簽名方案的安全性通常實際上是必需的。

要查看您的兩個簽名算法是否實際兼容,請嘗試使用MS Crypto API驗證OpenSSL簽名,並使用OpenSSL驗證MS Crypto簽名。 (然後修改文件一個字節並檢查它們是否不再驗證。)

+0

Paulo,我設法獲得了同樣的簽名。但我改變了任務。 – Stanislav 2011-12-27 09:46:04

+2

我使用MS CryptoAPI生成密鑰和簽名,並使用OpenSSL進行驗證。反之亦然。簽名是獨一無二的!所以我想我在我的情況下處理確定性RSA。 – Stanislav 2011-12-27 13:38:26

+0

如果相同的數據由相同的私鑰簽名,簽名將始終相同,因爲填充不是隨機的。 – doptimusprime 2013-04-11 05:22:38