php - RSA:从 Python 中的 n 和 e 生成公钥,PHP 给我两个不同的公钥
问题描述
在 python 中,我从这样的公钥中提取模数 (n) 和 (e):
#! /usr/bin/python3.5
# -*- coding: utf-8 -*-
import rsa
(pubkey, privkey) = rsa.newkeys(512)
dec_n = pubkey.n
dec_e = pubkey.e
在base64中,n和e的值为:
n:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIGqijUcytyQLcEVxC5gK4HDx7Y_c5aMJt9OOoWDfzcrifmZr0-8Q1i_LPE-4fuBLlaPl6EmgSN2wlbF_svHZV
e:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB
我有以下公钥:
-----BEGIN RSA PUBLIC KEY-----
MEgCQQCIGqijUcytyQLcEVxC5gK4HDx7Y/c5aMJt9OOoWDfzcrifmZr0+8Q1i/LP
E+4fuBLlaPl6EmgSN2wlbF/svHZVAgMBAAE=
-----END RSA PUBLIC KEY-----
我试图在 PHP 中生成相同的公钥。为此,我阅读了这篇文章:openssl:我如何从模数中获取公钥
所以我写了这段代码:
require_once("/var/www/phpseclib/Crypt/RSA.php");
$n = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIGqijUcytyQLcEVxC5gK4HDx7Y_c5aMJt9OOoWDfzcrifmZr0-8Q1i_LPE-4fuBLlaPl6EmgSN2wlbF_svHZV";
$e = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB";
$rsa = new Crypt_RSA();
$modulus = new Math_BigInteger(base64_decode(urldecode($n)), 256);
$exponent = new Math_BigInteger(base64_decode(urldecode($e)), 256);
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setPublicKey();
$pub_key = $rsa->getPublicKey();
print_r($pub_key);
但我得到了这个公钥:
-----BEGIN PUBLIC KEY-----
MFgwDQYJKoZIhvcNAQEBBQADRwAwRAI9AIgaqKNRzK3JAtwRXELmArgcPHthzlowm3046hYN/NyuJ+ZmvTxDWIs8Th+4EuVo+XoSaBI3bCVsWy8dlQIDAQAB
-----END PUBLIC KEY-----
解决方案
差异是由两个因素造成的:首先,公钥在 Python 代码中以 PKCS1 格式([1]和[2])显示,在 PHP 代码中以 X.509 格式([ 1]和[3])。其次,Base64 编码中存在一个错误。
Base64 编码:在 Python 代码中使用了 Base64 url 编码,而在 PHP 代码中仅使用了标准 Base64 编码([4])。虽然没有贴出带有 Base64url 编码的代码,但这可以从字符中推断出来
-
并_
出现在编码数据中。要在 PHP 代码中使用 Base64url-decoding(而不是 Base64-decoding):$modulus = new Math_BigInteger(base64_decode(urldecode($n)), 256);
必须替换为:
$modulus = new Math_BigInteger(base64url_decode(urldecode($n)), 256);
与([5]):
function base64url_decode( $data ){ return base64_decode( strtr( $data, '-_', '+/') . str_repeat('=', 3 - ( 3 + strlen( $data )) % 4 )); }
指数也是类似的。
因此,PHP 代码返回以下公钥:
-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIgaqKNRzK3JAtwRXELmArgcPHtj9zlo wm3046hYN/NyuJ+ZmvT7xDWL8s8T7h+4EuVo+XoSaBI3bCVsX+y8dlUCAwEAAQ== -----END PUBLIC KEY-----
注意:模数和指数的 Base64url 解码是十六进制的:
modulus : 0000000000000000000000000000000000000000000000000000000000000000881aa8a351ccadc902dc115c42e602b81c3c7b63f73968c26df4e3a85837f372b89f999af4fbc4358bf2cf13ee1fb812e568f97a126812376c256c5fecbc7655 exponent: 000000000000000000000000000000000000000000010001
0
不需要填充许多- 值(除了符号字节),不包含任何信息,只会增加数据量。格式:上一步的公钥内容相同,只是格式不同(X.509)。显示这一点的最简单方法是使用 ( [6] )额外显示 PKCS1 格式的公钥:
$pub_key = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); print($pub_key . "\n");
PKCS1 格式的公钥与 Python 代码的密钥匹配。另一种可能性是在 ASN.1 编辑器中直接比较两个键,例如在线 ( [7] )。
顺便说一句:要在 PHP 代码中也使用 Python 代码的公钥,没有必要通过模数和指数绕道。使用 ( [6] ) 更容易:
$rsa = new Crypt_RSA(); $keydata = "-----BEGIN RSA PUBLIC KEY-----\n MEgCQQCIGqijUcytyQLcEVxC5gK4HDx7Y/c5aMJt9OOoWDfzcrifmZr0+8Q1i/LP E+4fuBLlaPl6EmgSN2wlbF/svHZVAgMBAAE= \n-----END RSA PUBLIC KEY-----"; $rsa->loadKey($keydata); $rsa->setPublicKey(); $pub_key = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); print($pub_key . "\n"); $pub_key = $rsa->getPublicKey(); print($pub_key . "\n");
推荐阅读
- haskell - 将斐波那契数列计算为固定点的复杂性
- javascript - 他们是否有任何直接银行到银行转账第三方 API 可用?
- c++ - 当应用程序最小化/隐藏时,是否可以在不将对话框置于前面的情况下进行 QProgressDialog::show?
- docusignapi - 我的系统和 Docusign 用户之间的用户映射
- angular - Jest 和 Serialize-ts Count 查找字段的类型:
- excel - 将文档添加到数据
- google-bigquery - BigQuery,如何按周末分组未开始
- xcode - dyld:找不到符号:__ZN3WTF19initializeThreadingEv - webkit MacOSX
- sql-server - 如何构建 Mulesoft-SqlServer 错误处理
- typescript - 带有可选成员的 Typescript 接口类型检查