Я пытался какое-то время создать пару ключей RSA с расширением openssl PHP и сохранить результат в качестве совместимой с OpenSSH ключевой пары – это означает, что закрытый ключ закодирован в PEM (что легко), а открытый ключ хранится в специальном формате OpenSSH следующего вида:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABA...more base64 encoded stuff...
Насколько я мог понять, этот формат состоит из:
Я попытался реализовать это с помощью функции pack () PHP, но независимо от того, что я пробую, результат не эквивалентен тому, что я получаю от использования команды ssh-keygen -y -f
в том же секретном ключе RSA, сгенерированном openssl.
Вот упрощенная версия моего кода:
<?php // generate private key $privKey = openssl_pkey_new(array( 'private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA )); // convert public key to OpenSSH format $keyInfo = openssl_pkey_get_details($privKey); $data = pack("Na*", 7, 'ssh-rsa'); $data .= pack("Na*", strlen($keyInfo['rsa']['e']), $keyInfo['rsa']['e']); $data .= pack("Na*", strlen($keyInfo['rsa']['n']), $keyInfo['rsa']['n']); $pubKey = "ssh-rsa " . base64_encode($data); echo "PHP generated RSA public key:\n$pubKey\n\n"; // For comparison, generate public key using ssh-keygen openssl_pkey_export($privKey, $pem); $umask = umask(0066); // this is needed for ssh-keygen to work properly file_put_contents('/tmp/ssh-keygen-test', $pem); umask($umask); exec('ssh-keygen -y -f /tmp/ssh-keygen-test', $out, $ret); $otherPubKey = $out[0]; echo "ssh-keygen generated RSA public key:\n$otherPubKey\n\n"; echo ($pubKey == $otherPubKey ? "yes! they are the same\n" : "FAIL! they are different\n"); ?>
Любые советы о том, как я могу это сделать, не полагаясь на ssh-keygen?
Хорошо, я только что решил свою проблему, более подробно рассмотрев ссылки на реализацию C из Convert pem key в формат ssh-rsa (что я делал раньше, но, видимо, я пропустил некоторые важные вещи). Мне нужно было И первый символ N и e с 0x80, и если он соответствует, добавьте еще один символ NULL в начале номера и увеличьте размер на 1 соответственно.
Я не уверен, почему это делается (я не нашел в этом ссылки никаких ссылок в онлайновом поиске), но он работает.
Я только сделал базовые тесты, но, похоже, он работает хорошо, и вот мой код:
<?php $privKey = openssl_pkey_get_private($rsaKey); $pubKey = sshEncodePublicKey($privKey); echo "PHP generated RSA public key:\n$pubKey\n\n"; function sshEncodePublicKey($privKey) { $keyInfo = openssl_pkey_get_details($privKey); $buffer = pack("N", 7) . "ssh-rsa" . sshEncodeBuffer($keyInfo['rsa']['e']) . sshEncodeBuffer($keyInfo['rsa']['n']); return "ssh-rsa " . base64_encode($buffer); } function sshEncodeBuffer($buffer) { $len = strlen($buffer); if (ord($buffer[0]) & 0x80) { $len++; $buffer = "\x00" . $buffer; } return pack("Na*", $len, $buffer); } ?>
Гораздо более простой метод, использующий phpseclib, реализацию RSA с чистым PHP :
<?php include('Crypt/RSA.php'); $rsa = new Crypt_RSA(); $rsa->loadKey('-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0 FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/ 3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB -----END PUBLIC KEY-----'); $rsa->setPublicKey(); $publickey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH); ?>
в<?php include('Crypt/RSA.php'); $rsa = new Crypt_RSA(); $rsa->loadKey('-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0 FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/ 3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB -----END PUBLIC KEY-----'); $rsa->setPublicKey(); $publickey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH); ?>
Вывод:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZw== phpseclib-generated-key
Источник:
http://phpseclib.sourceforge.net/rsa/examples.html#public,openssh