2011-04-02 99 views
7

我一直在嘗試使用PHP的openssl擴展生成RSA密鑰對,並將結果保存爲OpenSSH兼容密鑰對 - 意味着私鑰是PEM編碼(很簡單)和公共密鑰存儲在以下形式的OpenSSH的特定格式:將OpenSSL生成的RSA公鑰轉換爲OpenSSH格式(PHP)

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABA...more base64 encoded stuff... 

至於我可以收集這些格式包括:

  • 關鍵型清晰文字,後面跟空格(即「openssh-rsa」)
  • 表示以下數據A base64編碼串:(在此情況下7)編碼爲32比特的無符號長大端
  • 算法名稱,在這種情況下「
    • 算法名稱的字節長度SSH- RSA E」
    • 的RSA的長度‘’中的字節數,被編碼爲32位無符號長大端
    • 的RSA‘e’的數量
    • 的RSA的長度‘N’數以字節爲單位的編碼作爲32位無符號長大端編號
    • RSA'n'編號

我嘗試實施這一使用PHP的包()函數,但無論我怎麼努力的結果絕不會是相當於什麼,我從使用上所產生的同RSA私鑰的ssh-keygen -y -f命令得到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-凱基?

回答

9

好的,我剛剛通過仔細看看Convert pem key to ssh-rsa format(之前做過但顯然我錯過了一些重要的東西)的C實現參考來解決了我自己的問題。我需要AND與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); 
} 
?> 
+0

請注意'sshEncodeBuffer'需要字節長度。如果你有'mbstring。func_overload'設置爲重載字符串函數,用'mb_strlen($ buffer,'8bit')替換'strlen($ buffer)';' – bishop 2016-02-17 16:02:29

+0

@shevron它完美適用於RSA密鑰。但它不適用於DSA密鑰。我如何轉換DSA公鑰? – Harikrishnan 2016-06-03 04:42:54

1

很多簡單的方法,使用phpseclib, a pure-PHP RSA implementation

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

相關問題