แปลงคีย์ pem เป็นรูปแบบ ssh-rsa


143

ฉันมีใบรับรองในderรูปแบบจากคำสั่งนี้ฉันจะสร้างกุญแจสาธารณะ:

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

ซึ่งผลลัพธ์ในสิ่งนี้:

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

ฉันจะรับกุญแจสาธารณะเช่นนี้ได้อย่างไร อาจมาจากใบรับรองหรือจากกุญแจสาธารณะนี้?

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

สิ่งนี้ได้มาด้วยคำสั่งนี้:

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

14
วิธีที่คุณโพสต์ใน "สิ่งนี้ได้มาจากคำสั่งนี้" ได้ผลสำหรับฉันดีกว่าคำตอบใด ๆ ด้านล่าง
Yoav Shapira

7
@YoavShipra ใช่ แต่คำถามทั้งหมดคือเขาต้องการแปลงโดยใช้รหัสสาธารณะเท่านั้น บางทีเขาอาจไม่มีรหัสส่วนตัวและเขามีรหัสสาธารณะเท่านั้นและต้องการแปลงจากรูปแบบ PEM เป็นรูปแบบ ssh-rsa
deltamind106

10
ได้รับ. pem จาก AWS คำสั่งที่คุณให้ไว้ข้างต้นนั้นssh-keygen -y -f private_key1.pem > public_key1.pubยอดเยี่ยมสำหรับฉัน
Kzqai

1
คำตอบที่ผิดทั้งหมด นี่คือสิ่งที่ถูกต้อง: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe

3
ความงามอยู่ในสายตาของคนดู เราจำเป็นต้องทราบว่าคีย์pemสามารถสร้างคีย์สาธารณะหรือคีย์ส่วนตัวหรือทั้งสองอย่าง เข้ารหัสหรืออาจจะไม่; บวกกับรูปแบบต่าง ๆ นอกจากนี้ยังมีความหมายของตัวเลือกที่-mแตกต่างกันสำหรับ/-i -eดังนั้นเพื่อนของฉันโปรดให้แน่ใจว่าคุณรู้ว่าสิ่งที่คุณต้องการและสิ่งที่คุณมี :-)
ryenus

คำตอบ:


129

ไม่จำเป็นต้องรวบรวมเนื้อหา คุณสามารถทำเช่นเดียวกันกับssh-keygen:

ssh-keygen -f pub1key.pub -i

จะอ่านกุญแจสาธารณะในรูปแบบ openssl จากpub1key.pubและส่งออกในรูปแบบ OpenSSH

หมายเหตุ : ในบางกรณีคุณจะต้องระบุรูปแบบอินพุต:

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

จาก ssh-keygen docs (จาก man ssh-keygen):

-m key_formatระบุรูปแบบคีย์สำหรับตัวเลือกการแปลง -i (นำเข้า) หรือ -e (ส่งออก) รูปแบบคีย์ที่รองรับคือ: "RFC4716" (RFC 4716 / SSH2 กุญแจสาธารณะหรือส่วนตัว), "PKCS8" (กุญแจสาธารณะ PEM PKCS8) หรือ "PEM" (กุญแจสาธารณะ PEM) รูปแบบการแปลงเริ่มต้นคือ“ RFC4716”


3
ssh-keygen: ตัวเลือกที่ผิดกฎหมาย - m
mbonnin

1
คำถามไปในทางอื่น
131

4
สำหรับผู้ค้นหาเว็บในอนาคตหากสิ่งนี้ไม่ได้ผลสำหรับคุณความคิดเห็นในคำถามเดิมใช้ได้สำหรับฉัน
kristopolous

17
ในกรณีของฉัน-m PKCS8มีความจำเป็น
เอียนฮันเตอร์

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

54

ไม่จำเป็นต้องใช้สคริปต์หรือ 'เทคนิค' อื่น ๆ : opensslและssh-keygenก็เพียงพอแล้ว ฉันสมมติว่าไม่มีรหัสผ่านสำหรับคีย์ (ซึ่งไม่ดี)

สร้างคู่ RSA

วิธีการทั้งหมดต่อไปนี้ให้คู่ของคีย์ RSA ในรูปแบบเดียวกัน

  1. ด้วย openssl (ประเภทคน )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    ใน OpenSSL v1.0.1 genrsa ถูกแทนที่ด้วยgenpkeyนี่คือวิธีใหม่ในการทำ ( man genpkey ):

    openssl genpkey -algorithm RSA -out dummy-genpkey.pem -pkeyopt rsa_keygen_bits:2048
    
  2. ด้วย ssh-keygen

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

การแปลง DER เป็น PEM

หากคุณมีคู่คีย์ RSA ในรูปแบบ DER คุณอาจต้องการแปลงเป็น PEM เพื่ออนุญาตการแปลงรูปแบบด้านล่าง:

รุ่น:

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

การแปลง:

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

แยกพับลิกคีย์จาก PEM ที่จัดรูปแบบแล้วคู่ RSA

  1. ในรูปแบบ PEM:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. ในรูปแบบ OpenSSH v2 ดู :

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

หมายเหตุ

ระบบปฏิบัติการและเวอร์ชั่นซอฟต์แวร์:

[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

อ้างอิง:


//, นี่จะสร้างคีย์ในssh-rsaรูปแบบจริงหรือไม่ การอ้างอิงที่ดี btw
Nathan Basanese

@NathanBasanese ใช่ (ดู "แยกคีย์สาธารณะออกจากคู่ RSA ที่จัดรูปแบบ PEM", จุดที่ 2): เมื่อมีใบรับรองในรูปแบบ pem: ssh-keygen -y -f dummy-xxx.pemสร้างไฟล์ที่ssh-rsa AAAA[...]==เหมาะสำหรับ ssh authorized_keys
โทมัส

ข้อมูลที่ดี ... แต่ฉันไม่คิดว่ามันจะตอบคำถามได้อย่างแท้จริงรวมถึงข้อความสั้นกว่านั้น
Ogre Codes

23

เพื่อตอบคำถามของฉันเองหลังจากโพสต์ในรายชื่อผู้รับจดหมาย openssl ได้รับสิ่งนี้:

นี่คือรหัส C ที่จะแปลงจากรหัสสาธารณะ OpenSSL เป็นรหัสสาธารณะ OpenSSH คุณสามารถคว้ารหัสจากลิงค์นี้และรวบรวมด้วยตัวคุณเอง:

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
ในกรณีที่มีคนสงสัยว่าจะรวบรวมข้อมูลได้อย่างไร (นี่คือฉัน) นี่คือการคอมไพล์เลอร์: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas

ที่ไม่เกี่ยวกับการได้รับ argv [2] (ssh_key_description) จาก ... ฉันเพียงแค่มี ----- BEGIN RSA คีย์สาธารณะ ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END อาร์เอส จำกัด KEY-- --- ไม่มีคำอธิบาย
braden

@braden โดยปกติจะเป็นเพียงที่อยู่อีเมลของเจ้าของกุญแจ แต่คุณสามารถใส่อะไรก็ได้ที่คุณต้องการให้เขาอธิบาย
deltamind106

การใช้งาน php opensshtopem ที่นี่ github.com/131/yks/blob/master/class/stds/crypt.php#L346
131

คำตอบจาก @mkalkov ด้านล่างทำการแปลงโดยใช้เครื่องมือบรรทัดคำสั่ง Linux มันแค่ต้องการไฟล์กุญแจสาธารณะที่มีการลบส่วนหัวและบรรทัดที่รวมเป็นอินพุต
alexandroid

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

3
ไม่ทำงานสำหรับฉัน: "do_convert_from_pkcs8: key.pem ไม่ใช่รูปแบบกุญแจสาธารณะที่รู้จัก" สิ่งที่ได้ผลคือ "ssh-keygen -y -f key.pem" ซึ่งพิมพ์ข้อความ ssh-rsa ที่จำเป็นสำหรับ authorized_keys
ห้วน

1
สิ่งนี้ไม่ทำงานdo_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu

ทำงานให้ฉันหลังจากopenssl genrsa -out newkey.pem 2048และopenssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix


6

ฉันทำกับ

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

เครดิตไปที่นี่


1
ทำไมคุณไม่ให้เครดิตกับผู้ชนะข้างต้น เขาให้คำสั่งเดียวกันกับคุณเกือบ 8 เดือนก่อนหน้านี้
jww

1
@jww จากบันทึกการแก้ไขการตอบกลับของ Victor คุณอาจเห็นว่าคำตอบเดิมแตกต่างกันเล็กน้อยฉันคิดว่านี่คือเหตุผล
periklis

4

สคริปต์ต่อไปนี้จะได้รับใบรับรองกุญแจสาธารณะ ci.jenkins-ci.org ในรูปแบบ DER ที่เข้ารหัสด้วย base64 และแปลงเป็นไฟล์กุญแจสาธารณะ OpenSSH รหัสนี้อนุมานว่าคีย์ RSA 2048 บิตจะใช้และดึงมากจากนี้เอียนบอยด์คำตอบ ฉันอธิบายอีกเล็กน้อยว่ามันทำงานอย่างไรในการแสดงความคิดเห็นต่อบทความนี้ใน 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

OMG นี่คือคำตอบที่ดีที่สุด! และมันใช้งานได้! (ฉันต้องแทนที่ status = none ด้วย status = noxfer) เพียงใช้คำสั่งที่สองที่ขึ้นต้นด้วย "base64" และให้ไฟล์ PEM กับอินพุตที่มีส่วนหัวหลุดออกและทุกบรรทัดจะรวมกันเป็นหนึ่งเดียว ขอบคุณ @mkalkov!
alexandroid

โปรดสังเกตคำสั่งข้างต้นสมมติว่ามีคีย์ 2048 บิตและจะทำงานไม่ถูกต้องหากให้รหัสที่มีขนาดต่าง
alexandroid

1

FWIW สคริปต์ BASH นี้จะใช้ใบรับรอง PEM- หรือ DER-format X.509 หรือไฟล์กุญแจสาธารณะ OpenSSL (เช่นรูปแบบ PEM) เป็นอาร์กิวเมนต์แรกและปลดกุญแจสาธารณะของ OpenSSH RSA สิ่งนี้จะขยายไปตามคำตอบของ @ mkalkov ด้านบน ต้องการมีcat, grep, tr, dd, xxd, sed, xargs, file, uuidgen, base64, openssl(1.0+) bashและแน่นอน ทั้งหมดยกเว้นopenssl(มีbase64) รับประกันค่อนข้างมากที่จะเป็นส่วนหนึ่งของการติดตั้งฐานในระบบ Linux ที่ทันสมัยใด ๆ ยกเว้นบางทีxxd(ซึ่ง Fedora แสดงในvim-commonแพ็คเกจ) หากใครต้องการทำความสะอาดและทำให้มันดีกว่านี้

#!/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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.