使用 Java 解密 OpenSSL PEM 编码的 RSA 私钥?

2024-04-07

我有一个加密的私钥并且我知道密码。

我需要使用 Java 库对其进行解密。

不过,除非没有其他选择,否则我不想使用 BouncyCastle。根据以往的经验,改动太多,文档不够。

私钥的形式如下:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,56F3A98D9CFFA77A

X5h7SUDStF1tL16lRM+AfZb1UBDQ0D1YbQ6vmIlXiK....
.....
/KK5CZmIGw==
-----END RSA PRIVATE KEY-----

我相信关键数据是 Base64 编码的,因为我看到\r\n64 个字符之后。

我尝试了以下方法来解密密钥:

import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public String decrypt(String keyDataStr, String passwordStr){
  // This key data start from "X5... to ==" 
  char [] password=passwordStr.toCharArray();
  byte [] keyDataBytes=com.sun.jersey.core.util.Base64.decode(keyDataStr);

  PBEKeySpec pbeSpec = new PBEKeySpec(password);
  EncryptedPrivateKeyInfo pkinfo = new EncryptedPrivateKeyInfo(keyDataBytes);
  SecretKeyFactory skf = SecretKeyFactory.getInstance(pkinfo.getAlgName());
  Key secret = skf.generateSecret(pbeSpec);
  PKCS8EncodedKeySpec keySpec = pkinfo.getKeySpec(secret);
  KeyFactory kf = KeyFactory.getInstance("RSA");
  PrivateKey pk=kf.generatePrivate(keySpec);
  return pk.toString();
}

我得到这个异常

java.io.IOException: DerInputStream.getLength(): lengthTag=50, too big.
    at sun.security.util.DerInputStream.getLength(DerInputStream.java:561)
    at sun.security.util.DerValue.init(DerValue.java:365)
    at sun.security.util.DerValue.<init>(DerValue.java:294)
    at javax.crypto.EncryptedPrivateKeyInfo.<init> (EncryptedPrivateKeyInfo.java:84)

我是否将正确的参数传递给EncryptedPrivateKeyInfo构造函数?

我怎样才能做到这一点?

我尝试了 Ericsonn 的建议,自从我使用 Java 7 以来,做了一个小小的更改,我无法使用 Base64.getMimeCoder() 而是使用 Base64.decode ,并且收到此错误 在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:750) 处使用填充密码进行解密时,我收到这样的错误:输入长度必须是 8 的倍数

static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
            throws GeneralSecurityException, UnsupportedEncodingException
          {
            byte[] pw = password.getBytes(StandardCharsets.UTF_8);
            byte[] iv = h2b(ivHex);
            SecretKey secret = opensslKDF(pw, iv);
            Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
            byte [] keyBytes=Base64.decode(keyDataStr.getBytes("UTF-8"));
            byte[] pkcs1 = cipher.doFinal(keyBytes);
            /* See note for definition of "decodeRSAPrivatePKCS1" */
            RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
            KeyFactory rsa = KeyFactory.getInstance("RSA");
            return (RSAPrivateKey) rsa.generatePrivate(spec);
          }

          private static SecretKey opensslKDF(byte[] pw, byte[] iv)
            throws NoSuchAlgorithmException
          {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(pw);
            md5.update(iv);
            byte[] d0 = md5.digest();
            md5.update(d0);
            md5.update(pw);
            md5.update(iv);
            byte[] d1 = md5.digest();
            byte[] key = new byte[24];
            System.arraycopy(d0, 0, key, 0, 16);
            System.arraycopy(d1, 0, key, 16, 8);
            return new SecretKeySpec(key, "DESede");
          }

          private static byte[] h2b(CharSequence s)
          {
            int len = s.length();
            byte[] b = new byte[len / 2];
            for (int src = 0, dst = 0; src < len; ++dst) {
              int hi = Character.digit(s.charAt(src++), 16);
              int lo = Character.digit(s.charAt(src++), 16);
              b[dst] = (byte) (hi << 4 | lo);
            }
            return b;
          }
          static RSAPrivateCrtKeySpec decodeRSAPrivatePKCS1(byte[] encoded)
          {
            ByteBuffer input = ByteBuffer.wrap(encoded);
            if (der(input, 0x30) != input.remaining())
              throw new IllegalArgumentException("Excess data");
            if (!BigInteger.ZERO.equals(derint(input)))
              throw new IllegalArgumentException("Unsupported version");
            BigInteger n = derint(input);
            BigInteger e = derint(input);
            BigInteger d = derint(input);
            BigInteger p = derint(input);
            BigInteger q = derint(input);
            BigInteger ep = derint(input);
            BigInteger eq = derint(input);
            BigInteger c = derint(input);
            return new RSAPrivateCrtKeySpec(n, e, d, p, q, ep, eq, c);
          }

          private static BigInteger derint(ByteBuffer input)
          {
            byte[] value = new byte[der(input, 0x02)];
            input.get(value);
            return new BigInteger(+1, value);
          }


          private static int der(ByteBuffer input, int exp)
          {
            int tag = input.get() & 0xFF;
            if (tag != exp)
              throw new IllegalArgumentException("Unexpected tag");
            int n = input.get() & 0xFF;
            if (n < 128)
              return n;
            n &= 0x7F;
            if ((n < 1) || (n > 2))
              throw new IllegalArgumentException("Invalid length");
            int len = 0;
            while (n-- > 0) {
              len <<= 8;
              len |= input.get() & 0xFF;
            }
            return len;
          }

1640 是 keyDataStr.length() ,1228 是 keyBytes.length


您需要使用非标准的 OpenSSL 方法来派生解密密钥。然后用它来解密 PKCS-#1 编码的密钥 - 您正在使用的是notPKCS #8 信封。您还需要标头中的 IV 作为这些流程的输入。

它看起来像这样:

  static RSAPrivateKey decrypt(String keyDataStr, String ivHex, String password)
    throws GeneralSecurityException
  {
    byte[] pw = password.getBytes(StandardCharsets.UTF_8);
    byte[] iv = h2b(ivHex);
    SecretKey secret = opensslKDF(pw, iv);
    Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    byte[] pkcs1 = cipher.doFinal(Base64.getMimeDecoder().decode(keyDataStr));
    /* See note for definition of "decodeRSAPrivatePKCS1" */
    RSAPrivateCrtKeySpec spec = decodeRSAPrivatePKCS1(pkcs1);
    KeyFactory rsa = KeyFactory.getInstance("RSA");
    return (RSAPrivateKey) rsa.generatePrivate(spec);
  }

  private static SecretKey opensslKDF(byte[] pw, byte[] iv)
    throws NoSuchAlgorithmException
  {
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    md5.update(pw);
    md5.update(iv);
    byte[] d0 = md5.digest();
    md5.update(d0);
    md5.update(pw);
    md5.update(iv);
    byte[] d1 = md5.digest();
    byte[] key = new byte[24];
    System.arraycopy(d0, 0, key, 0, 16);
    System.arraycopy(d1, 0, key, 16, 8);
    return new SecretKeySpec(key, "DESede");
  }

  private static byte[] h2b(CharSequence s)
  {
    int len = s.length();
    byte[] b = new byte[len / 2];
    for (int src = 0, dst = 0; src < len; ++dst) {
      int hi = Character.digit(s.charAt(src++), 16);
      int lo = Character.digit(s.charAt(src++), 16);
      b[dst] = (byte) (hi << 4 | lo);
    }
    return b;
  }

这已经是很多代码了,所以我将链接到定义的另一个答案the decodeRSAPrivatePKCS1() method. https://stackoverflow.com/a/19435226/3474

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Java 解密 OpenSSL PEM 编码的 RSA 私钥? 的相关文章

  • JPA 中的复合键

    我想创建一个具有自动生成的主键的实体 而且还有一个由其他两个字段组成的唯一复合键 我如何在 JPA 中执行此操作 我想这样做是因为主键应该用作另一个表中的外键 并且使其复合并不好 在下面的代码片段中 我需要命令和模型是唯一的 pk当然是主键
  • 在 JavaScript 中生成 RSA 密钥对

    我最近发现了这个 RSA JavaScript 库 http www ohdave com rsa http www ohdave com rsa 但是 它要求预先生成密钥 这是我的问题 问题 我想在 JavaScript 中生成 RSA
  • Java Runtime.getRuntime().freeMemory() 问题

    我搜索并看到了一些线程 但没有一个能够解决我遇到的具体问题 我正在尝试使用以下方式监视我的内存使用情况Runtime getRuntime freeMemory Runtime getRuntime maxMemory and Runtim
  • 使用 Ant 将非代码资源添加到 jar 文件

    我正在将 java 应用程序打包成 jar 文件 我正在使用 ant 和 eclipse 我实际上需要在 jar 中直接在根文件夹下包含几个单独的非代码文件 xml 和 txt 文件 而不是与代码位于同一位置 我正在尝试使用includes
  • Spring Boot自动装配存储库始终为空[重复]

    这个问题在这里已经有答案了 每次我进入我的服务类时 存储库似乎都没有自动连接 因为它不断抛出 NullPointerException 谁能帮我检查一下我缺少什么吗 这是我的代码 演示应用程序 java package com exampl
  • 当客户端关闭连接时,Spring StreamingResponseBody 请求线程未清理

    我在控制器中有一个端点 它返回一个StreamingResponseBody 用于向客户端发送文件 其代码大致如下 RestController RequestMapping value api public class Controlle
  • 使用 JUnit 时,有没有办法验证测试方法中是否调用了 try/catch 指令的 Catch 部分?

    例如 如果我想测试以下课程 public class SomeClass public void someMethod try Some code where comething could go wrong catch Exception
  • Spring Security SAML2 使用 G Suite 作为 Idp

    我正在尝试使用 Spring Security 5 3 3 RELEASE 来处理 Spring Boot 应用程序中的 SAML2 身份验证 Spring Boot 应用程序将成为 SP G Suite 将成为 IDP 在我的 Maven
  • crypto++ / pycrypto 与谷歌应用程序引擎

    我正在使用 crypto 将 AES 加密的 http 请求发送到应用程序引擎 计划在那里解密它们 我的计划是加密 之后的部分所以它是这样的 http myurl com Command eiwjfsdlfjldkjfs http myur
  • 套接字的读写如何同步?

    我们创建一个套接字 在套接字的一侧有一个 服务器 在另一侧有一个 客户端 服务器和客户端都可以向套接字写入和读取 这是我的理解 我不明白以下事情 如果服务器从套接字读取数据 它在套接字中是否只看到客户端写入套接字的内容 我的意思是 如果服务
  • 使用 Guice 优化注册表

    你好 今天思考了一种优化 有一些疑问 语境 我正在使用 Guice 2 进行 Java 开发 在我的网络应用程序中 我有一个转换器注册表 可以即时转换为某种类型 转换器描述如下 public class StringToBoolean im
  • GWT 2.3 开发模式 - 托管模式 JSP 编译似乎不使用 java 1.5 兼容性

    无法编译 JSP 类 生成的 servlet 错误 DefaultMessage 上次更新 0 日期 中 0 时间 HH mm ss z 语法 错误 注释仅在源级别为 1 5 时可用 在尝试以开发模式在 Web 浏览器中打开我的 gwt 模
  • Freemarker 和 Struts 2,有时它计算为序列+扩展哈希

    首先我要说的是 使用 Struts2 Freemarker 真是太棒了 然而有些事情让我发疯 因为我不明白为什么会发生这种情况 我在这里问是因为也许其他人有一个想法可以分享 我有一个动作 有一个属性 说 private String myT
  • 使用架构注册表对 avro 消息进行 Spring 云合约测试

    我正在查看 spring 文档和 spring github 我可以看到一些非常基本的内容examples https github com spring cloud samples spring cloud contract sample
  • 如何在 Java 中创建接受多个值的单个注释

    我有一个名为 Retention RetentionPolicy SOURCE Target ElementType METHOD public interface JIRA The Key Bug number JIRA referenc
  • “无法实例化活动”错误

    我的一个 Android 应用程序拥有大约 100 000 个用户 每周大约 10 次 我会通过 Google 的市场工具向我报告以下异常情况 java lang RuntimeException Unable to instantiate
  • Spring-ws:如何从没有“Request”元素的 xsd 创建 Wsdl

    尝试为客户端实现 SOAP Web 服务 我需要一个 wsdl 文件来通过soapUI 测试该服务 但正如您在下面看到的 这个 xsd 没有 Request 和 Response 方法 所有请求和响应都被定义为基本 ServiceProvi
  • Hamcrest Matchers - 断言列表类型

    问题 我目前正在尝试使用 Hamcrest Matchers 来断言返回的列表类型是特定类型 例如 假设我的服务调用返回以下列表 List
  • OpenCSV:将嵌套 Bean 映射到 CSV 文件

    我正在尝试将 bean 映射到 CSV 文件 但问题是我的 bean 具有其他嵌套 bean 作为属性 所发生的情况是 OpenCSV 遍历属性找到一个 bean 然后进入其中并映射该 bean 内的所有数据 如果找到另一个 bean 它就
  • 在java中使用多个bufferedImage

    我正在 java 小程序中制作游戏 并且正在尝试优化我的代码以减少闪烁 我已经实现了双缓冲 因此我尝试使用另一个 BufferedImage 来存储不改变的游戏背景元素的图片 这是我的代码的相关部分 public class QuizApp

随机推荐

  • 循环并将值插入到mysql的表中

    嗨 我有两个数组作为输入 我想使用循环插入到表中 这是我尝试过的 simple loop LOOP SET i i 1 simples loop LOOP SET j j 1 INSERT INTO ROLE PRIVILEGE BRIDG
  • SQL Server XML查询:查询多个同名子元素

    在上一个问题中 我想知道如何使用 SQL 来JOIN基于标识符的不同 XML 元素 如您所见 我获得了几个不错的解决方案here https stackoverflow com questions 60511464 sql server x
  • 执行 chroot 并在 chroot 中执行命令的 Shell 脚本

    如果我在 shell 脚本中写 chroot home mayank chroot codebase cd SBC 当我运行这个 shell 脚本时它确实进入了chroot但不执行命令cd SBC 当我退出时chroot然后它执行cd SB
  • 如何检查路径是绝对路径还是相对路径

    UNIX 绝对路径以 开头 而 Windows 以字母 C 或 开头 Node js 是否有标准的多平台函数来检查路径是绝对路径还是相对路径 从节点版本 0 12 0 开始 您可以使用path isAbsolute path https n
  • 如何从周数和年份获取日期

    我想从周数和年份获取日期 我从服务器获得了周数和年份 我是 尝试以下代码 但它不起作用 NSDateFormatter dateFormatter2 NSDateFormatter alloc init this is imporant w
  • 如何在 .NET 中使用 TreeView 控件创建三态复选框?

    我在 Windows 窗体项目中有一个树视图控件 该控件已打开复选框 因为树视图控件具有嵌套节点 所以我需要复选框能够进行某种三模式选择 我找不到方法来做到这一点 我只能完全选中或取消选中复选框 如果您正在谈论 Windows 窗体 本文应
  • 从 Google Visualization 的 ColumnChart 中手动选择一个栏

    我使用 Google Visualization 的 ColumnChart 制作了一个图表 如下所示 它基本上是一个使用 3 x 7 矩阵的堆积柱形图 在每个栏中 我删除了另外两行的数据 我的问题是如何使黄色条 或其他条 看起来像是从一开
  • XSLT:深度子副本

    我的需求 我想深度复制单个选定节点的所有子节点 而不实际复制它 示例 来自
  • 除了内存分配相关的东西之外, void* 是否是必需的

    Is void 除了C 中与内存分配相关的东西之外还有必要吗 你可以给我一个例子吗 记录内存地址 如果你想使用 iostreams 输出指针 例如用于日志记录 那么通过void 是确保的唯一方法operator lt lt 并没有以某种疯狂
  • Yii 2 在点击默认联系人选项卡时出现异常

    当我在 Mac 上使用 localhost 运行时 出现此错误 支持 FreeType 的 GD PHP 扩展或 ImageMagick PHP 需要支持 PNG 的扩展名 我认为问题出在联系页面上默认渲染的 PNG 图片上 所有代码都是Y
  • 当我有大量 ID 列表时,如何在 SQL Server 中创建临时表

    我有一个原始 ID 列表 我应该将其放入临时表中 我不确定这在 SQL Server 中如何工作 我知道一般格式 select PID into myPIDs from 我已经有一个大约 30 个 PID 的列表 我将使用它们 他们看起来像
  • 从 R 中的库效果中删除图​​中第三轴和第四轴上的刻度

    我想知道是否有一种方法可以删除库生成的绘图的第三轴和第四轴上的刻度线 轴 effects如下所示 library effects m lt lm Fertility data swiss plot allEffects m rug FALS
  • “无法通过密钥查找会话:connect.sid” - session.socket.io

    我对 NodeJS 开发还很陌生 我正在使用会话 socket io https github com functioncallback session socket io插件在我的 Express 应用程序中 但在调试应用程序时出现此错误
  • 没有这样的模块“SwiftyDropbox”

    首先 我正在使用 Xcode 8 和 Swift 3 现在我想将 Dropbox API SwiftyDropbox 集成到我的应用程序中 因为我对 iOS 编程很陌生 所以我不确定我是否正确完成了所有步骤 我决定使用 CocoaPods
  • 适配包含 ref 参数的 C# 事件

    我所处的情况是 我必须使用包含很多事件的第三方库 而且恕我直言 写得不是很好 它触发了我必须在代码中处理的事件 但我试图将其抽象出来 以便能够对依赖于该库的其余代码进行单元测试 因此我需要一个适配器 问题是一些事件是委托类型的 需要ref参
  • 无法通过 Gmail 插件访问 Gmail 草稿

    我正在尝试使用 Gmail 插件访问 Gmail 中的所有草稿 但它会记录如下错误Access denied Missing access token for per message scope authorization line 8 f
  • AWS Lambda 和 Apache Airflow 集成

    想知道是否有人可以阐明这个问题 我正在尝试找到 Airflow REST API URL 以启动 DAG 以从 AWS Lambda 函数运行 到目前为止 除了查看 Apache 孵化器站点提供的所有相关文档之外 解决该问题的唯一指导是在
  • 读取失败:Firebase 中的权限被拒绝错误

    我正在关注此教程link https www simplifiedcoding net firebase android tutorial writing firebase data 适用于 Android 中的 Firebase 我只是想
  • div 不会一直水平扩展

    为什么我的 div 左右有空白 render return div div h2 TEXT h2 div div 而在我的css intro body height 500px background color 3BC5C3 我尝试过设置b
  • 使用 Java 解密 OpenSSL PEM 编码的 RSA 私钥?

    我有一个加密的私钥并且我知道密码 我需要使用 Java 库对其进行解密 不过 除非没有其他选择 否则我不想使用 BouncyCastle 根据以往的经验 改动太多 文档不够 私钥的形式如下 BEGIN RSA PRIVATE KEY Pro