這裡(http://www.linuxidc.com/Linux/2012-08/68722.htm)寫過了RSA非對稱加密解密的交互方式,
其實數字簽名也是RSA非對稱加密,只不過用私鑰加密的,再加上個hash摘要
CryptoAPI與openssl RSA非對稱加密解密(PKCS1 PADDING)交互已經提到關於證書和私鑰的數據以及對象獲取,這裡就不再重復討論
1.openssl的簽名及驗證
- void opensslSigner::sign(EVP_PKEY* evpKey,BYTE** signValue,unsigned int &signLen,BYTE* text,int textLen)
- {
- EVP_MD_CTX mdctx; //摘要算法上下文變量
-
- if(evpKey == NULL)
- {
- printf("EVP_PKEY_new err\n");
- return;
- }
-
- //以下是計算簽名的代碼
- EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
- if(!EVP_SignInit_ex(&mdctx,EVP_md5(),NULL)) //簽名初始化,設置摘要算法
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- return;
- }
- if(!EVP_SignUpdate(&mdctx,text,textLen)) //計算簽名(摘要)Update
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- return;
- }
- if(!EVP_SignFinal(&mdctx,*signValue,&signLen,evpKey)) //簽名輸出
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- return;
- }
- printf("消息\"%s\"的簽名值是:\n",text);
- printByte(*signValue,signLen);
- printf("\n");
- EVP_MD_CTX_cleanup(&mdctx);
-
- }
-
- void opensslSigner::verify(EVP_PKEY* evpKey,BYTE* text,unsigned int textLen,BYTE* signValue,unsigned int signLen)
- {
- ERR_load_EVP_strings();
- EVP_MD_CTX mdctx; //摘要算法上下文變量
- EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
- if(!EVP_VerifyInit_ex(&mdctx, EVP_md5(), NULL)) //驗證初始化,設置摘要算法,一定要和簽名一致
- {
- printf("EVP_VerifyInit_ex err\n");
- EVP_PKEY_free(evpKey);
- return;
- }
- if(!EVP_VerifyUpdate(&mdctx, text, textLen)) //驗證簽名(摘要)Update
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- return;
- }
- if(!EVP_VerifyFinal(&mdctx,signValue,signLen,evpKey))
- {
- printf("verify err\n");
- EVP_PKEY_free(evpKey);
- EVP_MD_CTX_cleanup(&mdctx);
- return;
- }
- else
- {
- printf("驗證簽名正確.\n");
- }
- //釋放內存
- EVP_PKEY_free(evpKey);
- EVP_MD_CTX_cleanup(&mdctx);
- }
2.CryptoAPI的簽名驗證
依然是私鑰的問題,沒時間再去嘗試導入私鑰,暫且只寫驗證
因為也是RSA加密,所以同樣要注意字節排列方式,具體看RSA加密的交互部分
- void verify(HCRYPTPROV hProv,PCCERT_CONTEXT cert,BYTE* text,unsigned long len,BYTE* signValue,unsigned long signLen)
- {
- //反序與openssl一致
- for(int i = 0 ; i < signLen / 2;i++)
- {
- BYTE temp = signValue[i];
- signValue[i] = signValue[signLen - i - 1];
- signValue[signLen - i - 1] = temp;
- }
-
- // 創建離散對象
- HCRYPTHASH hHash = NULL;
- if(!CryptCreateHash(
- hProv, // 容器句柄
- CALG_MD5, // 算法標識
- NULL, // 算法使用的Key
- 0, // 算法標識
- &hHash)) // 返回的HASH對象
- {
- printf("CryptCreateHash error:0X%x.\n",GetLastError());
- return;
- }
-
- // 計算數據摘要
- if(CryptHashData(hHash, text, len, 0) == 0)
- {
- printf("CryptHashData error:0X%x.\n",GetLastError());
- return;
- }
-
-
- if(cert == NULL)
- {
- printf("pCertContext == NULL:0X%x.\n",GetLastError());
- return;
- }
- //獲取公鑰句柄
- HCRYPTKEY hPubKey;
- if(!CryptImportPublicKeyInfo(hProv, cert->dwCertEncodingType, &cert->pCertInfo->SubjectPublicKeyInfo, &hPubKey))
- {
- printf("CryptImportPublicKeyInfo error:0X%x.\n",GetLastError());
- return;
- }
- //驗證簽名
- if(!CryptVerifySignature(hHash, signValue, signLen, hPubKey, NULL, 0))
- {
- printf("CryptVerifySignature error:0X%x.\n",GetLastError());
- return;
- }
- cout << "sign verify successfully" << endl;
- }