【问题标题】:Read an encrypted private key with bouncycastle/spongycastle使用 bouncycastle/spongycastle 读取加密的私钥
【发布时间】:2014-05-20 03:37:56
【问题描述】:

我有一个受密码保护的加密 RSA 私钥,它是使用 PyCrypto (2.6.1) 创建的,根据他们的文档具有以下格式:PrivateKeyInfo, PKCS#8 (DER SEQUENCE), PEM (RFC1423),请参阅 [https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html#exportKey].

如何使用 Bouncycastle/Spongycastle 解密此 RSA 密钥?

我已经在 Google 上搜索了很长时间,但只得出了一些结果,要么不适用于 1.50 版(因为 PEMReader 已被弃用并被删除),要么是 PEMParser 的示例似乎无法阅读此内容格式。顺便说一句:我错过了关于 Bouncycastle 的任何文件吗?

这是我的加密私钥的标头:

-----BEGIN PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,68949227DD8A502D
xyz...

如果有人能帮助我,我真的很感激!

【问题讨论】:

  • 这是加密密钥(具有 CBC 模式和输入向量 68949227DD8A502D 的 TripleDES)。因此,在 PEMReader 可以读取之前,必须先对其进行解密。
  • 请注意,密钥是使用旧的(且不安全的)算法加密的。当前的做法是使用 PKCS#8 来保护私钥。 Bouncy Castle 在 JceOpenSSLPKCS8DecryptorProviderBuilder 类中支持 PKCS#8 解密。

标签: java rsa bouncycastle pem pkcs#8


【解决方案1】:

使用this question 的答案,您应该执行以下操作

File privateKeyFile = new File(privateKeyFileName); // private key file in PEM format
PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile));
Object object = pemParser.readObject();
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair kp;
if (object instanceof PEMEncryptedKeyPair) {
    kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
}

那你可以说

PrivateKey key = kp.getPrivateKey();

【讨论】:

    【解决方案2】:

    总结一下我在herethere这个话题上的发现:

    如果你想获得模数,这里是最终代码:

    import java.io.FileReader;
    import java.security.Security;
    import java.security.KeyFactory
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    // Note that you need to add 'pkix' package. e.g. 'org.bouncycastle:bcpkix-jdk15on'
    import org.bouncycastle.openssl.PEMEncryptedKeyPair;
    import org.bouncycastle.openssl.PEMParser;
    import org.bouncycastle.openssl.PEMDecryptorProvider;
    import org.bouncycastle.openssl.PEMKeyPair;
    import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
    import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
    
    // For JcaPEMKeyConverter().setProvider("BC")
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    
    // Using bcpkix-jdk14-1.48
    PEMParser pemParser = new PEMParser(new FileReader(file));
    Object object = pemParser.readObject();
    JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
    KeyPair kp;
    if (object instanceof PEMEncryptedKeyPair)
    {
        // Encrypted key - we will use provided password
        PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) object;
        PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
        kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
    }
    else
    {
        // Unencrypted key - no password needed
        PEMKeyPair ukp = (PEMKeyPair) object;
        kp = converter.getKeyPair(ukp);
    }
    
    // RSA
    KeyFactory keyFac = KeyFactory.getInstance("RSA");
    RSAPrivateCrtKeySpec privateKey = keyFac.getKeySpec(kp.getPrivate(), RSAPrivateCrtKeySpec.class);
    
    return privateKey;
    

    然后你可以调用例如:

    privateKey.getModulus();
    

    【讨论】:

    • 解析出来的PEM对象也可以是PrivateKeyInfo,用converter.getPrivateKey((PrivateKeyInfo) object);获取私钥
    【解决方案3】:

    以下静态方法将处理加密私钥的以下所有 PEM 编码样式:

    -----BEGIN ENCRYPTED PRIVATE KEY-----
    -----BEGIN PRIVATE KEY-----
    -----BEGIN EC PRIVATE KEY-----
    

    首先确保您已将 BC 注册为安全提供商,然后您可以使用此方法:

      static public PrivateKey stringToPrivateKey(String s, String password)
          throws IOException, PKCSException {
    
        PrivateKeyInfo pki;
    
        try (PEMParser pemParser = new PEMParser(new StringReader(s))) {
    
          Object o = pemParser.readObject();
    
          if (o instanceof PKCS8EncryptedPrivateKeyInfo) {
    
            PKCS8EncryptedPrivateKeyInfo epki = (PKCS8EncryptedPrivateKeyInfo) o;
    
            JcePKCSPBEInputDecryptorProviderBuilder builder =
                new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(bc);
    
            InputDecryptorProvider idp = builder.build(password.toCharArray());
    
            pki = epki.decryptPrivateKeyInfo(idp);
          } else if (o instanceof PEMEncryptedKeyPair) {
    
            PEMEncryptedKeyPair epki = (PEMEncryptedKeyPair) o;
            PEMKeyPair pkp = epki.decryptKeyPair(new BcPEMDecryptorProvider(password.toCharArray()));
    
            pki = pkp.getPrivateKeyInfo();
          } else {
            throw new PKCSException("Invalid encrypted private key class: " + o.getClass().getName());
          }
    
          JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(bc);
          return converter.getPrivateKey(pki);
        }
      }
    

    【讨论】:

      【解决方案4】:
         //https://stackoverflow.com/questions/7216969/getting-rsa-private-key-from-pem-base64-encoded-private-key-file
      //https://stackoverflow.com/questions/5271189/how-to-convert-a-pkcs8-encoded-rsa-key-into-pkcs1-in-java
      //https://stackoverflow.com/questions/22920131/read-an-encrypted-private-key-with-bouncycastle-spongycastle
      private static void decrypt() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
          // For JcaPEMKeyConverter().setProvider("BC")
          Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
          String caPrivateKeyFname = "E:\\xxx\\key.pem";
      
          FileInputStream fis = null;
          try {
              fis = new FileInputStream(caPrivateKeyFname);
          } catch (FileNotFoundException e) {
              e.printStackTrace();
          }
      
          //Load and parse PEM object
          PEMParser pemParser = new PEMParser(new InputStreamReader(fis));
          Object object = pemParser.readObject();
          JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
          KeyPair kp;
          //password
          String pwd = "typePassword";
          if (object instanceof PEMEncryptedKeyPair) {
              // Encrypted key - we will use provided password
              PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) object;
              PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(pwd.toCharArray());
              kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
          } else {
              // Unencrypted key - no password needed
              PEMKeyPair ukp = (PEMKeyPair) object;
              kp = converter.getKeyPair(ukp);
          }
          // RSA
          KeyFactory keyFac = KeyFactory.getInstance("RSA");
          RSAPrivateCrtKeySpec privateKey = keyFac.getKeySpec(kp.getPrivate(), RSAPrivateCrtKeySpec.class);
      
          PrivateKey privateKey1 = keyFac.generatePrivate(privateKey);
          //This is the same as the output below
          Base64Encoder.encode(privateKey1.getEncoded());
      
          PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey1.getEncoded());
          ASN1Encodable privateKeyPKCS1ASN1Encodable = pkInfo.parsePrivateKey();
          ASN1Primitive privateKeyPKCS1ASN1 = privateKeyPKCS1ASN1Encodable.toASN1Primitive();
          SONBASE64Encoder encoder = new SONBASE64Encoder();
          System.out.println(encoder.encode(privateKeyPKCS1ASN1.getEncoded()));
      
      }
      

      上面的代码应该解决了解密问题,把pkcs8编码的rsa-key放入pkcs1

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-13
        • 1970-01-01
        • 2015-03-21
        • 2018-09-30
        • 2013-12-14
        • 1970-01-01
        • 1970-01-01
        • 2015-07-29
        相关资源
        最近更新 更多