【发布时间】:2020-07-16 19:37:36
【问题描述】:
以下 PEM 格式的公共 RSA 密钥已提供给 openssl_pkey_get_public。
-----BEGIN PUBLIC KEY-----
MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQCIZouo/rL5IkIIGrke/qkY
Nsb9JDXUw2MfutYdwIVjPiEbAcLiVxK6tOVXy7dq+hU0zyNd68bUi7VJjXWoiepS
+Mm6v76GCGvVvno48m7ofWIq6VLEaMQjIM/pzkF0TW7CmtjKvgg722Hx87AI/KCM
sWuHjhcQZsMgV4ibC8EAY6GYwHYAPWfUq+LI2wfRsQHumFC2IuT4guO/Vs5FJGXw
Arrvv7VPyKwZ8cpcZn9ka1K0N7su7QiGnzOhS3n2THaj25alE6TMXnrKmt6yIiXh
amsKVEKPPzHpw9ldTao1aG7vVNC9QXC8i9uQTWhhokxvSNw5OYFFkDZC5jD7McvB
AgMBAAE=
-----END PUBLIC KEY-----
但是,方法调用失败,返回false,错误字符串error:0906D06C:PEM routines:PEM_read_bio:no start line
公钥无效吗?作为记录,我的代码从公钥模数和指数开始,并使用发布在here 的算法将其转换为 PEM 格式。
这是完整的脚本:
<?php
function createPemFromModulusAndExponent($n, $e)
{
$modulus = urlsafeB64Decode($n);
$publicExponent = urlsafeB64Decode($e);
$components = array(
'modulus' => pack('Ca*a*', 2, encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', 2, encodeLength(strlen($publicExponent)), $publicExponent)
);
$RSAPublicKey = pack('Ca*a*a*', 48, encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent']);
$rsaOID = pack('H*', '300d06092a864886f70d0101010500');
$RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
$RSAPublicKey = pack('Ca*a*', 48, encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----" . chunk_split(base64_encode($RSAPublicKey), 64) . '-----END PUBLIC KEY-----';
return $RSAPublicKey;
}
function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder)
{
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
function encodeLength($length)
{
if ($length <= 0x7F)
{
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
$key = createPemFromModulusAndExponent('iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ', 'AQAB');
print_r($key);
print_r(openssl_pkey_get_public($key));
print_r(openssl_error_string());
【问题讨论】:
-
已确认:1) 如果从证书中提取公钥,则不会显示错误消息。 2)错误信息不影响操作的结果(这至少适用于签名的验证)。
-
@Topaco:不根据文档。它可以准确读取 op 提供的密钥,事实上,这个例子对我来说在 PHP 7.4.4 中运行良好
-
@Topaco:啊,我明白了。是的,错误信息存在,你是对的。并且密钥可以用来加密。但是我发现了密钥的另一个问题:它 not 有效,因为模数是负数!我猜
openssl_pkey_get_public()只是忽略了负模数并将它们视为正数。这确实意味着生成 PEM 编码密钥的任何代码都是错误的。 -
我打开了一个issue 关于这个错误。
-
@PresidentJamesMoveonPolk - 是的,你是对的。一种可能的解决方法:由于
createPemFromModulusAndExponent期望模数为(Base64Url 编码的)十六进制字符串,它可以以已经正确的符号传递。然后将生成一个有效的密钥。当然,更好的方法是修复createPemFromModulusAndExponent。
标签: php openssl cryptography rsa