Convierta la clave pem al formato ssh-rsa

142

Tengo un certificado en derformato, a partir de él con este comando genero una clave pública:

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

Lo que resulta en esto:

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

¿Cómo puedo obtener una clave pública como esta? ¿Ya sea del certificado o de esta clave pública?

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

Esto se obtuvo con este comando:

ssh-keygen -y -f private_key1.pem > public_key1.pub
Adrya
fuente
14
La forma en que publicó en "Esto se obtuvo con este comando" funcionó para mí mejor que cualquiera de las respuestas a continuación.
Yoav Shapira
77
@YoavShipra. Sí, pero la pregunta es que quiere convertir usando solo la clave pública. Tal vez no tiene la clave privada y solo tiene la clave pública y quiere convertir del formato PEM al formato ssh-rsa.
deltamind106
10
Dado un .pem de AWS, el comando que proporcionó anteriormente ssh-keygen -y -f private_key1.pem > public_key1.pubfuncionó muy bien para mí.
Kzqai
1
Todas las respuestas incorrectas. Este es el correcto: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
3
La belleza está en el ojo del espectador . Debemos tener en cuenta que una clave pem podría contener una clave pública o una clave privada, o ambas; cifrado o tal vez no; Además con varios formatos. Además, el significado de la opción -mes diferente para -i/ -e. Entonces, mis amigos, asegúrese de saber lo que quiere y lo que tiene . :-)
ryenus

Respuestas:

129

No es necesario compilar cosas. Puedes hacer lo mismo con ssh-keygen:

ssh-keygen -f pub1key.pub -i

leerá la clave pública en formato openssl pub1key.puby la generará en formato OpenSSH.

Nota : En algunos casos, deberá especificar el formato de entrada:

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

De los documentos ssh-keygen (De man ssh-keygen):

-m key_format Especifique un formato de clave para las opciones de conversión -i (importar) o -e (exportar). Los formatos de clave compatibles son: "RFC4716" (clave pública o privada RFC 4716 / SSH2), "PKCS8" (clave pública PEM PKCS8) o "PEM" (clave pública PEM). El formato de conversión predeterminado es "RFC4716".

Victor Mataré
fuente
3
ssh-keygen: opción ilegal - m
mbonnin
1
La pregunta va al revés.
131
44
Para futuros buscadores web, si esto no funciona para usted, los comentarios en la pregunta original funcionaron para mí.
kristopolous
17
En mi caso, -m PKCS8fue necesario
Ian Hunter
1
$ ssh-keygen -f mykey.pub -i key_from_blob: invalid format decode blob failed.
Bastian Voigt
53

No hay necesidad de guiones u otros 'trucos': opensslyssh-keygen son suficientes. Supongo que no hay contraseña para las claves (lo cual es malo).

Generar un par RSA

Todos los siguientes métodos dan un par de claves RSA en el mismo formato

  1. Con openssl ( hombre genrsa )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    En OpenSSL v1.0.1 genrsa se reemplaza por genpkeylo que esta es la nueva forma de hacerlo ( man genpkey ):

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

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

Convertir DER a PEM

Si tiene un par de claves RSA en formato DER, puede convertirlo a PEM para permitir la conversión de formato a continuación:

Generacion:

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

Conversión:

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

Extraiga la clave pública del par RSA con formato PEM

  1. en formato PEM:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. en formato OpenSSH v2 ver :

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

Notas

Sistema operativo y versión de software:

[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

Referencias

Thomas
fuente
//, ¿Esto realmente genera una clave en el ssh-rsaformato? Buena referencia, por cierto.
Nathan Basanese
@NathanBasanese, sí (ver "Extraer la clave pública del par RSA formateado PEM", punto 2): una vez que uno tiene el certificado en formato pem: ssh-keygen -y -f dummy-xxx.pemproduce un ssh-rsa AAAA[...]==ajuste para el authorized_keysarchivo ssh .
Thomas
Buena pieza informativa ... pero no creo que realmente responda la pregunta tan bien como la pieza mucho más corta anterior.
Ogre Codes
23

Para responder a mi propia pregunta, después de publicar en la lista de correo openssl obtuve esto:

Aquí hay un código C para convertir de una clave pública OpenSSL a una clave pública OpenSSH. Puede obtener el código de este enlace y compilarlo usted mismo:

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
fuente
2
En caso de que alguien se pregunte cómo compilar esto (estaba), aquí está la llamada al compilador: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas Gohr
¿de dónde viene el get argv [2] (ssh_key_description) a partir ... Sólo tengo un ----- BEGIN RSA CLAVE PÚBLICA ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END RSA PÚBLICA KEY-- --- no tiene una descripción
braden
@braden. Por lo general, es solo la dirección de correo electrónico del propietario de la clave. Pero puedes poner lo que quieras en la descripción.
deltamind106
Una implementación de php abreshtopem aquí github.com/131/yks/blob/master/class/stds/crypt.php#L346
131
La respuesta de @mkalkov a continuación realiza la conversión utilizando herramientas de línea de comandos de Linux. Solo necesita el archivo pem de clave pública con los encabezados eliminados y las líneas fusionadas como entrada.
alexandroid
13
ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe
fuente
3
No funcionó para mí: "do_convert_from_pkcs8: key.pem no es un formato de clave pública reconocido". Lo que funcionó fue "ssh-keygen -y -f key.pem", que imprime el texto ssh-rsa necesario para las claves autorizadas.
Curt
1
Esto no está funcionandodo_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu
Trabajó para mí después openssl genrsa -out newkey.pem 2048yopenssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix
12
ssh-keygen -f private.pem -y > public.pub
zkilnbqi
fuente
6

Hice con

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

El crédito va aquí

periklis
fuente
1
¿Por qué no le diste crédito a Victor arriba? Te dio el mismo comando casi 8 meses antes.
2015
1
@jww Del registro de edición de la respuesta de Victor puede ver que originalmente la respuesta era un poco diferente, supongo que esta es la razón
periklis
4

El siguiente script obtendría el certificado de clave pública ci.jenkins-ci.org en formato DER codificado en base64 y lo convertiría en un archivo de clave pública OpenSSH. Este código supone que se usa una clave RSA de 2048 bits y se basa mucho en la respuesta de Ian Boyd . He explicado un poco más cómo funciona en los comentarios a este artículo en la wiki de 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
fuente
Dios mío, esta es la mejor respuesta! ¡Y funciona! (Solo tuve que reemplazar status = none con status = noxfer). Simplemente use el segundo comando que comienza con "base64" y dele un archivo PEM en la entrada con los encabezados eliminados y todas las líneas concatenadas en una. Gracias @mkalkov!
alexandroid
Tenga en cuenta que los comandos anteriores asumen una clave de 2048 bits y no funcionarán correctamente si se le da una clave de un tamaño diferente.
alexandroid
1

FWIW, este script BASH tomará un certificado X.509 en formato PEM o DER o un archivo de clave pública OpenSSL (también formato PEM) como primer argumento y arrojará una clave pública OpenSSH RSA. Esto se expande sobre la respuesta de @ mkalkov anterior. Los requisitos son cat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl(1.0+), y por supuesto bash. Todos, excepto openssl(contiene base64), están casi garantizados como parte de la instalación base en cualquier sistema Linux moderno, excepto tal vez xxd(que Fedora muestra en el vim-commonpaquete). Si alguien quiere limpiarlo y hacerlo más agradable, advierta 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_
fuente