PHP与openSSL - 提供的密钥参数不能被强制为私钥

问题描述:

我试图使用openssl_sign()函数签署文件。我有以下私钥: -----BEGIN EC PRIVATE KEY----- MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6 WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw== -----END EC PRIVATE KEY----- PHP与openSSL - 提供的密钥参数不能被强制为私钥

我正在使用以下函数:openssl_sign("test", $signature, $private_key, OPENSSL_ALGO_SHA256);

我有一台服务器可以使用给定的密钥进行签名,而另一台则不能。一个是PHP 5.6,另一个没有PHP 7.1。一台服务器怎么能够使用这个密钥而另一台却不能?

+0

https://stackoverflow.com/questions/21149200/supplied-key-param-cannot-be-coerced-into-a-private-key-with-google-apis – RamRaider

+0

出于安全考虑,我希望这不是你的您在此发布的实际私钥。如果是这样,我建议你立即更换它。 – Kaii

+0

啊不,这只是一些随机字节.. – user2298995

也许你需要使用openssl_get_privatekey创建私钥资源,而不是简单地使用字符串

$str_priv_key='-----BEGIN EC PRIVATE KEY----- 
MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK 
oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6 
WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw== 
-----END EC PRIVATE KEY-----'; 

$pkey=openssl_get_privatekey($str_priv_key); 
openssl_sign("test", $signature, $pkey); 
openssl_free_key($pkey); 

按照PHP manual私钥参数必须是一个资源

> priv_key_id 
> resource - a key, returned by openssl_get_privatekey() 
+0

感谢评论,似乎我得到了同样的错误。 'openssl_get_privatekey'没有什么区别:'PHP警告:openssl_sign():提供的密钥参数不能被强制转换为' – user2298995

+0

'中的私钥,这大概是问题中的私钥字符串不是完整的字符串?也许值得注意的是我有PHP 5.3.2 – RamRaider

+0

它应该是,因为它可以在不同的服务器上工作,并且在使用OpenSSL使用命令行进行签名时它可以工作:'openssl dgst -sha256 -hex -sign key.pem hash.txt' – user2298995

第一你应该检查是否启用了OpenSSL。您可以通过输出

phpinfo();

并检查:“启用了OpenSSL支持”。在这种情况下,它是。

为了进一步解决有两个功能,帮助很大:

error_get_last() 
Usage: print_r(error_get_last()); 

openssl_error_string() 
Usage: echo openssl_error_string(); 

在这种情况下, “error_get_last()” 返回:

openssl_sign(): supplied key param cannot be coerced into a private key

和返回的“openssl_error_string()”:

error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group

此消息表示使用的OpenSSL版本没有代码来处理使用的EC曲线。 “EC_GROUP_new_by_curve_name”搜索“静态常量ec_list_element curve_list []”并且没有找到。结果它返回“未知”。

现在你有3种选择:

  • 升级你的OpenSSL支持这种曲线。
  • 选择两台服务器都支持的另一条曲线。
  • 使用非EC加密。

由于PHP 7.1.0的你可以使用:

openssl_get_curve_names() 

获得支持的曲线列表。我不了解PHP 5.6的类似功能,因此您可能需要尝试一些才能获得两台主机上都可用的功能。

作为便笺: 某些Linux发行版(如RedHat和CentOS)使用比其他版本更严格的OpenSSL版本。错误表明在这种情况下,OpenSSL是在旧的(5.8)CentOS版本上手动更新的。网上有一些手册(如https://syslint.com/blog/tutorial/how-to-upgrade-openssl-on-centos-7-or-rhel-7/),它只升级OpenSSL可执行文件。如果使用了这种技术或类似的技术,PHP仍然会使用'旧'OpenSSL,因此,从命令行运行OpenSSL会产生与PHP调用不同的结果。

+0

同样的错误是我得到的:'openssl_sign():提供的键参数不能强制成私钥“ – user2298995

+0

尝试了第二条评论。收到:'错误:100AE081:椭圆曲线例程:EC_GROUP_new_by_curve_name:未知组' – user2298995

+0

工作的服务器:PHP 5.6,OpenSSL:1.0.1f 2014年1月6日;不支持的服务器:PHP 7.1,OpenSSL:1.0.2n 2017年12月7日(最新版)。 – user2298995