从 PEM BASE64 编码的私钥文件中获取 RSA 私钥

Posted

技术标签:

【中文标题】从 PEM BASE64 编码的私钥文件中获取 RSA 私钥【英文标题】:Getting RSA private key from PEM BASE64 Encoded private key file 【发布时间】:2011-11-05 05:29:10 【问题描述】:

我有一个私钥文件(PEM BASE64 编码)。我想在其他地方使用它来解密其他一些数据。使用Java我试图读取文件并解码其中的BASE64编码数据...... 这是我尝试过的代码 sn-p....

import java.io.*;
import java.nio.ByteBuffer;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import com.ibm.crypto.fips.provider.RSAPrivateKey;
import com.ibm.misc.BASE64Decoder;

public class GetPrivateKey 
    public static RSAPrivateKey get() throws Exception 
        File privateKeyFile = new File("privatekey.key");
        byte[] encodedKey = new byte[(int) privateKeyFile.length()];
        new FileInputStream(privateKeyFile).read(encodedKey);
        ByteBuffer keyBytes = new BASE64Decoder().decodeBufferToByteBuffer(encodedKey.toString());
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes.array());
        KeyFactory kf = KeyFactory.getInstance("RSA", "IBMJCEFIPS");
        RSAPrivateKey pk = (RSAPrivateKey) kf.generatePrivate(privateKeySpec);
        return pk;
    

    public static void main(String[] args) throws Exception 
        PrivateKey privKey = FormatMePlease.get();
        System.out.println(privKey.toString());
    


我收到以下错误

Exception in thread "main" java.security.spec.InvalidKeySpecException: Inappropriate key specification: DerInputStream.getLength(): lengthTag=127, too big.
at com.ibm.crypto.fips.provider.RSAKeyFactory.b(Unknown Source)
at com.ibm.crypto.fips.provider.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at GetPrivateKey.get(GetPrivateKey.java:24)
at GetPrivateKey.main(GetPrivateKey.java:29)

文件“privatekey.key”的内容

-----BEGIN RSA PRIVATE KEY-----
MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAF53wUbKmDHtvfOb8u1HPqEBFNNF
csnOMjIcSEhAwIQMbgrOuQ+vH/YgXuuDJaURS85H8P4UTt6lYOJn+SFnXvS82E7LHJpVrWwQzbh2
QKh13/akPe90DlNTUGEYO7rHaPLqTlld0jkLFSytwqfwqn9yrYpM1ncUOpCciK5j8t8MzO71LJoJ
g24CFxpjIS0tBrJvKzrRNcxWSRDLmu2kNmtsh7yyJouE6XoizVmBmNVltHhFaDMmqjugMQA2CZfL
rxiR1ep8TH8IBvPqysqZI1RIpB/e0engP4/1KLrOt+6gGS0JEDh1kG2fJObl+N4n3sCOtgaz5Uz8
8jpwbmZ3Se8CAwEAAQKCAQAdOsSs2MbavAsIM3qo/GBehO0iqdxooMpbQvECmjZ3JTlvUqNkPPWQ
vFdiW8PsHTvtackhdLsqnNUreKxXL5rr8vqi9qm0/0mXpGNi7gP3m/FeaVdYnfpIwgCe6lag5k6M
yv7PG/6N8+XrWyBdwlOe96bGohvB4Jp2YFjSTM67QONQ8CdmfqokqJ8/3RyrpDvGN3iX3yzBqXGO
jPkoJQv3I4lsYdR0nl4obHHnMSeWCQCYvJoZ7ZOliu/Dd0ksItlodG6s8r/ujkSa8VIhe0fnXTf0
i7lqa55CAByGN4MOR0bAkJwIB7nZzQKurBPcTAYJFFvAc5hgMnWT0XW83TehAoGBALVPGnznScUw
O50OXKI5yhxGf/XDT8g28L8Oc4bctRzI+8YfIFfLJ57uDGuojO/BpqtYmXmgORru0jYR8idEkZrx
gf62czOiJrCWTkBCEMtrNfFHQJQCQrjfbHofp7ODnEHbHFm7zdlbfNnEBBaKXxd2rVv4UTEhgftv
wsHcimbXAoGBAIViWrHWElMeQT0datqlThE/u51mcK4VlV7iRWXVa1/gAP85ZAu44VvvDlkpYVkF
zSRR+lHSOzsubDMN45OBQW6UA3RPg4TCvrTOmhQUeF5XPuSdcD0R2At6pdaLwAKnOtILg13Ha6ym
Igjv8glodvem3hWLmpHIhNBiaXtf8wqpAoGADH5a8OhvKOtd8EChGXyp9LDW+HRw9vbyN/gi9dQX
ltgyoUBb1jDllgoJSRHgRFUvyvbb/ImR5c03JwqtiQ8siWTC9G5WGeS+jcSNt9fVmG7W1L14MbrG
Jj8fFns/7xrOlasnlPdgA+5N+CONtI/sZY2D/KZr0drhPhZBcWJlFxkCgYAn+4SOPEo/6hjKNhA6
vER7fSxDEVsDg+rDh3YgAWpvUdlaqBxqOyAqi600YugQZGHK2lv7vNYOdmrunuIx7BPuDqY+bjtR
R4Mc9bVQAZbXSLXMl7j2RWwKfNhLSJbk9LX4EoVtTgLjvOUE4tAdq9fFgpqdwLwzqPTO9kECP4++
CQKBgH6tO/xcNxG/uXUideluAn3H2KeyyznZMJ7oCvzf26/XpTAMI243OoeftiKVMgxuZ7hjwqfn
/VHXABc4i5gchr9RzSb1hZ/IqFzq2YGmbppg5Ok2cgwalDoDBi21bRf8aDRweL62mO+7aPnCQZ58
j5W72PB8BAr6xg0Oro25O4os
-----END RSA PRIVATE KEY-----

此处已发布了类似的问题,但这些问题对我来说无济于事。 几乎所有人都建议使用 Bouncycastle 提供商,但他们不愿意使用,因为我应该使用符合 FIPS 的提供商,但不确定 BC 提供商是否符合 FIPS。

非常感谢您帮助我摆脱困境... 提前致谢。

【问题讨论】:

1) 代码 sn-p 在哪里?2) 为什么不使用 Bouncy Castle? @user384706 我不确定 Bouncycastle 是否符合 fips。所以我正在使用 IBMJCEFIPS 提供程序。 BC 提供程序不符合 FIPS。您的 PEM 文件的第一行是什么,以“-----BEGIN”开头的行? @GregS private.key文件的第一行是-----BEGIN RSA PRIVATE KEY----- @Greg,不用担心密钥只是用于测试:D 【参考方案1】:

对于正在寻找更简单的方法将 RSAPrivateKey 转换为 PrivateKey 的人,BouncyCastle 有一个 KeyUtil 来执行此操作。

  RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(pkcs1Bytes)
  byte[] privateKeyInfoBytes = KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), rsaPrivateKey);
  PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfoBytes);
  PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);

如果 PKCS1 PEM 输入使用 AES 256 CBC 加密,则可以使用 JcePemDecryptorProvider 对其进行解密

PEMDecryptor decryptor = new JcePEMDecryptorProviderBuilder().build("password").get("AES-256-CBC");
byte[] decrypted = decryptor.decrypt(pkcs1Bytes, iv);

【讨论】:

【参考方案2】:

您将在下面找到一些用于读取以下列格式编码的未加密 RSA 密钥的代码:

PKCS#1 PEM (-----BEGIN RSA PRIVATE KEY-----) PKCS#8 PEM (-----BEGIN PRIVATE KEY-----) PKCS#8 DER(二进制)

它适用于 Java 7+(以及 9 之后),并且不使用第三方库(如 BouncyCastle)或内部 Java API(如DerInputStreamDerValue)。

private static final String PKCS_1_PEM_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
private static final String PKCS_1_PEM_FOOTER = "-----END RSA PRIVATE KEY-----";
private static final String PKCS_8_PEM_HEADER = "-----BEGIN PRIVATE KEY-----";
private static final String PKCS_8_PEM_FOOTER = "-----END PRIVATE KEY-----";

public static PrivateKey loadKey(String keyFilePath) throws GeneralSecurityException, IOException 
    byte[] keyDataBytes = Files.readAllBytes(Paths.get(keyFilePath));
    String keyDataString = new String(keyDataBytes, StandardCharsets.UTF_8);

    if (keyDataString.contains(PKCS_1_PEM_HEADER)) 
        // OpenSSL / PKCS#1 Base64 PEM encoded file
        keyDataString = keyDataString.replace(PKCS_1_PEM_HEADER, "");
        keyDataString = keyDataString.replace(PKCS_1_PEM_FOOTER, "");
        return readPkcs1PrivateKey(Base64.decodeBase64(keyDataString));
    

    if (keyDataString.contains(PKCS_8_PEM_HEADER)) 
        // PKCS#8 Base64 PEM encoded file
        keyDataString = keyDataString.replace(PKCS_8_PEM_HEADER, "");
        keyDataString = keyDataString.replace(PKCS_8_PEM_FOOTER, "");
        return readPkcs8PrivateKey(Base64.decodeBase64(keyDataString));
    

    // We assume it's a PKCS#8 DER encoded binary file
    return readPkcs8PrivateKey(Files.readAllBytes(Paths.get(keyFilePath)));


private static PrivateKey readPkcs8PrivateKey(byte[] pkcs8Bytes) throws GeneralSecurityException 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign");
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes);
    try 
        return keyFactory.generatePrivate(keySpec);
     catch (InvalidKeySpecException e) 
        throw new IllegalArgumentException("Unexpected key format!", e);
    


private static PrivateKey readPkcs1PrivateKey(byte[] pkcs1Bytes) throws GeneralSecurityException 
    // We can't use Java internal APIs to parse ASN.1 structures, so we build a PKCS#8 key Java can understand
    int pkcs1Length = pkcs1Bytes.length;
    int totalLength = pkcs1Length + 22;
    byte[] pkcs8Header = new byte[] 
            0x30, (byte) 0x82, (byte) ((totalLength >> 8) & 0xff), (byte) (totalLength & 0xff), // Sequence + total length
            0x2, 0x1, 0x0, // Integer (0)
            0x30, 0xD, 0x6, 0x9, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0, // Sequence: 1.2.840.113549.1.1.1, NULL
            0x4, (byte) 0x82, (byte) ((pkcs1Length >> 8) & 0xff), (byte) (pkcs1Length & 0xff) // Octet string + length
    ;
    byte[] pkcs8bytes = join(pkcs8Header, pkcs1Bytes);
    return readPkcs8PrivateKey(pkcs8bytes);


private static byte[] join(byte[] byteArray1, byte[] byteArray2)
    byte[] bytes = new byte[byteArray1.length + byteArray2.length];
    System.arraycopy(byteArray1, 0, bytes, 0, byteArray1.length);
    System.arraycopy(byteArray2, 0, bytes, byteArray1.length, byteArray2.length);
    return bytes;

来源:https://github.com/Mastercard/client-encryption-java/blob/master/src/main/java/com/mastercard/developer/utils/EncryptionUtils.java

【讨论】:

这看起来是最好的解决方案。它有什么缺点吗?像这样简单地将 PKCS1 密钥转换为 PKCS8 是否安全? "它有什么缺点吗?" @krishnaTelgave,最好的判断方法是使用您的应用程序应该处理的数据对该代码进行单元测试【参考方案3】:

您刚刚发布了该私钥,所以现在全世界都知道它是什么了。希望这只是为了测试。

编辑:Others 注意到已发布密钥的 openssl 文本标头 -----BEGIN RSA PRIVATE KEY----- 表明它是 PKCS#1。但是,相关密钥的实际 Base64 内容是 PKCS#8。显然,出于某种未知原因,OP 将 PKCS#1 密钥的标题和尾部复制并粘贴到 PKCS#8 密钥上。我在下面提供的示例代码适用于 PKCS#8 私钥。

这里有一些代码将根据该数据创建私钥。您必须将 Base64 解码替换为 IBM Base64 解码器。

public class RSAToy 

    private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\n"
            + "MIIEuwIBADAN ...skipped the rest\n"
         // + ...   
         // + ... skipped the rest
         // + ...   
            + "-----END RSA PRIVATE KEY-----";

    public static void main(String[] args) throws Exception 

        // Remove the first and last lines

        String privKeyPEM = BEGIN_RSA_PRIVATE_KEY.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
        privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
        System.out.println(privKeyPEM);

        // Base64 decode the data

        byte [] encoded = Base64.decode(privKeyPEM);

        // PKCS8 decode the encoded RSA private key

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privKey = kf.generatePrivate(keySpec);

        // Display the results

        System.out.println(privKey);
    

【讨论】:

@Venkat Madhav:我知道您必须使用 IBM JDK。我建议您使用 Oracle JDK 测试您的代码,只是为了缩小问题所在。如果您的代码适用于 Oracle JDK,那么我们知道我们有一个 IBM JDK 问题需要解决。但是,如果它不适用于 Oracle JDK,那么我们知道问题出在您的代码中,而不是在 IBM JDK 中。 我收到此错误:java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source) at java.security.KeyFactory.generatePrivate(Unknown Source) @GregS,这是一段不错的代码,但我不相信-----BEGIN RSA PRIVATE KEY----- 表示 PKCS8 格式的密钥。据我了解,这些是 SSLeay 格式,这会导致某些用户出现错误。看我的回答:***.com/a/22218774/1554386 @AlastairMcCormack:感谢您的评论。我没有注意标题和预告片,只是里面的东西显然是 PKCS#8 编码的。要查看此内容,只需将其粘贴到您最喜欢的 ASN.1 解码器中即可。我喜欢lapo.it。也许OP从不同类型的文件中剪切并粘贴了不同的标题?如果是这样,那会误导其他人,因此非常感谢您的评论。 @Nepoxx:我使用的bouncycastle base64 decoder 忽略了空格。【参考方案4】:

确保您的 id_rsa 文件没有任何扩展名,例如 .txt 或 .rtf。富文本格式会在您的文件中添加额外的字符,并将这些字符添加到字节数组中。最终导致无效的私钥错误。长话短说,复制文件,而不是内容。

【讨论】:

【参考方案5】:

正如其他人所回应的那样,您尝试解析的密钥没有 Oracle 的 PKCS8EncodedKeySpec 需要理解的正确 PKCS#8 标头。如果您不想使用 openssl pkcs8 转换密钥或使用 JDK 内部 API 解析它,您可以像这样预先添加 PKCS#8 标头:

static final Base64.Decoder DECODER = Base64.getMimeDecoder();

private static byte[] buildPKCS8Key(File privateKey) throws IOException 
  final String s = new String(Files.readAllBytes(privateKey.toPath()));
  if (s.contains("--BEGIN PRIVATE KEY--")) 
    return DECODER.decode(s.replaceAll("-----\\w+ PRIVATE KEY-----", ""));
  
  if (!s.contains("--BEGIN RSA PRIVATE KEY--")) 
    throw new RuntimeException("Invalid cert format: "+ s);
  

  final byte[] innerKey = DECODER.decode(s.replaceAll("-----\\w+ RSA PRIVATE KEY-----", ""));
  final byte[] result = new byte[innerKey.length + 26];
  System.arraycopy(DECODER.decode("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKY="), 0, result, 0, 26);
  System.arraycopy(BigInteger.valueOf(result.length - 4).toByteArray(), 0, result, 2, 2);
  System.arraycopy(BigInteger.valueOf(innerKey.length).toByteArray(), 0, result, 24, 2);
  System.arraycopy(innerKey, 0, result, 26, innerKey.length);
  return result;

一旦该方法到位,您可以将其输出提供给PKCS8EncodedKeySpec 构造函数,如下所示:new PKCS8EncodedKeySpec(buildPKCS8Key(privateKey));

【讨论】:

但这不会将 PKCS#1 数据更改为 PKCS#8。 @user207421:是的。 base64 blob 是外部标记 & (dummy) len、版本、RSA 的算法标识符和内部标记 & (dummy) len,在更正 len 字段后,使 PKCS1-private 变为 PKCS8-RSA。【参考方案6】:

这是私钥的 PKCS#1 格式。试试这个代码。它不使用 Bouncy Castle 或其他第三方加密提供商。仅用于 DER 序列解析的 java.security 和 sun.security。它还支持解析 PKCS#8 格式的私钥(PEM 文件的标题为“-----BEGIN PRIVATE KEY-----”)。

import sun.security.util.DerInputStream;
import sun.security.util.DerValue;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.Base64;

public static PrivateKey pemFileLoadPrivateKeyPkcs1OrPkcs8Encoded(File pemFileName) throws GeneralSecurityException, IOException 
        // PKCS#8 format
        final String PEM_PRIVATE_START = "-----BEGIN PRIVATE KEY-----";
        final String PEM_PRIVATE_END = "-----END PRIVATE KEY-----";

        // PKCS#1 format
        final String PEM_RSA_PRIVATE_START = "-----BEGIN RSA PRIVATE KEY-----";
        final String PEM_RSA_PRIVATE_END = "-----END RSA PRIVATE KEY-----";

        Path path = Paths.get(pemFileName.getAbsolutePath());

        String privateKeyPem = new String(Files.readAllBytes(path));

        if (privateKeyPem.indexOf(PEM_PRIVATE_START) != -1)  // PKCS#8 format
            privateKeyPem = privateKeyPem.replace(PEM_PRIVATE_START, "").replace(PEM_PRIVATE_END, "");
            privateKeyPem = privateKeyPem.replaceAll("\\s", "");

            byte[] pkcs8EncodedKey = Base64.getDecoder().decode(privateKeyPem);

            KeyFactory factory = KeyFactory.getInstance("RSA");
            return factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));

         else if (privateKeyPem.indexOf(PEM_RSA_PRIVATE_START) != -1)   // PKCS#1 format

            privateKeyPem = privateKeyPem.replace(PEM_RSA_PRIVATE_START, "").replace(PEM_RSA_PRIVATE_END, "");
            privateKeyPem = privateKeyPem.replaceAll("\\s", "");

            DerInputStream derReader = new DerInputStream(Base64.getDecoder().decode(privateKeyPem));

            DerValue[] seq = derReader.getSequence(0);

            if (seq.length < 9) 
                throw new GeneralSecurityException("Could not parse a PKCS1 private key.");
            

            // skip version seq[0];
            BigInteger modulus = seq[1].getBigInteger();
            BigInteger publicExp = seq[2].getBigInteger();
            BigInteger privateExp = seq[3].getBigInteger();
            BigInteger prime1 = seq[4].getBigInteger();
            BigInteger prime2 = seq[5].getBigInteger();
            BigInteger exp1 = seq[6].getBigInteger();
            BigInteger exp2 = seq[7].getBigInteger();
            BigInteger crtCoef = seq[8].getBigInteger();

            RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);

            KeyFactory factory = KeyFactory.getInstance("RSA");

            return factory.generatePrivate(keySpec);
        

        throw new GeneralSecurityException("Not supported format of a private key");
    

【讨论】:

DerInputStreamDerValue 从 JDK 9 开始不再可用。【参考方案7】:

您将面临的问题是 PEM 格式的密钥有两种类型:PKCS8 和 SSLeay。 OpenSSL 似乎根据命令同时使用两者并没有帮助:

通常的openssl genrsa 命令将生成 SSLeay 格式的 PEM。使用 openssl pkcs12 -in file.p12 从 PKCS12 文件导出将创建一个 PKCS8 文件。

后一种 PKCS8 格式可以使用 PKCS8EncodedKeySpec 在 Java 中本地打开。另一方面,SSLeay 格式的密钥无法在本地打开。

要打开 SSLeay 私钥,您可以像以前一样使用 BouncyCastle 提供程序,也可以使用 Not-Yet-Commons-SSL 从 BouncyCastle 借用最少的必要代码来支持解析 PEM 和 DER 格式的 PKCS8 和 SSLeay 密钥:http://juliusdavies.ca/commons-ssl/pkcs8.html。 (我不确定 Not-Yet-Commons-SSL 是否符合 FIPS)

密钥格式识别

从 OpenSSL 手册页推断,两种格式的关键标头如下:

PKCS8 格式

未加密:-----BEGIN PRIVATE KEY----- 加密:-----BEGIN ENCRYPTED PRIVATE KEY-----

SSLeay 格式

-----BEGIN RSA PRIVATE KEY-----

(这些似乎与其他答案相矛盾,但我已经使用 PKCS8EncodedKeySpec 测试了 OpenSSL 的输出。只有 PKCS8 密钥,显示 ----BEGIN PRIVATE KEY----- 在本机工作)

【讨论】:

我相信您可以使用 openssl 命令将“原始”密钥转换为等效的 PKCS8 输出。尝试类似 openssl pkcs8 -topk8 非常感谢您分享您对 PEM 文件的观察。可能需要一段时间才能弄清楚。【参考方案8】:

解析 PKCS1(android 上只有 PKCS8 格式可以开箱即用)密钥在 Android 上被证明是一项繁琐的任务,因为缺乏 ASN1 支持,但如果您包含 Spongy castle jar 来读取 DER 整数,则可以解决。

String privKeyPEM = key.replace(
"-----BEGIN RSA PRIVATE KEY-----\n", "")
    .replace("-----END RSA PRIVATE KEY-----", "");

// Base64 decode the data

byte[] encodedPrivateKey = Base64.decode(privKeyPEM, Base64.DEFAULT);

try 
    ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence
        .fromByteArray(encodedPrivateKey);
    Enumeration<?> e = primitive.getObjects();
    BigInteger v = ((DERInteger) e.nextElement()).getValue();

    int version = v.intValue();
    if (version != 0 && version != 1) 
        throw new IllegalArgumentException("wrong version for RSA private key");
    
    /**
     * In fact only modulus and private exponent are in use.
     */
    BigInteger modulus = ((DERInteger) e.nextElement()).getValue();
    BigInteger publicExponent = ((DERInteger) e.nextElement()).getValue();
    BigInteger privateExponent = ((DERInteger) e.nextElement()).getValue();
    BigInteger prime1 = ((DERInteger) e.nextElement()).getValue();
    BigInteger prime2 = ((DERInteger) e.nextElement()).getValue();
    BigInteger exponent1 = ((DERInteger) e.nextElement()).getValue();
    BigInteger exponent2 = ((DERInteger) e.nextElement()).getValue();
    BigInteger coefficient = ((DERInteger) e.nextElement()).getValue();

    RSAPrivateKeySpec spec = new RSAPrivateKeySpec(modulus, privateExponent);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey pk = kf.generatePrivate(spec);
 catch (IOException e2) 
    throw new IllegalStateException();
 catch (NoSuchAlgorithmException e) 
    throw new IllegalStateException(e);
 catch (InvalidKeySpecException e) 
    throw new IllegalStateException(e);

【讨论】:

海绵城堡和充气城堡的罐子不符合 FIPS,事实上我很久以前就研究过充气城堡的供应商,但它不符合我的要求,因为它不符合 FIPS。 @VenkatMadhav DER 不是加密标准 - 它是编码标准。 在相关问题上,有任何处理 SSH 公钥的例子吗?我猜只需要更改 3 行。从公钥文件(“~/.ssh/id_rsa.pub”)、“kf.generatePublic”和“spec = new RSAPublicKeySpec(modulus, publicExponent);”中读取? 整晚都在努力解决这个问题(之前也尝试过几次)。虽然与现代 Java 标准相比丑陋,但这是迄今为止读取 SSL 私钥的最佳方式(例如 ~/.ssh/id_rsa 问题中实际列出的key是PKCS#8,这段代码不会解析。

以上是关于从 PEM BASE64 编码的私钥文件中获取 RSA 私钥的主要内容,如果未能解决你的问题,请参考以下文章

1:RSA 加密 .pem .csr .crt .der .p12文件的区别 base64

如何在不使用 OpenSSL 的情况下使用私钥导出 base64 编码的 x.509 证书

OpenSSL生成公私钥

使用openssl命令从.p12文件中提取证书和私钥。

iOS RSA加密生成公钥私钥

base64编码解码