У меня возникла проблема с созданием / использованием ключей RSA, созданных и используемых в PHP. Проблема в том, что (публичные и частные) ключи должны быть обменены между разными серверами (например, когда перемещается учетная запись пользователя).
Теперь, opensl-lib из 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? PKCS # 1? PKCS # 8? Это также настраивается?
Нет конфигурации (к сожалению). Просто версия PHP + OpenSSL. BEGIN RSA PRIVATE KEY
указывает формат PKCS # 1. Без RSA
это PKCS # 8.
Создайте RSA с открытым ключом с помощью PKCS1 (моя старая почта с той же проблемой)
каковы различия между «НАЧАТЬ КВАДРАТ RSA» и «НАЧАТЬ ЧАСТНЫЙ КЛЮЧ» .
Вы можете попробовать библиотеку phpsec или вызвать openssl из командной строки ( exec()
). Я знаю, что это вам не поможет, но, похоже, пока нет хорошего решения.
редактировать
Я немного изменил ваш тестовый сценарий и протестировал формат закрытого ключа на своих окнах 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.8 и 1.0.0 [29.03.2010]
Сделайте PKCS # 8 стандартным форматом записи для закрытых ключей, заменив традиционный формат. Эта форма стандартизирована, более безопасна и не включает неявную зависимость MD5. [Стив Хенсон]