Ubah kunci pem ke format ssh-rsa

142

Saya memiliki sertifikat dalam derformat, darinya dengan perintah ini saya menghasilkan kunci publik:

openssl x509 -inform der -in ejbcacert.cer -noout -pubkey > pub1key.pub

Yang menghasilkan ini:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vbqajDw4o6gJy8UtmIbkcpnk
O3Kwc4qsEnSZp/TR+fQi62F79RHWmwKOtFmwteURgLbj7D/WGuNLGOfa/2vse3G2
eHnHl5CB8ruRX9fBl/KgwCVr2JaEuUm66bBQeP5XeBotdR4cvX38uPYivCDdPjJ1
QWPdspTBKcxeFbccDwIDAQAB
-----END PUBLIC KEY-----

Bagaimana saya bisa mendapatkan kunci publik seperti ini? Baik dari sertifikat atau dari kunci publik ini?

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC7vbqajDw4o6gJy8UtmIbkcpnkO3Kwc4qsEnSZp/TR+fQi62F79RHWmwKOtFmwteURgLbj7D/WGuNLGOfa/2vse3G2eHnHl5CB8ruRX9fBl/KgwCVr2JaEuUm66bBQeP5XeBotdR4cvX38uPYivCDdPjJ1QWPdspTBKcxeFbccDw==

Ini diperoleh dengan perintah ini:

ssh-keygen -y -f private_key1.pem > public_key1.pub
Adrya
sumber
14
Cara Anda memposting di "Ini diperoleh dengan perintah ini" bekerja untuk saya lebih baik daripada jawaban di bawah ini.
Yoav Shapira
7
@YoavShipra. Ya tapi seluruh pertanyaannya adalah dia ingin mengonversi menggunakan kunci publik saja. Mungkin dia tidak memiliki kunci pribadi dan dia hanya memiliki kunci publik dan ingin mengkonversi dari format PEM ke format ssh-rsa.
deltamind106
10
Diberi .pem dari AWS, perintah yang Anda berikan di atas ssh-keygen -y -f private_key1.pem > public_key1.pubbekerja dengan baik untuk saya.
Kzqai
1
Semua jawaban salah. Ini yang benar: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
3
Kecantikan ada di mata yang melihatnya . Kita perlu mencatat bahwa kunci pem dapat menyimpan kunci publik atau pribadi, atau keduanya; terenkripsi atau mungkin tidak; ditambah dengan berbagai format. Juga arti dari opsi -mberbeda untuk -i/ -e. Jadi teman-teman saya, pastikan Anda tahu apa yang Anda inginkan dan apa yang Anda miliki . :-)
ryenus

Jawaban:

129

Tidak perlu mengkompilasi barang. Anda dapat melakukan hal yang sama dengan ssh-keygen:

ssh-keygen -f pub1key.pub -i

akan membaca kunci publik dalam format openssl dari pub1key.pubdan mengeluarkannya dalam format OpenSSH.

Catatan : Dalam beberapa kasus, Anda perlu menentukan format input:

ssh-keygen -f pub1key.pub -i -mPKCS8

Dari dokumen ssh-keygen (Dari man ssh-keygen):

-m key_format Menentukan format kunci untuk opsi konversi -i (impor) atau -e (ekspor). Format kunci yang didukung adalah: "RFC4716" (kunci publik atau pribadi RFC 4716 / SSH2), "PKCS8" (kunci publik PEM PKCS8) atau "PEM" (kunci publik PEM). Format konversi default adalah "RFC4716".

Victor Mataré
sumber
3
ssh-keygen: opsi ilegal - m
mbonnin
1
Pertanyaannya sebaliknya.
131
4
Untuk pencari web di masa depan, jika ini tidak berhasil untuk Anda, komentar dalam pertanyaan awal berfungsi untuk saya.
kristopolous
17
Dalam kasus saya, -m PKCS8itu perlu
Ian Hunter
1
$ ssh-keygen -f mykey.pub -i key_from_blob: invalid format decode blob failed.
Bastian Voigt
53

Tidak perlu skrip atau 'trik' lain: openssldan ssh-keygensudah cukup. Saya mengasumsikan tidak ada kata sandi untuk kunci (yang buruk).

Buat pasangan RSA

Semua metode berikut memberikan pasangan kunci RSA dalam format yang sama

  1. Dengan openssl ( man genrsa )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    Dalam OpenSSL v1.0.1 genrsa digantikan oleh genpkeyjadi ini adalah cara baru untuk melakukannya ( man genpkey ):

    openssl genpkey -algorithm RSA -out dummy-genpkey.pem -pkeyopt rsa_keygen_bits:2048
    
  2. Dengan ssh-keygen

    ssh-keygen -t rsa -b 2048 -f dummy-ssh-keygen.pem -N '' -C "Test Key"
    

Mengubah DER menjadi PEM

Jika Anda memiliki pasangan kunci RSA dalam format DER, Anda mungkin ingin mengubahnya menjadi PEM untuk memungkinkan konversi format di bawah ini:

Generasi:

openssl genpkey -algorithm RSA -out genpkey-dummy.cer -outform DER -pkeyopt rsa_keygen_bits:2048

Konversi:

openssl rsa -inform DER -outform PEM -in genpkey-dummy.cer -out dummy-der2pem.pem

Ekstrak kunci publik dari pasangan RSA yang diformat PEM

  1. dalam format PEM:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. dalam format OpenSSH v2 lihat :

    ssh-keygen -y -f dummy-xxx.pem
    

Catatan

Versi OS dan perangkat lunak:

[user@test1 ~]# cat /etc/redhat-release ; uname -a ; openssl version
CentOS release 6.5 (Final)
Linux test1.example.local 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
OpenSSL 1.0.1e-fips 11 Feb 2013

Referensi:

Thomas
sumber
//, Apakah ini benar-benar menghasilkan kunci dalam ssh-rsaformat? Referensi yang bagus, btw.
Nathan Basanese
@NathanBasanese, ya (lihat "Ekstrak kunci publik dari pasangan RSA yang diformat PEM", poin 2): begitu seseorang memiliki sertifikat dalam format pem: ssh-keygen -y -f dummy-xxx.pemmenghasilkan ssh-rsa AAAA[...]==kecocokan untuk authorized_keysfile ssh .
Thomas
Bagian informatif yang bagus ... tapi saya rasa itu tidak menjawab pertanyaan dan juga bagian yang jauh lebih pendek.
Kode Ogre
23

Untuk menjawab pertanyaan saya sendiri, setelah memposting di milis openssl, dapatkan ini:

Berikut adalah kode C untuk mengkonversi dari kunci publik OpenSSL ke kunci publik OpenSSH. Anda dapat mengambil kode dari tautan ini dan mengompilasinya sendiri:

static unsigned char pSshHeader[11] = { 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61};

static int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char* pBuffer)
{
   int adjustedLen = bufferLen, index;
   if (*pBuffer & 0x80)
   {
      adjustedLen++;
      pEncoding[4] = 0;
      index = 5;
   }
   else
   {
      index = 4;
   }
   pEncoding[0] = (unsigned char) (adjustedLen >> 24);
   pEncoding[1] = (unsigned char) (adjustedLen >> 16);
   pEncoding[2] = (unsigned char) (adjustedLen >>  8);
   pEncoding[3] = (unsigned char) (adjustedLen      );
   memcpy(&pEncoding[index], pBuffer, bufferLen);
   return index + bufferLen;
}

int main(int argc, char**  argv)
{
   int iRet = 0;
   int nLen = 0, eLen = 0;
   int encodingLength = 0;
   int index = 0;
   unsigned char *nBytes = NULL, *eBytes = NULL;
   unsigned char* pEncoding = NULL;
   FILE* pFile = NULL;
   EVP_PKEY *pPubKey = NULL;
   RSA* pRsa = NULL;
   BIO *bio, *b64;

   ERR_load_crypto_strings(); 
   OpenSSL_add_all_algorithms();

   if (argc != 3)
   {
      printf("usage: %s public_key_file_name ssh_key_description\n", argv[0]);
      iRet = 1;
      goto error;
   }

   pFile = fopen(argv[1], "rt");
   if (!pFile)
   {
      printf("Failed to open the given file\n");
      iRet = 2;
      goto error;
   }

   pPubKey = PEM_read_PUBKEY(pFile, NULL, NULL, NULL);
   if (!pPubKey)
   {
      printf("Unable to decode public key from the given file: %s\n", ERR_error_string(ERR_get_error(), NULL));
      iRet = 3;
      goto error;
   }

   if (EVP_PKEY_type(pPubKey->type) != EVP_PKEY_RSA)
   {
      printf("Only RSA public keys are currently supported\n");
      iRet = 4;
      goto error;
   }

   pRsa = EVP_PKEY_get1_RSA(pPubKey);
   if (!pRsa)
   {
      printf("Failed to get RSA public key : %s\n", ERR_error_string(ERR_get_error(), NULL));
      iRet = 5;
      goto error;
   }

   // reading the modulus
   nLen = BN_num_bytes(pRsa->n);
   nBytes = (unsigned char*) malloc(nLen);
   BN_bn2bin(pRsa->n, nBytes);

   // reading the public exponent
   eLen = BN_num_bytes(pRsa->e);
   eBytes = (unsigned char*) malloc(eLen);
   BN_bn2bin(pRsa->e, eBytes);

   encodingLength = 11 + 4 + eLen + 4 + nLen;
   // correct depending on the MSB of e and N
   if (eBytes[0] & 0x80)
      encodingLength++;
   if (nBytes[0] & 0x80)
      encodingLength++;

   pEncoding = (unsigned char*) malloc(encodingLength);
   memcpy(pEncoding, pSshHeader, 11);

   index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
   index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);

   b64 = BIO_new(BIO_f_base64());
   BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
   bio = BIO_new_fp(stdout, BIO_NOCLOSE);
   BIO_printf(bio, "ssh-rsa ");
   bio = BIO_push(b64, bio);
   BIO_write(bio, pEncoding, encodingLength);
   BIO_flush(bio);
   bio = BIO_pop(b64);
   BIO_printf(bio, " %s\n", argv[2]);
   BIO_flush(bio);
   BIO_free_all(bio);
   BIO_free(b64);

error:
   if (pFile)
      fclose(pFile);
   if (pRsa)
      RSA_free(pRsa);
   if (pPubKey)
      EVP_PKEY_free(pPubKey);
   if (nBytes)
      free(nBytes);
   if (eBytes)
      free(eBytes);
   if (pEncoding)
      free(pEncoding);

   EVP_cleanup();
   ERR_free_strings();
   return iRet;
}
Adrya
sumber
2
Jika seseorang bertanya-tanya bagaimana cara mengkompilasi ini (saya dulu), inilah panggilan kompiler: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas Gohr
di mana tidak pada get argv [2] (ssh_key_description) dari ... Aku hanya punya ----- BEGIN RSA PUBLIC KEY ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END RSA PUBLIC KEY- --- itu tidak memiliki deskripsi
braden
@braden. Biasanya ini hanya alamat email pemilik kunci. Tetapi Anda dapat memasukkan apa pun yang Anda inginkan ke dalam deskripsi.
deltamind106
Implementasi php opensshtopem di sini github.com/131/yks/blob/master/class/stds/crypt.php#L346
131
Jawaban dari @mkalkov di bawah ini melakukan konversi menggunakan alat baris perintah Linux. Itu hanya perlu file pem kunci publik dengan header dihapus dan garis digabungkan sebagai input.
alexandroid
13
ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
sumber
3
Tidak berfungsi untuk saya: "do_convert_from_pkcs8: key.pem bukan format kunci publik yang dikenali". Apa yang berhasil adalah "ssh-keygen -y -f key.pem" yang mencetak teks ssh-rsa yang diperlukan untuk otor_keys.
Curt
1
Ini tidak berfungsido_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu
Bekerja untuk saya setelah openssl genrsa -out newkey.pem 2048danopenssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix
12
ssh-keygen -f private.pem -y > public.pub
zkilnbqi
sumber
6

Saya lakukan dengan

ssh-keygen -i -f $ sshkeysfile >> otor_keys

Kredit di sini

periklis
sumber
1
Mengapa Anda tidak memberikan pujian kepada Victor di atas? Dia memberimu perintah yang sama hampir 8 bulan sebelumnya.
jww
1
@jww Dari catatan edit jawaban Victor, Anda mungkin melihat bahwa awalnya jawabannya sedikit berbeda, saya menganggap inilah alasannya
periklis
4

Skrip berikut akan mendapatkan sertifikat kunci publik ci.jenkins-ci.org dalam format DER yang disandikan base64 dan mengubahnya menjadi file kunci publik OpenSSH. Kode ini mengasumsikan bahwa kunci RSA 2048-bit digunakan dan menarik banyak dari jawaban Ian Boyd ini . Saya telah menjelaskan sedikit lebih banyak tentang cara kerjanya di komentar pada artikel ini di Jenkins wiki.

echo -n "ssh-rsa " > jenkins.pub
curl -sfI https://ci.jenkins-ci.org/ | grep X-Instance-Identity | tr -d \\r | cut -d\  -f2 | base64 -d | dd bs=1 skip=32 count=257 status=none | xxd -p -c257 | sed s/^/00000007\ 7373682d727361\ 00000003\ 010001\ 00000101\ / | xxd -p -r | base64 -w0 >> jenkins.pub
echo >> jenkins.pub
mkalkov
sumber
OMG ini adalah jawaban terbaik! Dan itu berhasil! (Saya hanya perlu mengganti status = tidak ada dengan status = noxfer). Cukup gunakan perintah kedua dimulai dengan "base64" dan berikan file PEM pada input dengan header dilucuti dan semua baris digabungkan menjadi satu. @Mkalkov terima kasih!
alexandroid
Perhatikan bahwa perintah di atas menganggap kunci 2048-bit dan tidak akan berfungsi dengan benar jika diberikan kunci dengan ukuran yang berbeda.
alexandroid
1

FWIW, skrip BASH ini akan mengambil sertifikat X.509 format PEM-atau DER atau file kunci publik OpenSSL (juga format PEM) sebagai argumen pertama dan mencabut kunci publik OpenSSH RSA. Ini berkembang atas jawaban @ mkalkov di atas. Persyaratan adalah cat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl(1.0+), dan tentu saja bash. Semua kecuali openssl(berisi base64) dijamin cukup banyak untuk menjadi bagian dari instalasi dasar pada sistem Linux modern apa pun, kecuali mungkin xxd(yang ditunjukkan Fedora dalam vim-commonpaket). Jika ada yang ingin membersihkannya dan membuatnya lebih bagus, peringatan lector.

#!/bin/bash
#
# Extract a valid SSH format public key from an X509 public certificate.
#

# Variables:
pubFile=$1
fileType="no"
pkEightTypeFile="$pubFile"
tmpFile="/tmp/`uuidgen`-pkEightTypeFile.pk8"

# See if a file was passed:
[ ! -f "$pubFile" ] && echo "Error, bad or no input file $pubFile." && exit 1

# If it is a PEM format X.509 public cert, set $fileType appropriately:
pemCertType="X$(file $pubFile | grep 'PEM certificate')"
[ "$pemCertType" != "X" ] && fileType="PEM"

# If it is an OpenSSL PEM-format PKCS#8-style public key, set $fileType appropriately:
pkEightType="X$(grep -e '-BEGIN PUBLIC KEY-' $pubFile)"
[ "$pkEightType" != "X" ] && fileType="PKCS"

# If this is a file we can't recognise, try to decode a (binary) DER-format X.509 cert:
if [ "$fileType" = "no" ]; then
        openssl x509 -in $pubFile -inform DER -noout
        derResult=$(echo $?)
        [ "$derResult" = "0" ] && fileType="DER"
fi

# Exit if not detected as a file we can use:
[ "$fileType" = "no" ] && echo "Error, input file not of type X.509 public certificate or OpenSSL PKCS#8-style public key (not encrypted)." && exit 1

# Convert the X.509 public cert to an OpenSSL PEM-format PKCS#8-style public key:
if [ "$fileType" = "PEM" -o "$fileType" = "DER" ]; then
        openssl x509 -in $pubFile -inform $fileType -noout -pubkey > $tmpFile
        pkEightTypeFile="$tmpFile"
fi

# Build the string:
# Front matter:
frontString="$(echo -en 'ssh-rsa ')"

# Encoded modulus and exponent, with appropriate pointers:
encodedModulus="$(cat $pkEightTypeFile | grep -v -e "----" | tr -d '\n' | base64 -d | dd bs=1 skip=32 count=257 status=none | xxd -p -c257 | sed s/^/00000007\ 7373682d727361\ 00000003\ 010001\ 00000101\ / | xxd -p -r | base64 -w0 )"

# Add a comment string based on the filename, just to be nice:
commentString=" $(echo $pubFile | xargs basename | sed -e 's/\.crt\|\.cer\|\.pem\|\.pk8\|\.der//')"

# Give the user a string:
echo $frontString $encodedModulus $commentString

# cleanup:
rm -f $tmpFile
db_
sumber