Konvertieren Sie den PEM-Schlüssel in das ssh-rsa-Format


142

Ich habe ein Zertifikat im derFormat, aus dem ich mit diesem Befehl einen öffentlichen Schlüssel generiere:

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

Was dazu führt:

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

Wie kann ich einen solchen öffentlichen Schlüssel erhalten? Entweder vom Zertifikat oder von diesem öffentlichen Schlüssel?

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

Dies wurde mit diesem Befehl erhalten:

ssh-keygen -y -f private_key1.pem > public_key1.pub

14
Die Art und Weise, wie Sie in "Dies wurde mit diesem Befehl erhalten" gepostet haben, hat für mich besser funktioniert als jede der folgenden Antworten.
Yoav Shapira

7
@ YoavShipra. Ja, aber die ganze Frage ist, dass er nur mit dem öffentlichen Schlüssel konvertieren möchte. Vielleicht hat er nicht den privaten Schlüssel und er hat nur den öffentlichen Schlüssel und möchte vom PEM-Format in das ssh-rsa-Format konvertieren.
Deltamind106

10
Angesichts eines .pem von AWS hat der Befehl, den Sie oben gegeben haben, ssh-keygen -y -f private_key1.pem > public_key1.pubfür mich hervorragend funktioniert.
Kzqai

1
Alle falschen Antworten. Dies ist die richtige: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe

3
Schönheit liegt im Auge des Betrachters . Wir müssen beachten, dass ein PEM- Schlüssel entweder einen öffentlichen oder einen privaten Schlüssel oder beides enthalten kann. verschlüsselt oder vielleicht auch nicht; Plus mit verschiedenen Formaten. Auch die Bedeutung der Option -mist für -i/ unterschiedlich -e. Also meine Freunde, bitte stellen Sie sicher, dass Sie wissen, was Sie wollen und was Sie haben . :-)
Ryenus

Antworten:


129

Keine Notwendigkeit, Sachen zu kompilieren. Sie können dasselbe tun mit ssh-keygen:

ssh-keygen -f pub1key.pub -i

liest den öffentlichen Schlüssel im openssl-Format aus pub1key.pubund gibt ihn im OpenSSH-Format aus.

Hinweis : In einigen Fällen müssen Sie das Eingabeformat angeben:

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

Aus den ssh-keygen-Dokumenten (From man ssh-keygen):

-m Schlüsselformat Geben Sie ein Schlüsselformat für die Konvertierungsoptionen -i (Import) oder -e (Export) an. Die unterstützten Schlüsselformate sind: "RFC4716" (öffentlicher oder privater RFC 4716 / SSH2-Schlüssel), "PKCS8" (öffentlicher PEM PKCS8-Schlüssel) oder "PEM" (öffentlicher PEM-Schlüssel). Das Standardkonvertierungsformat ist "RFC4716".


3
ssh-keygen: illegale Option - m
mbonnin

1
Die Frage geht in die andere Richtung.
131

4
Wenn dies für zukünftige Websucher bei Ihnen nicht funktioniert, haben die Kommentare in der ursprünglichen Frage für mich funktioniert.
kristopolous

17
In meinem Fall war das -m PKCS8notwendig
Ian Hunter

1
$ ssh-keygen -f mykey.pub -i key_from_blob: invalid format decode blob failed.
Bastian Voigt

53

Keine Notwendigkeit für Skripte oder andere "Tricks": opensslund ssh-keygensind genug. Ich gehe von keinem Passwort für die Schlüssel aus (was schlecht ist).

Generieren Sie ein RSA-Paar

Alle folgenden Methoden geben ein RSA-Schlüsselpaar im gleichen Format an

  1. Mit openssl ( man genrsa )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    In OpenSSL v1.0.1 genrsa wird ersetzt durch genpkeyso ist dies der neue Weg , um es (zu tun , Mann genpkey ):

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

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

DER in PEM konvertieren

Wenn Sie ein RSA-Schlüsselpaar im DER-Format haben, möchten Sie es möglicherweise in PEM konvertieren, um die folgende Formatkonvertierung zu ermöglichen:

Generation:

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

Umwandlung:

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

Extrahieren Sie den öffentlichen Schlüssel aus dem PEM-formatierten RSA-Paar

  1. im PEM-Format:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. im OpenSSH v2-Format siehe :

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

Anmerkungen

Betriebssystem- und Softwareversion:

[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

Verweise:


//, Erzeugt dies tatsächlich einen Schlüssel im ssh-rsaFormat? Gute Referenz übrigens.
Nathan Basanese

@ NathanBasanese, ja (siehe "Extrahieren des öffentlichen Schlüssels aus dem PEM-formatierten RSA-Paar", Punkt 2): Sobald das Zertifikat im PEM-Format vorliegt, ssh-keygen -y -f dummy-xxx.pemwird eine ssh-rsa AAAA[...]==Anpassung für die authorized_keysDatei von ssh erstellt.
Thomas

Gutes informatives Stück ... aber ich denke nicht, dass es die Frage so gut beantwortet wie das oben genannte viel kürzere Stück.
Oger-Codes

23

Um meine eigene Frage zu beantworten, habe ich nach dem Posten auf der openssl Mailingliste Folgendes erhalten:

Hier ist C-Code zum Konvertieren von einem öffentlichen OpenSSL-Schlüssel in einen öffentlichen OpenSSH-Schlüssel. Sie können den Code über diesen Link abrufen und selbst kompilieren:

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;
}

2
Falls sich jemand fragt, wie man das kompiliert (ich war es), hier ist der Compiler-Aufruf: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas Gohr

wo kommt auf get argv [2] (ssh_key_description) aus ... Ich habe nur ein ----- BEGIN RSA PUBLIC KEY ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END RSA PUBLIC KEY-- --- es hat keine Beschreibung
Braden

@ Braden. Normalerweise ist es nur die E-Mail-Adresse des Besitzers des Schlüssels. Aber Sie können alles, was Sie wollen, in die Beschreibung einfügen.
Deltamind106

Eine PHP-Implementierung öffnetshtopem hier github.com/131/yks/blob/master/class/stds/crypt.php#L346
131

Die Antwort von @mkalkov unten führt die Konvertierung mit Linux-Befehlszeilentools durch. Es wird lediglich eine PEM-Datei mit öffentlichem Schlüssel benötigt, in der die Überschriften entfernt und die Zeilen als Eingabe zusammengeführt werden.
Alexandroid

13
ssh-keygen -i -m PKCS8 -f public-key.pem

3
Hat bei mir nicht funktioniert: "do_convert_from_pkcs8: key.pem ist kein anerkanntes öffentliches Schlüsselformat". Was funktionierte, war "ssh-keygen -y -f key.pem", das den ssh-rsa-Text druckt, der für autorisierte Schlüssel benötigt wird.
Curt

1
Dies funktioniert nichtdo_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu

Arbeitete für mich nach openssl genrsa -out newkey.pem 2048undopenssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix


6

Ich habe mit gemacht

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

Kredit geht hier


1
Warum hast du Victor oben keine Ehre gemacht? Er hat Ihnen fast 8 Monate zuvor den gleichen Befehl gegeben.
JWW

1
@jww Aus dem Bearbeitungsprotokoll von Victors Antwort können Sie sehen, dass die Antwort ursprünglich etwas anders war, ich nehme an, dass dies der Grund ist
Periklis

4

Das folgende Skript würde das öffentliche Schlüsselzertifikat ci.jenkins-ci.org im base64-codierten DER-Format erhalten und es in eine öffentliche OpenSSH-Schlüsseldatei konvertieren. Dieser Code setzt voraus, dass ein 2048-Bit-RSA-Schlüssel verwendet wird, und zieht viel aus der Antwort von Ian Boyd . Ich habe in Kommentaren zu diesem Artikel im Jenkins-Wiki etwas mehr erklärt, wie es funktioniert .

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

OMG das ist die beste Antwort! Und es funktioniert! (Ich musste nur status = none durch status = noxfer ersetzen). Verwenden Sie einfach den zweiten Befehl, der mit "base64" beginnt, und geben Sie ihm bei der Eingabe eine PEM-Datei, wobei die Überschriften entfernt und alle Zeilen zu einer verkettet werden. Vielen Dank, dass Sie @mkalkov!
Alexandroid

Beachten Sie, dass die obigen Befehle einen 2048-Bit-Schlüssel annehmen und nicht ordnungsgemäß funktionieren, wenn ein Schlüssel einer anderen Größe angegeben wird.
Alexandroid

1

FWIW, dieses BASH-Skript verwendet ein X.509-Zertifikat im PEM- oder DER-Format oder eine öffentliche OpenSSL-Schlüsseldatei (auch PEM-Format) als erstes Argument und entfernt einen öffentlichen OpenSSH-RSA-Schlüssel. Dies erweitert die obige Antwort von @ mkalkov. Die Anforderungen sind cat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl(1.0+) und natürlich bash. Alle außer openssl(enthält base64) sind so gut wie garantiert Teil der Basisinstallation auf jedem modernen Linux-System, außer vielleicht xxd(was Fedora im vim-commonPaket zeigt ). Wenn jemand es aufräumen und schöner machen möchte, Vorbehalt Lektor.

#!/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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.