在c/c++中解決SHA1WithRSA/ras/X509的過程記錄

GOOSasha 8年前發布 | 46K 次閱讀 OpenSSL 加密解密 C/C++開發 C/C++

這里記錄了一種簡單的辦法,在遇到寫c/c++找不到答案時的最簡單找代碼辦法。

方法是:google找php怎么解決,大把的答案,然后看php源代碼是怎么用c實現的。

提出

我們server端在對接google play的時候,遇到了ras加密來驗證參數的實現,官方也沒有什么c的參考代碼,java和php的網上倒是能找到一堆。

java怎么解決

java的實現和本文要說的內容無關,只是隨帶一列:

public static boolean verify(String publicKey, byte[] data, String sign) throws Exception {

        // 解密由base64編碼的公鑰
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        System.out.println(keyBytes.length);
        // 構造X509EncodedKeySpec對象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        // 取公鑰匙對象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initVerify(pubKey);
        signature.update(data);

        // 驗證簽名是否正常
        return signature.verify(Base64.decodeBase64(sign));
    }

php怎么解決

php的實現比較多,隨便找了一個,沒有驗證過:

<?php
$public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’);
$pkeyid = openssl_pkey_get_public($public_key);
$data = ‘abc’;
$sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’;
$sign = base64_decode($sign);
if ($pkeyid) {
$verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
}
var_dump($verify);
?>

找到代碼

看到上面的php代碼,關鍵的幾個函數有:openssl_pkey_get_public openssl_verify

然后轉戰最新的php源代碼, https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c

別問為什么可以定位到這個文件的,github可以直接搜一個庫里的源文件。

忽略一切以zend、zval開頭的邏輯,直接找上面關鍵的函數。

于是就找到了關鍵的頭文件:

/* OpenSSL includes */
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>

關鍵的一行key生成代碼:

key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);

關鍵的核心邏輯:

EVP_VerifyInit (&md_ctx, mdtype);
    EVP_VerifyUpdate (&md_ctx, data, data_len);
    err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey);
    EVP_MD_CTX_cleanup(&md_ctx);

    if (keyresource == NULL) {
        EVP_PKEY_free(pkey);
    }

這么些核心代碼都找到了,還不會抄嗎?

最終解決

通過上面的過程,進行自己的組裝,已經再簡單不過了,為了讓寫c/c++的同學們快速得到google play的rsa驗證代碼,特別貼一下:

int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) {
    char *chPublicKey = const_cast<char *>(publicKey.c_str());

    BIO* mem_bio = NULL;
    if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) {        //從字符串讀取RSA公鑰
        BIO_free(mem_bio);
        return -3;
    }
    EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL);
    unsigned int slen = signature.length();

    EVP_MD_CTX md_ctx;
    EVP_VerifyInit(&md_ctx, EVP_sha1());
    EVP_VerifyUpdate(&md_ctx, message, strlen(message));
    int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa);
    EVP_MD_CTX_cleanup(&md_ctx);
    EVP_PKEY_free(publicRsa);
    return err;
}

結論

通過php的解決方案去找到php的實現,是寫c/c++同學們不可不學的一招。

EOF

English Version

a story about SHA1WithRSA/ras/X509 with c/c++

This is a simple solution when you do not know how to develop with c/c++.

The solution is,it will have lots of answer ho to do with php in Google,and then look up the desgin in the source codes of php.

Question

We need to verify the parameters by RSA when we devlop the Google Play apps.There is not any reference codes with c/c++.The java or php example are too many in internet.

How to resolve in java

It no connection with what we are talking about.Just BTW:

public static boolean verify(String publicKey, byte[] data, String sign) throws Exception {

        // 解密由base64編碼的公鑰
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        System.out.println(keyBytes.length);
        // 構造X509EncodedKeySpec對象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        // 取公鑰匙對象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initVerify(pubKey);
        signature.update(data);

        // 驗證簽名是否正常
        return signature.verify(Base64.decodeBase64(sign));
    }

How to resolve in php

There are too many php examples.Find one without checking:

<?php
$public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’);
$pkeyid = openssl_pkey_get_public($public_key);
$data = ‘abc’;
$sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’;
$sign = base64_decode($sign);
if ($pkeyid) {
$verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
}
var_dump($verify);
?>

Find the codes

The key functions are openssl_pkey_get_public and openssl_verify in the codes above mentioned.

Go to the newest php source codes, https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c

Dont ask me how to find the file.You can search the file in a project at Github.

Ignore all the codes start with zval and zend.Go to the codes which include the key functions.

And then there is the key header file:

/* OpenSSL includes */
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>

The key codes generated pkey:

key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);

The core logic:

EVP_VerifyInit (&md_ctx, mdtype);
    EVP_VerifyUpdate (&md_ctx, data, data_len);
    err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey);
    EVP_MD_CTX_cleanup(&md_ctx);

    if (keyresource == NULL) {
        EVP_PKEY_free(pkey);
    }

All of the codes are ready,cant you copy?

Final

It is easy to merge the codes above mentioned.

To get the codes faster for any other people,there are the codes about Google play Ras verifying:

int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) {
    char *chPublicKey = const_cast<char *>(publicKey.c_str());

    BIO* mem_bio = NULL;
    if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) {        //從字符串讀取RSA公鑰
        BIO_free(mem_bio);
        return -3;
    }
    EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL);
    unsigned int slen = signature.length();

    EVP_MD_CTX md_ctx;
    EVP_VerifyInit(&md_ctx, EVP_sha1());
    EVP_VerifyUpdate(&md_ctx, message, strlen(message));
    int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa);
    EVP_MD_CTX_cleanup(&md_ctx);
    EVP_PKEY_free(publicRsa);
    return err;
}

Conclusion

Is is a good solution for c/c++ developer.You can find the answer in php at first,go to see the c source codes of php at last.

原創文章如轉載,請注明:轉載自五四陳科學院[ http://www.54chen.com ]

 

來自: http://2014.54chen.com/blog/2016/05/25/a-story-about-sha1withrsa-slash-ras-slash-x509-with-c-slash-c-plus-plus/

 

 本文由用戶 GOOSasha 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!