phpopenssl_sign参数,PHP版本兼容之openssl调⽤参数
背景与问题解决⽅式
⽼项⽬重构⽀付宝部分代码整合⽀付宝新的sdk时发现验签总是失败,才发现是open_verify最后的参数传输问题。⽽open_sign同样如此。本⽂主要说明open_verify的解决⽅式和代码解析。⽽问题的解决⽅式也是修改最后的加密类型参数,解决⽅式代码如下:
// 将最后的常量OPENSSL_ALGO_SHA256修改成字符串
openssl_verify($data, base64_decode($sign), $res, "sha256WithRSAEncryption");
复制代码
官⽅⽂档解释
上⾯只说了问题的出现与对应的解决⽅式,如果有兴趣继续了解该函数的,可以继续往下读,⾸先来看下官⽅⽂档对此函数的解释。
int openssl_verify ( string $data , string $signature , mixed $pub_key_id [, mixed $signature_alg = OPENSSL_ALGO_SHA1 ] )
复制代码
参数注释
data
以前⽤来⽣成签名的数据字符串。
signature
原始⼆进制字符串,通过openssl_sign()或类似的函数⽣成。
pub_key_id
resource - ⼀个密钥, 通过 openssl_get_publickey() 函数返回。
string - ⼀个 PEM 格式的密钥, ⽐如, "-----BEGIN PUBLIC "
signature_alg
int - 以下签名算法之⼀Signature Algorithms.
string - 由openssl_get_md_methods()函数返回的可⽤字符串,⽐如, "sha1WithRSAEncryption" 或者 "sha512".
官⽅⽂档给出的signature_alg参数可以为int或者string类型,int类型直接调⽤对应的枚举值,string则是openssl_get_md_methods函数返回的可⽤字符串,调⽤openssl_get_md_methods⽅法打印参数如下,⽽这些字符串也是对应加密⽅式的摘要信息,后⽂源码中可能会看的对函数调⽤稍微明⽩那么⼀丢丢。
Array
(
[0] => DSA
[1] => DSA-SHA
[2] => DSA-SHA1
[3] => DSA-SHA1-old
[4] => DSS1
[5] => GOST 28147-89 MAC
[6] => GOST R 34.11-94
[7] => MD4
[8] => MD5
[9] => MDC2
[10] => RIPEMD160
[11] => RSA-MD4
[12] => RSA-MD5
[13] => RSA-MDC2
[14] => RSA-RIPEMD160
[15] => RSA-SHA
[16] => RSA-SHA1
[17] => RSA-SHA1-2
[18] => RSA-SHA224
[19] => RSA-SHA256
[20] => RSA-SHA384
[21] => RSA-SHA512
[22] => SHA
[23] => SHA1
[24] => SHA224
[25] => SHA256
[26] => SHA384
[27] => SHA512
[28] => dsaEncryption
[29] => dsaWithSHA
[30] => dsaWithSHA1
[31] => dss1
[32] => ecdsa-with-SHA1
[33] => gost-mac
[34] => md4
[35] => md4WithRSAEncryption
[36] => md5
[37] => md5WithRSAEncryption
php手机版下载[38] => md_gost94
[39] => mdc2
[40] => mdc2WithRSA
[41] => ripemd
[42] => ripemd160
[43] => ripemd160WithRSA
[44] => rmd160
[45] => sha
[46] => sha1
[47] => sha1WithRSAEncryption
[48] => sha224
[49] => sha224WithRSAEncryption
[50] => sha256
[51] => sha256WithRSAEncryption
[52] => sha384
[53] => sha384WithRSAEncryption
[54] => sha512
[55] => sha512WithRSAEncryption
[56] => shaWithRSAEncryption
[57] => ssl2-md5
[58] => ssl3-md5
[59] => ssl3-sha1
[60] => whirlpool
)
复制代码
由此也可看出函数是兼容两种模式的,但是为什么php版本会有兼容问题么?在openssl库版本是⼀致的情况下,接下来的原因应该只遗留在php扩展的问题上。那下⾯来看看对应的源码去发现问题出现在哪吧。
函数源码
openssl_verify函数源码
openssl_verify源码中有这样⼀段,如果参数method为string类型的时候,调⽤openssl库的EVP_get_digestbyname⽅法,在⽹上查看了下此⽅法的作⽤,主要是根据摘要信息返回
EVP_MD结构,⽽EVP_get_digestbyname⽅法由于是openssl库源代码并且对C语⾔知之甚少,熊某就没去查看,
只是了解php代码调⽤背后的⼀些处理逻辑,有兴趣的可以看看openssl库的代码实现。
if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
if (method != NULL) {
signature_algo = Z_LVAL_P(method);
}
mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
} else if (Z_TYPE_P(method) == IS_STRING) {
mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
} else {
php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
RETURN_FALSE;
}
复制代码
原来是枚举值的问题?
⼀开始本⼈以为php5.3版本会是method参数类型的限制,⼀看源代码才发现,openssl_verify函数的实现逻辑是⼀致的,都是检测method参数类型,那么问题就不出现在参数类型上,然后我查看了参数为long类型是所调⽤的php_openssl_get_evp_md_from_algo函数,果然发现了问题所在。源码如下:
php5.3.27
static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
EVP_MD *mdtype;
switch (algo) {
case OPENSSL_ALGO_SHA1:
mdtype = (EVP_MD *) EVP_sha1();
break;
case OPENSSL_ALGO_MD5:
mdtype = (EVP_MD *) EVP_md5();
break;
case OPENSSL_ALGO_MD4:
mdtype = (EVP_MD *) EVP_md4();
break;
#ifdef HAVE_OPENSSL_MD2_H
case OPENSSL_ALGO_MD2:
mdtype = (EVP_MD *) EVP_md2();
break;
#endif
case OPENSSL_ALGO_DSS1:
mdtype = (EVP_MD *) EVP_dss1();
break;
default:
return NULL;
break;
}
return mdtype;
}
复制代码php7.1.18
static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */
EVP_MD *mdtype;
switch (algo) {
case OPENSSL_ALGO_SHA1:
mdtype = (EVP_MD *) EVP_sha1();
break;
case OPENSSL_ALGO_MD5:
mdtype = (EVP_MD *) EVP_md5();
break;
case OPENSSL_ALGO_MD4:
mdtype = (EVP_MD *) EVP_md4();
break;
#ifdef HAVE_OPENSSL_MD2_H
case OPENSSL_ALGO_MD2:
mdtype = (EVP_MD *) EVP_md2();
break;
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER) case OPENSSL_ALGO_DSS1:
mdtype = (EVP_MD *) EVP_dss1();
break;
#endif
case OPENSSL_ALGO_SHA224:
mdtype = (EVP_MD *) EVP_sha224();
break;
case OPENSSL_ALGO_SHA256:
mdtype = (EVP_MD *) EVP_sha256();
break;
case OPENSSL_ALGO_SHA384:
mdtype = (EVP_MD *) EVP_sha384();
break;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论