将 pem 密钥转换为 ssh-rsa 格式

Posted

技术标签:

【中文标题】将 pem 密钥转换为 ssh-rsa 格式【英文标题】:Convert pem key to ssh-rsa format 【发布时间】:2010-11-03 22:30:25 【问题描述】:

我有一个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

【问题讨论】:

您在“这是通过此命令获得的”中发布的方式对我来说比以下任何答案都更有效。 @YoavShipra。是的,但整个问题是他只想使用公钥进行转换。也许他没有私钥,他只有公钥,想从 PEM 格式转换为 ssh-rsa 格式。 鉴于来自 AWS 的 .pem,您在 ssh-keygen -y -f private_key1.pem > public_key1.pub 上面给出的命令对我来说非常有用。 所有错误答案。这是正确的:ssh-keygen -i -m PKCS8 -f public-key.pem 美丽在旁观者的眼中。我们需要注意 pem 密钥可以包含公钥或私钥,或两者兼而有之;加密或不加密;加上各种格式。选项-m 的含义也与-i/-e 不同。所以我的朋友们,请确保您知道自己想要什么以及拥有什么。 :-) 【参考方案1】:

不需要编译东西。你可以用ssh-keygen做同样的事情:

ssh-keygen -f pub1key.pub -i

将从pub1key.pub读取openssl格式的公钥,并以OpenSSH格式输出。

注意:在某些情况下您需要指定输入格式:

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

来自 ssh-keygen 文档(来自 man ssh-keygen):

-m key_format 为 -i(导入)或 -e(导出)转换选项指定密钥格式。支持的密钥格式为:“RFC4716”(RFC 4716/SSH2 公钥或私钥)、“PKCS8”(PEM PKCS8 公钥)或“PEM”(PEM 公钥)。默认转换格式为“RFC4716”。

【讨论】:

ssh-keygen: 非法选项 -- m 问题反过来了。 对于未来的网络搜索者,如果这对您不起作用,那么原始问题中的 cmets 对我有用。 就我而言,-m PKCS8 是必要的 $ ssh-keygen -f mykey.pub -i key_from_blob: invalid format decode blob failed.【参考方案2】:

不需要脚本或其他“技巧”:opensslssh-keygen 就足够了。我假设密钥没有密码(这很糟糕)。

生成一个 RSA 对

以下所有方法都给出了相同格式的 RSA 密钥对

    使用 openssl (man genrsa)

    openssl genrsa -out dummy-genrsa.pem 2048
    

    在 OpenSSL v1.0.1 genrsa is superseded genpkey 中,这是实现它的新方法 (man genpkey):

    openssl genpkey -algorithm RSA -out dummy-genpkey.pem -pkeyopt rsa_keygen_bits:2048
    

    使用 ssh-keygen

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

将 DER 转换为 PEM

如果您有 DER 格式的 RSA 密钥对,您可能需要将其转换为 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 对中提取公钥

    PEM 格式:

    openssl rsa -in dummy-xxx.pem -pubout
    

    OpenSSH v2 格式see:

    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

参考资料:

Sysmic.org Convert keys betweens GnuPG, OpenSsh and OpenSSL

【讨论】:

// , 这真的会生成ssh-rsa 格式的密钥吗?很好的参考,顺便说一句。 @NathanBasanese,是的(请参阅“从 PEM 格式的 RSA 对中提取公钥”,第 2 点):一旦拥有 pem 格式的证书:ssh-keygen -y -f dummy-xxx.pem 会生成适合的 ssh-rsa AAAA[...]== ssh 的authorized_keys 文件。 内容翔实的文章...但我认为它并不能像上面更短的文章那样真正回答问题。 通过转换显示:无法加载Private Key 10828:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:.\crypto\a sn1\tasn_dec.c:1200: 写出:OpenSSL> rsa -in genpkeySSH.pem -pubout -out genpubkeySSH.pem【参考方案3】:

为了回答我自己的问题,在 openssl 邮件列表上发帖后得到了这个:

这是从 OpenSSL 公钥转换为 OpenSSH 公钥的 C 代码。 你可以从this link获取代码并自己编译:

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;

【讨论】:

如果有人想知道如何编译这个(我是),这里是编译器调用:gcc -o pubkey2ssh pubkey2ssh.c -lcrypto 其中上获取的argv确实[2]从...我只是有(ssh_key_description)一个----- BEGIN RSA公钥----- MIGJAoGBAMC62xWiOZYlhUhmk + JESy5eZunwGoG9kSHUMn67iBNZLEsR2qN44J1B TOtZRuEsSAKxu7alFlJVu5aSGbUvin3DusYAsl5sZjTf9VZgJHsVycOrtChC1tUi WMAWfv2BLTmK4zBEC33riEBLeX8Trphp3YbIMtzqV81ZrzHZbSnrAgMBAAE = --- --END RSA PUBLIC KEY-----它没有描述 @braden。通常它只是密钥所有者的电子邮件地址。但是你可以在他的描述中放任何你想要的东西。 这里是一个php实现opensshtopem github.com/131/yks/blob/master/class/stds/crypt.php#L346 下面@mkalkov 的回答使用Linux 命令行工具进行了转换。它只需要删除标题并将行合并为输入的公钥 pem 文件。【参考方案4】:
ssh-keygen -i -m PKCS8 -f public-key.pem

【讨论】:

对我不起作用:“do_convert_from_pkcs8:key.pem 不是公认的公钥格式”。起作用的是“ssh-keygen -y -f key.pem”,它打印出授权密钥所需的 ssh-rsa 文本。 这不起作用do_convert_from_pkcs8: TEST.pem is not a recognised public key format openssl genrsa -out newkey.pem 2048openssl rsa -in newkey.pem -outform PEM -pubout -out newkeypublic.pem 之后为我工作【参考方案5】:
ssh-keygen -f private.pem -y > public.pub

【讨论】:

【参考方案6】:

以下脚本将获取 base64 编码的 DER 格式的 ci.jenkins-ci.org 公钥证书,并将其转换为 OpenSSH 公钥文件。此代码假定使用 2048 位 RSA 密钥,并从 Ian Boyd 的 answer 中汲取了很多信息。我已经向 Jenkins wiki 中的 this article 解释了它在 cmets 中的工作原理。

echo -n "ssh-rsa " > jenkins.pub
curl -sfI https://ci.jenkins-ci.org/ | grep -i 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

【讨论】:

天哪,这是最好的答案!它有效! (我只需要将 status=none 替换为 status=noxfer)。只需使用以“base64”开头的第二个命令,并在输入时为其提供一个 PEM 文件,其中标头被剥离,所有行连接成一个。谢谢@mkalkov! 请注意,以上命令假定密钥为 2048 位,如果给定不同大小的密钥,将无法正常工作。【参考方案7】:

我做过

ssh-keygen -i -f $sshkeysfile >> 授权密钥

Credit goes here

【讨论】:

你为什么不把上面的维克多归功于?差不多 8 个月前,他给了你同样的命令。 @jww 从 Victor 回复的编辑日志中,您可能会看到原来的答案有点不同,我认为这是原因【参考方案8】:

FWIW,此 BASH 脚本将采用 PEM 或 DER 格式的 X.509 证书或 OpenSSL 公钥文件(也是 PEM 格式)作为第一个参数并泄露 OpenSSH RSA 公钥。这扩展了@mkalkov 上面的回答。要求为catgreptrddxxdsedxargsfileuuidgen、@987654331(1.@90+6)当然还有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

【讨论】:

以上是关于将 pem 密钥转换为 ssh-rsa 格式的主要内容,如果未能解决你的问题,请参考以下文章

将Java密钥库转换为PEM格式

如何将 ECDSA 密钥转换为 PEM 格式

sh 将密钥从二进制(由生成密钥生成)转换为pem格式。适用于私钥和公钥

将 ssh-dss 密钥转换为 .pem?

将 CA 签名的 JKS 密钥库转换为 PEM

在 Windows 中自动/脚本/命令行将 .pem 密钥文件转换为 .ppk