RSA:从 Python 和 PHP 中的 n 和 e 生成 public 密钥给我两个不同的 public 密钥
RSA: generate public key from n and e in Python and PHP give me two different public key
在 python 中,我从 public 键中提取模数 (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
我有以下 public 密钥:
-----BEGIN RSA PUBLIC KEY-----
MEgCQQCIGqijUcytyQLcEVxC5gK4HDx7Y/c5aMJt9OOoWDfzcrifmZr0+8Q1i/LP
E+4fuBLlaPl6EmgSN2wlbF/svHZVAgMBAAE=
-----END RSA PUBLIC KEY-----
我试图在 PHP 中生成相同的 public 密钥。为此,我阅读了这篇 post:openssl: how can i get public key from modulus
所以我写了这段代码:
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);
但我得到了这个 public 密钥:
-----BEGIN PUBLIC KEY-----
MFgwDQYJKoZIhvcNAQEBBQADRwAwRAI9AIgaqKNRzK3JAtwRXELmArgcPHthzlowm3046hYN/NyuJ+ZmvTxDWIs8Th+4EuVo+XoSaBI3bCVsWy8dlQIDAQAB
-----END PUBLIC KEY-----
差异是由两个因素造成的:首先,public键显示在PKCS1格式([1] and [2]), and in the PHP-code in the X.509-format ([1] and [3])的Python代码中。其次,Base64编码有一个bug。
Base64 编码:在 Python 编码中使用了 Base64url 编码,在 PHP-code 仅标准 Base64 编码 ([4])。虽然没有贴出Base64url编码的代码,但是从编码数据中出现的字符-
和_
可以得出结论。要在 PHP 代码中使用 Base64url 解码(而不是 Base64 解码):
$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-代码因此 returns 以下 public 键:
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIgaqKNRzK3JAtwRXELmArgcPHtj9zlo
wm3046hYN/NyuJ+ZmvT7xDWL8s8T7h+4EuVo+XoSaBI3bCVsX+y8dlUCAwEAAQ==
-----END PUBLIC KEY-----
注:模数和指数的Base64url-解码为十六进制:
modulus : 0000000000000000000000000000000000000000000000000000000000000000881aa8a351ccadc902dc115c42e602b81c3c7b63f73968c26df4e3a85837f372b89f999af4fbc4358bf2cf13ee1fb812e568f97a126812376c256c5fecbc7655
exponent: 000000000000000000000000000000000000000000010001
没有必要使用许多 0
值进行填充(符号字节除外),不包含任何信息,只会增加数据量。
格式:上一步的public密钥内容相同,只是格式不同(X.509)。显示这一点的最简单方法是使用 ([6]):
在 PKCS1 格式中额外显示 public 密钥
$pub_key = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
print($pub_key . "\n");
PKCS1 格式的 public 密钥与 Python 代码的密钥匹配。另一种可能性是在 ASN.1 编辑器中直接比较两个键,例如在线 ([7]).
顺便说一下: 要在 PHP 中使用 Python 代码的 public 键-代码,没有必要通过模数和指数绕道。使用 ([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");
在 python 中,我从 public 键中提取模数 (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
我有以下 public 密钥:
-----BEGIN RSA PUBLIC KEY-----
MEgCQQCIGqijUcytyQLcEVxC5gK4HDx7Y/c5aMJt9OOoWDfzcrifmZr0+8Q1i/LP
E+4fuBLlaPl6EmgSN2wlbF/svHZVAgMBAAE=
-----END RSA PUBLIC KEY-----
我试图在 PHP 中生成相同的 public 密钥。为此,我阅读了这篇 post:openssl: how can i get public key from modulus
所以我写了这段代码:
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);
但我得到了这个 public 密钥:
-----BEGIN PUBLIC KEY-----
MFgwDQYJKoZIhvcNAQEBBQADRwAwRAI9AIgaqKNRzK3JAtwRXELmArgcPHthzlowm3046hYN/NyuJ+ZmvTxDWIs8Th+4EuVo+XoSaBI3bCVsWy8dlQIDAQAB
-----END PUBLIC KEY-----
差异是由两个因素造成的:首先,public键显示在PKCS1格式([1] and [2]), and in the PHP-code in the X.509-format ([1] and [3])的Python代码中。其次,Base64编码有一个bug。
Base64 编码:在 Python 编码中使用了 Base64url 编码,在 PHP-code 仅标准 Base64 编码 ([4])。虽然没有贴出Base64url编码的代码,但是从编码数据中出现的字符
-
和_
可以得出结论。要在 PHP 代码中使用 Base64url 解码(而不是 Base64 解码):$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-代码因此 returns 以下 public 键:
-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIgaqKNRzK3JAtwRXELmArgcPHtj9zlo wm3046hYN/NyuJ+ZmvT7xDWL8s8T7h+4EuVo+XoSaBI3bCVsX+y8dlUCAwEAAQ== -----END PUBLIC KEY-----
注:模数和指数的Base64url-解码为十六进制:
modulus : 0000000000000000000000000000000000000000000000000000000000000000881aa8a351ccadc902dc115c42e602b81c3c7b63f73968c26df4e3a85837f372b89f999af4fbc4358bf2cf13ee1fb812e568f97a126812376c256c5fecbc7655 exponent: 000000000000000000000000000000000000000000010001
没有必要使用许多
0
值进行填充(符号字节除外),不包含任何信息,只会增加数据量。格式:上一步的public密钥内容相同,只是格式不同(X.509)。显示这一点的最简单方法是使用 ([6]):
在 PKCS1 格式中额外显示 public 密钥$pub_key = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); print($pub_key . "\n");
PKCS1 格式的 public 密钥与 Python 代码的密钥匹配。另一种可能性是在 ASN.1 编辑器中直接比较两个键,例如在线 ([7]).
顺便说一下: 要在 PHP 中使用 Python 代码的 public 键-代码,没有必要通过模数和指数绕道。使用 ([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");