【问题标题】:RSA: generate public key from n and e in Python and PHP give me two different public keyRSA:从 Python 中的 n 和 e 生成公钥,PHP 给我两个不同的公钥
【发布时间】:2019-10-25 05:45:46
【问题描述】:

在 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: 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);

但是我得到了这个公钥:

-----BEGIN PUBLIC KEY-----
MFgwDQYJKoZIhvcNAQEBBQADRwAwRAI9AIgaqKNRzK3JAtwRXELmArgcPHthzlowm3046hYN/NyuJ+ZmvTxDWIs8Th+4EuVo+XoSaBI3bCVsWy8dlQIDAQAB
-----END PUBLIC KEY-----

【问题讨论】:

    标签: php python rsa phpseclib


    【解决方案1】:

    差异是由两个因素造成的:首先,公钥以PKCS1格式([1]和[2])的Python代码显示,以及X.509-的PHP代码显示。格式([1] 和 [3])。其次,Base64编码有一个bug。

    • Base64 编码:在 Python 代码中使用了 Base64url 编码,而在 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");
      

    【讨论】:

      猜你喜欢
      • 2017-07-19
      • 2013-09-25
      • 2019-08-15
      • 1970-01-01
      • 2017-09-24
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      相关资源
      最近更新 更多