Convertir la clé pem au format ssh-rsa

143

J'ai un certificat au derformat, à partir de celui-ci avec cette commande, je génère une clé publique:

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

Ce qui se traduit par ceci:

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

Comment puis-je obtenir une clé publique comme celle-ci? Soit à partir du certificat, soit à partir de cette clé publique?

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

Ceci a été obtenu avec cette commande:

ssh-keygen -y -f private_key1.pem > public_key1.pub
Adrya
la source
14
La façon dont vous avez posté dans le "Ceci a été obtenu avec cette commande" a fonctionné pour moi mieux que n'importe laquelle des réponses ci-dessous.
Yoav Shapira
7
@YoavShipra. Oui mais toute la question est qu'il veut convertir en utilisant uniquement la clé publique. Peut-être qu'il n'a pas la clé privée et il n'a que la clé publique et veut convertir du format PEM au format ssh-rsa.
deltamind106
10
Étant donné un .pem d'AWS, la commande que vous donnez ci-dessus ssh-keygen -y -f private_key1.pem > public_key1.puba très bien fonctionné pour moi.
Kzqai
1
Toutes les mauvaises réponses. C'est la bonne: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
3
La beauté est dans l'œil du spectateur . Nous devons noter qu'une clé pem peut contenir soit une clé publique, soit une clé privée, ou les deux; crypté ou peut-être pas; plus avec différents formats. La signification de l'option -mest également différente pour -i/ -e. Alors mes amis, assurez-vous de savoir ce que vous voulez et ce que vous avez . :-)
ryenus

Réponses:

129

Pas besoin de compiler des trucs. Vous pouvez faire de même avec ssh-keygen:

ssh-keygen -f pub1key.pub -i

lira la clé publique au format openssl pub1key.pubet la sortira au format OpenSSH.

Remarque : dans certains cas, vous devrez spécifier le format d'entrée:

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

À partir de la documentation ssh-keygen (De man ssh-keygen):

-m key_format Spécifie un format de clé pour les options de conversion -i (importation) ou -e (exportation). Les formats de clé pris en charge sont: «RFC4716» (clé publique ou privée RFC 4716 / SSH2), «PKCS8» (clé publique PEM PKCS8) ou «PEM» (clé publique PEM). Le format de conversion par défaut est «RFC4716».

Victor Mataré
la source
3
ssh-keygen: option illégale - m
mbonnin
1
La question va dans l'autre sens.
131
4
Pour les futurs internautes, si cela ne fonctionne pas pour vous, les commentaires de la question d'origine ont fonctionné pour moi.
kristopolous
17
Dans mon cas, -m PKCS8c'était nécessaire
Ian Hunter
1
$ ssh-keygen -f mykey.pub -i key_from_blob: invalid format decode blob failed.
Bastian Voigt
54

Pas besoin de scripts ou d'autres «astuces»: opensslet ssh-keygensuffisent. Je suppose qu'aucun mot de passe pour les clés (ce qui est mauvais).

Générer une paire RSA

Toutes les méthodes suivantes donnent une paire de clés RSA dans le même format

  1. Avec openssl ( man genrsa )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    Dans OpenSSL v1.0.1 genrsa est remplacé par genpkeydonc c'est la nouvelle façon de le faire ( man genpkey ):

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

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

Conversion de DER en PEM

Si vous disposez d'une paire de clés RSA au format DER, vous souhaiterez peut-être la convertir en PEM pour permettre la conversion de format ci-dessous:

Génération:

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

Conversion:

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

Extraire la clé publique de la paire RSA formatée PEM

  1. au format PEM:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. au format OpenSSH v2 voir :

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

Remarques

Version du système d'exploitation et du logiciel:

[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

Références:

Thomas
la source
//, Cela génère-t-il réellement une clé au ssh-rsaformat? Bonne référence, btw.
Nathan Basanese
@NathanBasanese, oui (voir "Extraire la clé publique de la paire RSA formatée PEM", point 2): une fois que l'on a le certificat au format pem: ssh-keygen -y -f dummy-xxx.pemproduit un ssh-rsa AAAA[...]==ajustement pour le authorized_keysfichier de ssh .
Thomas
Bon article informatif ... mais je ne pense pas qu'il réponde vraiment à la question ainsi que l'article beaucoup plus court ci-dessus.
Codes Ogre
23

Pour répondre à ma propre question, après avoir posté sur la liste de diffusion openssl, j'ai obtenu ceci:

Voici le code C pour convertir une clé publique OpenSSL en une clé publique OpenSSH. Vous pouvez récupérer le code à partir de ce lien et le compiler vous-même:

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
la source
2
Au cas où quelqu'un se demanderait comment compiler ceci (je l'étais), voici l'appel du compilateur: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas Gohr
d' où vient le get argv [2] (ssh_key_description) de ... J'ai juste ----- BEGIN RSA PUBLIC KEY ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END RSA PUBLIC KEY-- --- il n'a pas de description
braden
@braden. Il ne s'agit généralement que de l'adresse e-mail du propriétaire de la clé. Mais vous pouvez mettre ce que vous voulez dans la description.
deltamind106
Une implémentation php opensshtopem ici github.com/131/yks/blob/master/class/stds/crypt.php#L346
131
La réponse de @mkalkov ci-dessous effectue la conversion à l'aide des outils de ligne de commande Linux. Il a juste besoin d'un fichier pem de clé publique avec les en-têtes supprimés et les lignes fusionnées en entrée.
alexandroid
13
ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
la source
3
Cela n'a pas fonctionné pour moi: "do_convert_from_pkcs8: key.pem n'est pas un format de clé publique reconnu". Ce qui a fonctionné, c'est "ssh-keygen -y -f key.pem" qui imprime le texte ssh-rsa nécessaire pour les clés_autorisées.
Curt
1
Cela ne fonctionne pasdo_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu
A travaillé pour moi après openssl genrsa -out newkey.pem 2048etopenssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix
12
ssh-keygen -f private.pem -y > public.pub
zkilnbqi
la source
6

J'ai fait avec

ssh-keygen -i -f $ sshkeysfile >> clés_autorisées

Le crédit va ici

periklis
la source
1
Pourquoi n'avez-vous pas donné crédit à Victor ci-dessus? Il vous a donné la même commande presque 8 mois plus tôt.
jww
1
@jww Dans le journal d'édition de la réponse de Victor, vous pouvez voir qu'à l'origine la réponse était un peu différente, je suppose que c'est la raison
periklis
4

Le script suivant obtiendrait le certificat de clé publique ci.jenkins-ci.org au format DER encodé en base64 et le convertirait en fichier de clé publique OpenSSH. Ce code suppose qu'une clé RSA de 2048 bits est utilisée et s'inspire beaucoup de la réponse de Ian Boyd . J'ai expliqué un peu plus comment cela fonctionne dans les commentaires de cet article sur le wiki Jenkins.

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
la source
OMG c'est la meilleure réponse! Et il fonctionne! (Je n'ai eu qu'à remplacer status = none par status = noxfer). Utilisez simplement la deuxième commande commençant par "base64" et donnez-lui un fichier PEM en entrée avec les en-têtes supprimés et toutes les lignes concaténées en une seule. Merci @mkalkov!
alexandroid
Notez que les commandes ci-dessus supposent une clé de 2048 bits et ne fonctionneront pas correctement si une clé de taille différente leur est donnée.
alexandroid le
1

FWIW, ce script BASH prendra un certificat X.509 au format PEM ou DER ou un fichier de clé publique OpenSSL (également au format PEM) comme premier argument et annulera une clé publique OpenSSH RSA. Cela étend la réponse de @ mkalkov ci-dessus. Les exigences sont cat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl(1.0+), et bien sûr bash. Tous sauf openssl(contient base64) sont à peu près garantis pour faire partie de l'installation de base sur n'importe quel système Linux moderne, sauf peut-être xxd(ce que Fedora montre dans le vim-commonpaquet). Si quelqu'un veut le nettoyer et le rendre plus agréable, avertissez le lecteur.

#!/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_
la source