為了防止在支付通信過程中的參數數據被篡改或者偽造,采用RSA進行數據簽名和驗證簽名。
RSA算法是一種非對稱密碼算法,所謂非對稱,就是指該算法需要一對密鑰,使用其中一個加密,則需要用另一個才能解密。
生成公私鑰:
生成 RSA 私鑰 PEM 文件:
openssl genrsa -out rsa_private_key.pem 2048
根據已經生成的私鑰再生成公鑰:
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
注意:生成后的rsa_private_key.pem私鑰不能直接用於java進行加密,原因是java使用的PKCS#8格式的私鑰,但PHP不會有問題。java的keytool生成的rsa公鑰密私鑰是16進制字符串,php用openssl生成的公鑰私鑰是基於base64格式的字符串或者二進制格式,這兩種不同的公約密鑰並不能直接轉化。
簽名驗證:
首先URL的參數請用'key'的字母順序排序,然后對整個URL,除了sign簽名參數之外的部分做簽名,以參數名sign做urlencode處理后加在URL后面。比如如下紅色的部分為簽名的原始字符串數據,藍色部分為追加的簽名值。
changba://game/goldpay?access_token=xxxxxxxx&id=yourgameid&orderid=111111&ordesc=%E8%B4%AD%E4%B9%B0%E4%B8%80%E4%B8%AAXX%E6%B8%B8%E6%88%8FXX%E6%AD%A6%E5%99%A8&payredirect_uri=game%3a%2f%2fchangba%2fpay&price=100&ver=1.0&sign=o8z82NNFYggbYC/kcPztSrXtTVa39A7eqyxhcNtvXRteHl8nvcNFmhrjk9lhz0Td877m4xUGb6LnEcs4acoeQnUtub6Yn1Y9sLtbQ1kBTTbD9oV2Ru0Gu4HutA/iJZWtFrzcvUo/JsZOCT4Vn9XtLGWFgvaPCpDqUF49/HBvJIVr/jMk2Ww2FuZgieIH8qBVHxTAoLdJfD2kwEMIPo9y/i3qbnluAmPC0vvuUZPaFohVn0M9BXps83c7750JaMJuFRarpC/Xp6gUjOm5neSbcwWBe7kHPWPIOjLTmQSWUlsf/Mu/Bhd/neHwzoUwqJbOotGRIFC6pfXiQhc6oidAxQ==
注意簽名的字符串數據中參數值必須是urlencode處理過的,簽名值需要再做base64編碼以及urlencode處理,以備當做sign URL參數傳遞。
驗簽的時候需要先進行base64解碼,然后才進行驗證簽名。
class ChangbaRsaSign { /**RSA簽名函數 * $data為待簽名數據,比如URL * 簽名用游戲方的保密私鑰,必須是沒有經過pkcs8轉換的.結果需要用base64編碼以備在URL中傳輸 * return Sign 簽名 */ public static function sign($data) { $priKey = file_get_contents('key/rsa_private_key.pem'); //轉換為openssl密鑰,必須是沒有經過pkcs8轉換的私鑰 $res = openssl_get_privatekey($priKey); //調用openssl內置簽名方法,生成簽名$sign openssl_sign($data, $sign, $res); openssl_free_key($res); $sign = base64_encode($sign); return $sign; } /**RSA驗證簽名 * $data為要驗證的數據字符串 * $sign是需要驗證的簽名數據,是直接從URL中取到的$_POST["sign"]型參數,函數里面會進行base64_decode的。 * return 驗簽是否通過,為BOOL值 */ public static function verify($data, $sign) { //讀取公鑰文件,也就是簽名方公開的公鑰,用來驗證這個data是否真的是簽名方發出的 $pubKey = file_get_contents('key/rsa_public_key.pem'); $res = openssl_get_publickey($pubKey); //調用openssl內置方法驗簽,返回bool值 $result = (bool)openssl_verify($data, base64_decode($sign), $res); openssl_free_key($res); return $result; }
