Создание ключа PHP RSA


У меня проблема с созданием/использованием ключей RSA, созданных и используемых в PHP. Проблема в том, что (открытые И закрытые) ключи должны обмениваться между разными серверами (например, при перемещении учетной записи пользователя).

Теперь openssl-библиотека PHP не предоставляет никакой подробной информации о том, в каком формате создаются ключи. Последняя документация по адресу http://php.net/manual/en/function.openssl-pkey-export.php просто заявляет, что это "в формате PEM", но не говорит, так ли это в PKCS#1 или PKCS#8

Кроме того, заголовки и трейлеры PEM закрытого ключа различаются в разных версиях PHP, как показано в следующем коде:

<?php
$config = array(
    "digest_alg" => 'sha512',
        "private_key_bits" => 4096,
    "private_key_type" => OPENSSL_KEYTYPE_RSA
);
$keyPair = openssl_pkey_new($config);
$privateKey = NULL;
openssl_pkey_export($keyPair, $privateKey);
var_dump($privateKey);
$keyDetails = openssl_pkey_get_details($keyPair);
$publicKey = $keyDetails['key'];
var_dump($publicKey);
die();
?>

Выведет другой материал:

PHP v 5.4:

string(3272) "-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqA//...
-----END PRIVATE KEY-----
"

string(800) "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAO//...
-----END PUBLIC KEY-----
"

PHP v 5.5:

string(3272) "-----BEGIN RSA PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqA//...
-----END RSA PRIVATE KEY-----
"

string(800) "-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAO//...
-----END PUBLIC KEY-----
"

PHP v 5.6:

string(3272) "-----BEGIN PRIVATE KEY----- 
MIIJQgIBADANBggsdisdVUCJDSQCjqgl2XqzR+bSv//...
-----END PRIVATE KEY-----
"

string(800) "-----BEGIN PUBLIC KEY----- 
MIICIjANBgkqhkiG9w0BsdvQEFAAOdfAg8AMIICFAgEAo6oJdl6s0fm0r7QlaN/U//...
-----END PUBLIC KEY----- 
"

Таким образом, заголовок/трейлер закрытого ключа изменяется в зависимости от используемой версии PHP. Это не было бы реальной проблемой, но, как выясняется, система, которая создавала бы заголовок ключа С "RSA", не будет возможность использовать пользовательский ключ БЕЗ "RSA", например, openssl_sign(): вы получите сообщение об ошибке, в котором говорится, что "предоставленный ключ не может быть преобразован в закрытый ключ"... И вот тут-то все и становится запутанным.

В соответствии с https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem , должно быть различие между форматами PEM с закрытым ключом с "RSA" в заголовке и без, являющимися PKCS#1 и PKCS#8, т.Е. с дополнительной информацией об алгоритме и т. Д. Или нет.

Я из-за этого я сталкиваюсь с серьезными проблемами. То же программное обеспечение, написанное для PHP5.6, не может работать на PHP5.5.On может использовать обходной путь, заменив заголовки 5.5 на совместимые с 5.6 вручную, но это будет просто "грязный взлом". Есть ли "хороший" способ справиться с этим?

При установке этот код замены попытается создать закрытый ключ, извлечь заголовок и "запомнить его". Затем будут проверены все ключи, используемые во время выполнения. Если найденные заголовки не будут соответствовать "локальному" одни, их нужно было бы обменять.

Но я предполагаю, что есть какая-то опция конфигурации (которую мне еще не удалось найти), где я могу настроить, какой формат используется?

Следующий, более интересный вопрос: Какой именно формат создается openssl? ПККС № 1? ПККС № 8? Это также настраивается?

Author: Xenonite, 2015-08-10

1 answers

Нет конфигурации (к сожалению). Просто проблема с версией PHP + OpenSSL. BEGIN RSA PRIVATE KEY указывает формат PKCS#1. Без RSA это PKCS#8.

Сгенерировать закрытый ключ RSA с помощью PKCS1 (мой более старый пост с той же проблемой)

В чем разница между "НАЧАТЬ ЗАКРЫТЫЙ КЛЮЧ RSA" и "НАЧАТЬ ЗАКРЫТЫЙ КЛЮЧ".

Вы можете попробовать библиотеку phpsec или вызвать openssl из командной строки (exec()). Я знаю, что это вам не поможет, но, похоже, нет хорошего решения пока.

Редактировать

Я немного изменил ваш тестовый сценарий и протестировал формат закрытого ключа в своей Windows 7.

<?php

$keyPair = openssl_pkey_new(array(
    "digest_alg" => 'sha512',
    "private_key_bits" => 4096,
    "private_key_type" => OPENSSL_KEYTYPE_RSA
));
$privateKey = null;

openssl_pkey_export($keyPair, $privateKey);

echo sprintf("PHP: %s\n", phpversion());
echo sprintf("OpenSSL: %s\n", OPENSSL_VERSION_TEXT);
echo sprintf("Private key header: %s\n", current(explode("\n", $privateKey)));

 

PHP: 5.4.44
OpenSSL: OpenSSL 0.9.8zf 19 Mar 2015
Private key header: -----BEGIN RSA PRIVATE KEY-----

PHP: 5.5.28
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----

PHP: 5.6.12
OpenSSL: OpenSSL 1.0.1p 9 Jul 2015
Private key header: -----BEGIN PRIVATE KEY-----

Эти результаты воспроизводят поведение openssl по умолчанию в соответствии с его списком изменений.

Изменения между 0.9.8n и 1.0.0 [29 марта 2010]

Сделайте PKCS#8 форматом записи по умолчанию для закрытых ключей, заменив традиционный формат. Эта форма стандартизирована, более безопасна и не включает неявная зависимость MD5. [Стив Хенсон]

 1
Author: kba, 2017-05-23 11:52:50