RSA: сгенерируйте открытый ключ из n и e в Python и PHP, дайте мне два разных открытых ключа - PullRequest
1 голос
/ 25 октября 2019

В 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-----

1 Ответ

3 голосов
/ 25 октября 2019

Разница вызвана двумя факторами: во-первых, открытый ключ отображается в Python-коде в формате PKCS1 ( [1] и [2] ),и в PHP-коде в формате X.509 ( [1] и [3] ). Во-вторых, есть ошибка в кодировке Base64.

  • Кодировка Base64: В коде Python использовалось кодирование Base64 url и в PHP-кодировать только стандартную кодировку Base64 ( [4] ). Хотя код с Base64url-кодировкой не опубликован, это можно сделать из символов - и _, присутствующих в закодированных данных. Чтобы использовать Base64url-декодирование (вместо Base64-декодирования) в PHP-коде:

    $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). Самый простой способ показать это - дополнительно отобразить открытый ключ в формате PKCS1 с помощью ( [6] ):

    $pub_key = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
    print($pub_key . "\n");
    

    Открытый ключ в формате PKCS1 соответствуетключ Python-кода. Другая возможность - это прямое сравнение обоих ключей в редакторе ASN.1, например, в режиме онлайн ( [7] ).

  • Кстати: Чтобы использовать открытый ключ Python-кода также в PHP-коде, нет необходимости обходить его через модуль и экспоненту. Это гораздо проще сделать с помощью ( [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");
    
...