Chuyển đổi khóa pem sang định dạng ssh-rsa


142

Tôi có một chứng chỉ ở derđịnh dạng, từ lệnh này với lệnh này, tôi tạo khóa công khai:

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

Kết quả nào trong việc này:

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

Làm thế nào tôi có thể có được một khóa công khai như thế này? Hoặc từ chứng chỉ hoặc từ khóa công khai này?

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

Điều này đã đạt được với lệnh này:

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

14
Cách bạn đăng trong "Điều này có được với lệnh này" hoạt động với tôi tốt hơn bất kỳ câu trả lời nào dưới đây.
Yoav Shapira

7
@YoavShipra. Có nhưng toàn bộ câu hỏi là anh ta muốn chuyển đổi chỉ sử dụng khóa chung. Có thể anh ta không có khóa riêng và anh ta chỉ có khóa chung và muốn chuyển đổi từ định dạng PEM sang định dạng ssh-rsa.
deltamind106

10
Đưa ra một .pem từ AWS, lệnh bạn đưa ra ở trên có ssh-keygen -y -f private_key1.pem > public_key1.pubtác dụng rất lớn đối với tôi.
Kzqai

1
Tất cả các câu trả lời sai. Đây là một trong những chính xác: ssh-keygen -i -m PKCS8 -f public-key.pem
Boeboe

3
Vẻ đẹp là trong mắt của kẻ si tình . Chúng ta cần lưu ý rằng khóa pem có thể chứa khóa chung hoặc khóa riêng hoặc cả hai; được mã hóa hoặc có thể không; cộng với định dạng khác nhau. Ngoài ra ý nghĩa của tùy chọn -mlà khác nhau cho -i/ -e. Vì vậy, các bạn của tôi, hãy chắc chắn rằng bạn biết những gì bạn muốn và những gì bạn có . :-)
ryenus

Câu trả lời:


129

Không cần phải biên dịch công cụ. Bạn có thể làm tương tự với ssh-keygen:

ssh-keygen -f pub1key.pub -i

sẽ đọc khóa công khai ở định dạng openssl từ pub1key.pubvà xuất nó ở định dạng OpenSSH.

Lưu ý : Trong một số trường hợp, bạn sẽ cần chỉ định định dạng đầu vào:

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

Từ các tài liệu ssh-keygen (Từ man ssh-keygen):

-m key_format Chỉ định định dạng khóa cho các tùy chọn chuyển đổi -i (nhập) hoặc -e (xuất). Các định dạng khóa được hỗ trợ là: Khóa RFC4716 ((khóa công khai hoặc riêng tư RFC 4716 / SSH2), Khóa PKCS8 ((khóa công khai PEM PKCS8) hoặc Khóa PEM (khóa công khai PEM). Định dạng chuyển đổi mặc định là R R R474716.


3
ssh-keygen: tùy chọn bất hợp pháp - m
mbonnin

1
Câu hỏi đi theo một cách khác.
131

4
Đối với những người tìm kiếm trên web trong tương lai, nếu điều này không phù hợp với bạn, các ý kiến ​​trong câu hỏi ban đầu sẽ có hiệu quả với tôi.
kristopolous

17
Trong trường hợp của tôi, điều -m PKCS8cần thiết là
Ian Hunter

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

53

Không cần kịch bản hoặc 'thủ thuật' khác: opensslssh-keygenlà đủ. Tôi giả sử không có mật khẩu cho các khóa (đó là xấu).

Tạo cặp RSA

Tất cả các phương pháp sau đây cung cấp một cặp khóa RSA có cùng định dạng

  1. Với openssl ( man genrsa )

    openssl genrsa -out dummy-genrsa.pem 2048
    

    Trong OpenSSL v1.0.1 genrsa được thay thế bởi genpkeyvì vậy đây là cách mới để làm điều đó ( man genpkey ):

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

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

Chuyển đổi DER sang PEM

Nếu bạn có cặp khóa RSA ở định dạng DER, bạn có thể muốn chuyển đổi nó thành PEM để cho phép chuyển đổi định dạng bên dưới:

Thế hệ:

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

Chuyển đổi:

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

Trích xuất khóa chung từ cặp RSA được định dạng PEM

  1. ở định dạng PEM:

    openssl rsa -in dummy-xxx.pem -pubout
    
  2. trong định dạng OpenSSH v2, xem :

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

Ghi chú

Phiên bản hệ điều hành và phần mềm:

[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

Người giới thiệu:


//, Điều này thực sự tạo ra một khóa trong ssh-rsađịnh dạng? Tài liệu tham khảo tốt, btw.
Nathan Basan

@NathanBasan, có (xem "Trích xuất khóa chung từ cặp RSA được định dạng PEM", điểm 2): một khi người ta có chứng chỉ ở định dạng pem: ssh-keygen -y -f dummy-xxx.pemtạo ra sự ssh-rsa AAAA[...]==phù hợp cho authorized_keystệp của ssh .
Thomas

Phần thông tin tốt ... nhưng tôi không nghĩ rằng nó thực sự trả lời câu hỏi cũng như phần ngắn hơn nhiều ở trên.
Mã Ogre

23

Để trả lời câu hỏi của riêng tôi, sau khi đăng lên danh sách gửi thư openssl đã nhận được điều này:

Đây là mã C để chuyển đổi từ khóa chung OpenSSL sang khóa chung OpenSSH. Bạn có thể lấy mã từ liên kết này và tự biên dịch nó:

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
Trong trường hợp ai đó đang tự hỏi làm thế nào để biên dịch cái này (tôi đã), thì đây là trình biên dịch gọi: gcc -o pubkey2ssh pubkey2ssh.c -lcrypto
Andreas Gohr

nơi nào trên get argv [2] (ssh_key_description) từ ... tôi chỉ có một ----- BEGIN RSA CÔNG CHÍNH ----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = ----- END RSA CÔNG KEY-- --- nó không có mô tả
braden

@braden. Thông thường nó chỉ là địa chỉ email của chủ sở hữu khóa. Nhưng bạn có thể đặt bất cứ điều gì bạn muốn int anh mô tả.
deltamind106

Việc triển khai php opensshtopem tại đây github.com/131/yks/blob/master/
131

Câu trả lời từ @mkalkov dưới đây thực hiện chuyển đổi bằng các công cụ dòng lệnh Linux. Nó chỉ cần tệp pem khóa công khai với các tiêu đề được loại bỏ và các dòng được hợp nhất làm đầu vào.
alexandroid

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

3
Không hoạt động đối với tôi: "do_convert_from_pkcs8: key.pem không phải là định dạng khóa công khai được công nhận". Những gì đã làm là "ssh-keygen -y -f key.pem" in ra văn bản ssh-rsa cần thiết cho ủy quyền.
Curt

1
Điều này không hiệu quảdo_convert_from_pkcs8: TEST.pem is not a recognised public key format
Jinna Balu

Làm việc cho tôi sau openssl genrsa -out newkey.pem 2048openssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem
xirix


6

Tôi đã làm với

ssh-keygen -i -f $ sshkeysfile >> ủy quyền

Tín dụng ở đây


1
Tại sao bạn không cung cấp tín dụng cho Victor ở trên? Anh ta đưa cho bạn lệnh tương tự gần 8 tháng trước.
jww

1
@jww Từ nhật ký chỉnh sửa câu trả lời của Victor, bạn có thể thấy rằng ban đầu câu trả lời hơi khác một chút, tôi cho rằng đây là lý do
periklis

4

Kịch bản sau đây sẽ có được chứng chỉ khóa công khai ci.jenkins-ci.org ở định dạng DER được mã hóa cơ sở64 và chuyển đổi nó thành tệp khóa công khai OpenSSH. Mã này giả định rằng khóa RSA 2048 bit được sử dụng và rút ra rất nhiều từ câu trả lời của Ian Boyd này . Tôi đã giải thích thêm một chút về cách hoạt động của nó trong các bình luận cho bài viết này trong 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

OMG đây là câu trả lời tốt nhất! Và nó hoạt động! (Tôi chỉ phải thay trạng thái = none bằng status = noxfer). Chỉ cần sử dụng lệnh thứ hai bắt đầu bằng "base64" và cung cấp cho nó tệp PEM ở đầu vào với các tiêu đề được loại bỏ và tất cả các dòng được nối thành một. Cảm ơn bạn @mkalkov!
alexandroid

Lưu ý các lệnh trên giả sử khóa 2048 bit và sẽ không hoạt động chính xác nếu được cung cấp một khóa có kích thước khác.
alexandroid

1

FWIW, tập lệnh BASH này sẽ lấy chứng chỉ X.509 định dạng PEM hoặc DER hoặc tệp khóa công khai OpenSSL (cũng là định dạng PEM) làm đối số đầu tiên và giải mã khóa công khai RSSS OpenSSH. Điều này mở rộng dựa trên câu trả lời của @ mkalkov ở trên. Yêu cầu là cat, grep, tr, dd, xxd, sed, xargs,file , uuidgen, base64, openssl(1.0 trở lên), và tất nhiên bash. Tất cả ngoại trừ openssl(chứa base64) được đảm bảo khá nhiều là một phần của cài đặt cơ sở trên bất kỳ hệ thống Linux hiện đại nào, ngoại trừ có thể xxd(mà Fedora hiển thị trong vim-commongói). Nếu bất cứ ai muốn làm sạch nó và làm cho nó đẹp hơn, hãy cẩn thận.

#!/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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.