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

Openssl 将pem密钥转换为ssh rsa格式,openssl,openssh,Openssl,Openssh,我有一个der格式的证书,通过此命令我可以从中生成一个公钥: openssl x509 -inform der -in ejbcacert.cer -noout -pubkey > pub1key.pub 其结果是: -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vbqajDw4o6gJy8UtmIbkcpnk O3Kwc4qsEnSZp/TR+fQi62F79RHWmwKOtFmwteURgLbj7

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

为了回答我自己的问题,在openssl邮件列表上发布后,我得到以下信息:

下面是将OpenSSL公钥转换为OpenSSH公钥的C代码。 您可以从中获取代码并自己编译:

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;
}

不需要编译东西。您可以对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键_格式为-i(导入)或-e(导出)转换选项指定键格式。支持的密钥格式有:“RFC4716”(RFC 4716/SSH2公钥或私钥)、“PKCS8”(PEM PKCS8公钥)或“PEM”(PEM公钥)。默认转换格式为“RFC4716”

我和你一起去的

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


以下脚本将获取base64编码的DER格式的ci.jenkins-ci.org公钥证书,并将其转换为OpenSSH公钥文件。这段代码假设使用了2048位RSA密钥,并从Ian Boyd的密码中提取了很多信息。我已经在Jenkins wiki的评论中详细解释了它的工作原理

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

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

生成RSA对 以下所有方法都提供相同格式的RSA密钥对

  • 使用openssl()

    在OpenSSL v1.0.1
    genrsa
    by
    genpkey
    中,这是一种新的方法():

  • 使用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格式中:

  • 笔记 操作系统和软件版本:

    [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
    
    参考资料:


    FWIW,此BASH脚本将采用PEM或DER格式的X.509证书或OpenSSL公钥文件(也是PEM格式)作为第一个参数,并释放OpenSSH RSA公钥。这扩展了上面@mkalkov的答案。要求包括
    cat
    grep
    tr
    dd
    xxd
    sed
    xargs
    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
    

    如果有人想知道如何编译这个(我是),下面是编译器调用:gcc-o pubkey2ssh pubkey2ssh.c-lcrypton从哪里获取argv[2](ssh_key_description)。。。我只有一个------BEGIN RSA公钥------MIGJAoGBAMC62xWiOZYlhUhmk+jesy5ezungugog9kshumn67ibnzlesr2qn44j1b totzruessakxu7alfljvu5asgbuvin3dusal5szjtf9vzgjhsvycortchc1tui wmawfv2bltmk4zbec33rieblex8trphp3ybimtzqv81zrzhzbsnbaae=----结束RSA公钥------它没有description@braden. 通常它只是密钥所有者的电子邮件地址。但是你可以在描述中放入你想要的任何东西。一个php实现opensshtopem这里来自@mkalkov的答案使用Linux命令行工具进行转换。它只需要删除带有标题的公钥pem文件,并将行合并为输入。ssh-keygen:非法选项--m问题是相反的。对于未来的web搜索者,如果这对你不起作用,那么原始问题中的注释对我起作用。在我的情况下,
    -m PKCS8
    是必需的
    $ssh keygen-f mykey.pub-i
    key\u from\u blob:invalid format
    解码blob失败。
    您在“这是通过此命令获得的”中发布的方式比下面的任何答案更适合我。@YoavShipra。是的,但整个问题是,他只想使用公钥进行转换。也许他没有私钥,他只有公钥,想从PEM格式转换成ssh rsa格式。如果AWS提供了一个.PEM,你上面给出的命令
    ssh-keygen-y-f private_-key1.PEM>public_-key1.pub
    对我来说非常有效。答案都错了。这是正确的:
    ssh-keygen-i-m PKCS8-f公钥。我们需要注意的是,pem密钥可以包含公钥或私钥,或者两者都包含;加密或不加密;加上各种格式。选项
    -m
    的含义也与
    -i
    /
    -e
    不同。所以,我的朋友们,请确保你知道你想要什么和你拥有什么。:-)你为什么不相信维克托?差不多8个月前,他给了你同样的命令。@jww从维克多回复的编辑日志中,你可能会看到最初的答案有点不同,我想这就是原因了,omg这是最好的答案!而且它有效!(我只需将status=none替换为status=noxfer)。只需使用以“base64”开头的第二个命令,并在输入时为其提供一个PEM文件,去掉标题并将所有行连接成一行。谢谢你@mkalkov!注意:上面的命令假定为2048位密钥,如果给定不同大小的密钥,则无法正常工作。//,这是否实际生成
    ssh rsa
    格式的密钥?很好的参考,顺便说一句@Nathanbassanese,是的(见“提取
    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-keygen -f private.pem -y > public.pub
    
    ssh-keygen -i -m PKCS8 -f public-key.pem
    
    #!/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