使用 RSA 2048 公钥验证 RSA PKCS#1v1.5 SHA 256 签名

问题描述 投票:0回答:1

我有一个公钥作为字符串存储在数据库中。生成库说它是一个 RSA 2048 公钥。这是存储公钥的示例:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHPAou1FpNAoLwF/mL0rei8QcC+LvKIYteEHOpxGibI6PNQ8kSpB7WNPJT2wM+B0+DT04L5LBi78PSo1UQO3umYEhHbAsKuNBV3CR8NGfUsWzSkgIzkbTCsELWkJT50foBT4YmBKEe6W8Ai2+3yzvMtic8RtBel73zS3dIdUUGaf7SMPtva+XDZTozRNiyligPh0nDgHcj6OQAtCxfTogLKukwaEPyWA06nQ68pMsxzzHqUZl5HJuDJRphAtOc2ZRFXZ1xaxVMO2D7UnkFA5q00UBW/i+KzkhgtNkLI8j2jiBim3IozRwpjQJvFsKoi29WDWPXcgtTU6k9kSmJBIqQIDAQAB

我有一个由同一个库生成的数据字符串和签名。根据文档,签名是 RSA PKCS#1v1.5 SHA 256 签名。

数据串:

{"username":"[email protected]","requestTime":"1679669234"}

签名:

PiXcXFykgtOZY+tpmmXqt39VHwURd5NSIGL0U+TEj+qS6QwIT4Eh4W3fKYfIXwZGDu6Rdsu2PQxqBMhEQe7H7C0nq6ssih74MLavxpLuGPxmlZJ/EN2/m2fhLweerjS6U1uMIDcKE6cZgSD6z+KfkuWnKssM5yuMEkdztL5ef0Ay6Il0jXGayp+tLMGxGZaJLv31PRmYoK3c68buGphKV0hnj2y6+rKsoPfn+sVDxInH40oNcxF2zU+Y3ed9pW+/VOpnkTE9MoSNthNvwjNpRFJr4Awx7mKmOGe3dvC3yZ+iZ/lT892pTSwqo1O2mtXskbsUe1+xEfrzbi1/0ejy/g==

我一直在尝试使用

openssl_verify
来验证这个签名,但是还没有能够使用
openssl_pkey_get_public
成功解析公钥。我尝试了以下变化:

$publickey = "-----BEGIN RSA PUBLIC KEY-----\n".$publickey."\n-----END RSA PUBLIC KEY-----";
$pkey = openssl_pkey_get_public($publickey);

我已经尝试了

-----BEGIN RSA PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
的变体,尽管我相信 RSA 版本是正确的。我也尝试过使用
chunk_split($publickey, 64, "\n")
在传递给
openssl_pkey_get_public
之前拆分线。

每次尝试后,

openssl_error_string()
返回以下内容:

error:0909006C:PEM routines:get_name:no start line

我不明白为什么会这样。谁能帮我验证这个签名?

虽然我宁愿避免额外的 PHP 库,但如果我必须安装 PHP 库,例如 phpseclib,我会安装。

php rsa php-7.1 php-openssl
1个回答
1
投票

这就是所谓的 SPKI(主题公钥标识符)。这是 PEM 标题行中没有 RSA 的那个,即只是 PUBLIC KEY。

也许问题是 PEM 的结构不正确。

你可以例如尝试以下操作:

$publickey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHPAou1FpNAoLwF/mL0rei8QcC+LvKIYteEHOpxGibI6PNQ8kSpB7WNPJT2wM+
B0+DT04L5LBi78PSo1UQO3umYEhHbAsKuNBV3CR8NGfUsWzSkgIzkbTCsELWkJT50foBT4YmBKEe6W8Ai2+3yzvMtic8RtBel73zS3dIdUUGaf7SMPtva+XD
ZTozRNiyligPh0nDgHcj6OQAtCxfTogLKukwaEPyWA06nQ68pMsxzzHqUZl5HJuDJRphAtOc2ZRFXZ1xaxVMO2D7UnkFA5q00UBW/i+KzkhgtNkLI8j2jiBi
m3IozRwpjQJvFsKoi29WDWPXcgtTU6k9kSmJBIqQIDAQAB";
preg_replace("(.{64})", "\1\r\n", $publickey);
$publickey = "-----BEGIN PUBLIC KEY-----\r\n".$publickey."\r\n-----END PUBLIC KEY-----";
$pkey = openssl_pkey_get_public($publickey);

请注意,PEM 文件确实需要 base64,但官方规定它们的行数限制恰好为 64 个字符。较旧的解析器可能需要使用 CR/LF 而不仅仅是 LF,因此字符串中的

\r\n


因为你很好,所以签名验证:

$data = '{"username":"[email protected]","requestTime":"1679669234"}';
$sig = "PiXcXFykgtOZY+tpmmXqt39VHwURd5NSIGL0U+TEj+qS6QwIT4Eh4W3fKYfIXwZGDu6Rdsu2PQxqBMhEQe7H7C0nq6ssih74MLavxpLuGPxmlZJ/EN2/m2fhLweerjS6U1uMIDcKE6cZgSD6z+KfkuWnKssM5yuMEkdztL5ef0Ay6Il0jXGayp+tLMGxGZaJLv31PRmYoK3c68buGphKV0hnj2y6+rKsoPfn+sVDxInH40oNcxF2zU+Y3ed9pW+/VOpnkTE9MoSNthNvwjNpRFJr4Awx7mKmOGe3dvC3yZ+iZ/lT892pTSwqo1O2mtXskbsUe1+xEfrzbi1/0ejy/g==";
$res = openssl_verify($data, base64_decode($sig), $pkey, OPENSSL_ALGO_SHA256);
© www.soinside.com 2019 - 2024. All rights reserved.