場景:
只有公鑰字符串(base64編碼),需驗證簽名。
環境:
c++ + openssl
step1 從內存讀取公鑰
static RSA* GetPublicKeyRSA(string strPublicKey) { int nPublicKeyLen = strPublicKey.size(); //strPublicKey為base64編碼的公鑰字符串 for(int i = 64; i < nPublicKeyLen; i+=64) { if(strPublicKey[i] != '/n') { strPublicKey.insert(i, "/n"); } i++; } strPublicKey.insert(0, "-----BEGIN PUBLIC KEY-----/n"); strPublicKey.append("/n-----END PUBLIC KEY-----/n"); BIO *bio = NULL; RSA *rsa = NULL; char *chPublicKey = const_cast<char *>(strPublicKey.c_str()); if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) //從字符串讀取RSA公鑰 { cout<<"BIO_new_mem_buf failed!"<<endl; } rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); //從bio結構中得到rsa結構 if (NULL == rsa) { BIO_free_all(bio); unsigned long ulErr = ERR_get_error(); // 獲取錯誤號 char szErrMsg[1024] = {0}; char *pTmp = NULL; pTmp = ERR_error_string(ulErr,szErrMsg); // 格式:error:errId:庫:函數:原因 cout << szErrMsg; cout << "load public key fail error=" <<ulErr << " msg=" << szErrMsg; } else { cout<< "load public key ok "<<endl; } return rsa; }step2 開始驗證啦static bool verify( string sign, string content ){ // 公鑰字符串,經過base64編碼 string publicKey = "xxxxxxxxxxxxx"; // 得到公鑰的RSA結構體 RSA* rsa = GetPublicKeyRSA(publicKey); if (NULL == rsa) { return false; } // 將原串經過sha256摘要(摘要算法根據實際使用來,此處以sha256為例) string hash = Sha256(content.c_str(),false); // 將待驗證簽名用base64解碼(一般給的簽名是經過base64編碼的) string sign = Base64Decode((char *)gameAuthSign.c_str(), strlen(gameAuthSign.c_str())); // 此處簽名長度根據實際使用來,最好不要直接strlen(sign),可能發生截斷 int sign_len = 256; int res = RSA_verify(NID_sha256, (const unsigned char*)hash.c_str(), strlen(hash.c_str()), (unsigned char*)sign.c_str(),sign_len, rsa); if (res == 1) { gDebugStream("huawei verify ok"); } else {// 此api打印了驗證失敗的原因(bad signature,sigature length error等) unsigned long ulErr = ERR_get_error(); // 獲取錯誤號 char szErrMsg[1024] = {0}; char *pTmp = NULL; pTmp = ERR_error_string(ulErr,szErrMsg); // 格式:error:errId:庫:函數:原因 cout << szErrMsg; gDebugStream("verify error:" << szErrMsg); } return res == 1; }ps base64解碼,編碼 sha256摘要 都能過openssl實現 base64解碼
static string Base64Decode(char * input, int length) { string result; static char decode[1024] = {0}; if (NULL == input || length <= 0 || length >= 1024) { return result; } int len = EVP_DecodeBlock((unsigned char*)decode, (const unsigned char*)input, length); if (len >= 1024 || len <= 0) { return result; } decode[len] = '/0'; result.resize(len); for(int i = 0; i < len; i++) { result[i] = decode[i]; } return result; }base64編碼 static string Base64Encode(char * input, int length) { static char encoded[1024] = {0}; string result; if (NULL == input || length <= 0 || length >= 1024) { return result; } int len = EVP_EncodeBlock((unsigned char*)encoded, (const unsigned char*)input, length); if (len >= 1024 || len <= 0) { return result; } encoded[len] = '/0'; result = string(encoded); return result; }sha256static string Sha256(const char* data, bool bHex = true) { unsigned char md[SHA256_DIGEST_LENGTH] = {0}; SHA256((const unsigned char *)data, strlen(data), md); if (!bHex) { string s; s.resize(SHA256_DIGEST_LENGTH); for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) { s[i] = md[i]; } return s; } else { string s; s.resize(SHA256_DIGEST_LENGTH * 2); int k = 0; for(unsigned int i = 0; i < SHA256_DIGEST_LENGTH ; i++) { sPRintf(&s.at(k), "%02x", md[i]); k += 2; } return s; } }另外,嘗試過php來驗證但是讀取公鑰時總用報錯 $openssl_public_key = @openssl_get_publickey($pubKey);error:0906D06C:PEM routines:PEM_read_bio:no start line
似乎是openssl_get_publickey這個api不支持只用公鑰的字符串,應該讀取的是證書,但是只有公鑰字符串,我也不知道如何生成證書。。
最后~希望你順利驗證通過~~~~
新聞熱點
疑難解答