问题描述
因对接第三方支付渠道接口,对方仅提供了java版本demo,未提供php版本,故只能根据java版本转成php,
一开始看到对方提供的代码一脸懵逼⊙﹏⊙‖∣
先看java版本核心代码
//签名
public String sign(String content, String privateKey) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature
.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes());
byte[] signed = signature.sign();
return Base64.encode(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//校验
public boolean doCheck(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decode(publicKey);
PublicKey pubKey = keyFactory
.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature
.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes());
boolean bverify = signature.verify(Base64.decode(sign));
return bverify;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
看到RSA、SHA1WithRSA、Base64、PKCS8EncodedKeySpec、X509EncodedKeySpec这些名词后,内心是沮丧的,直接翻译是行不通的,只能祭出Google大杀器来。
经过几个关键词组合尝试后,终于在gist上找到眉目,直达连接 事例代码用的bin2hex、hex2bin,我们直接替换为base64_encode、base64_decode试试看,竟然一次通过,和java版本的加密解密结果是一致的
解决方案
生成ssl证书
openssl genrsa -out key.pem 1024 openssl rsa -in key.pem -pubout -outform PEM -out pubkey.pem openssl rsa -in key.pem -pubout -outform DER -out pubkey.der
代码实现
//签名 function buildSign($content) { $signature = null; $pri_key = file_get_contents('key.pem'); $pri_key_id = openssl_get_privatekey($pri_key); openssl_sign($content, $signature, $pri_key_id); openssl_free_key($pri_key_id); return base64_encode($signature); } //校验 function verifySign($sign, $toSign) { $signed_data = base64_decode($sign); $pub_key = file_get_contents('pubkey.pem'); $pub_key_id = openssl_get_publickey($pub_key); $ret = openssl_verify($toSign, $signed_data, $pub_key_id); return $ret; }
openssl_sign和openssl_verify默认算法都是SHA1,如果是其他请在第4个参数中传入,请参考如下
define ('OPENSSL_ALGO_SHA1', 1);
define ('OPENSSL_ALGO_MD5', 2);
define ('OPENSSL_ALGO_MD4', 3);
define ('OPENSSL_ALGO_MD2', 4);
define ('OPENSSL_ALGO_DSS1', 5);
define ('OPENSSL_ALGO_SHA224', 6);
define ('OPENSSL_ALGO_SHA256', 7);
define ('OPENSSL_ALGO_SHA384', 8);
define ('OPENSSL_ALGO_SHA512', 9);
define ('OPENSSL_ALGO_RMD160', 10);