目录

  • 一、序言
  • 二、代码示例
    • 1、Maven依赖
    • 2、工具类封装
  • 三、测试用例
    • 1、密钥文件
    • 2、公私钥PKCS1和PKCS8格式互相转换

一、序言

之前在 《前后端RSA互相加解密、加签验签、密钥对生成》 中提到过PKCS#1格式和PKCS#8格式密钥的区别以及如何生成密钥。实际有些场景中有可能也会涉及到前后端密钥格式不一致,这篇文章我们会讨论关于PKCS#1PKCS#8格式密钥的互相转换。

这里我们会用到Bouncy Castle,它提供了各种加密算法的Java实现,其中Java相关的资料可以参考Bouncy Castle Github。


二、代码示例

1、Maven依赖

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk18on</artifactId><version>1.72</version>
</dependency>

2、工具类封装

package com.universe.crypto;import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;/*** @author Nick Liu* @date 2023/2/2*/
public class AsymmetricKeyUtils {private static final String ALGORITHM_NAME = "RSA";private static final Encoder BASE64_ENCODER = Base64.getEncoder();private static final Decoder BASE64_DECODER = Base64.getDecoder();static {// 必须创建Bouncy Castle提供者Security.addProvider(new BouncyCastleProvider());}/*** 格式化密钥为标准Pem格式* @param keyFormat 密钥格式,参考{@link KeyFormat}* @param asymmetricKey 非对称密钥* @return .pem格式密钥字符串* @throws IOException*/public static String formatKeyAsPemString(KeyFormat keyFormat, String asymmetricKey) throws IOException {byte[] keyInBytes = BASE64_DECODER.decode(asymmetricKey);PemObject pemObject = new PemObject(keyFormat.getName(), keyInBytes);try (StringWriter stringWriter = new StringWriter()) {PemWriter pemWriter = new PemWriter(stringWriter);pemWriter.writeObject(pemObject);pemWriter.flush();return stringWriter.toString();}}/*** 从标准Pem格式中提取密钥* @param asymmetricKeyAsPem* @return 无---BEGIN---和---END---前后缀的密钥字符串* @throws IOException*/public static String extractKeyFromPemString(String asymmetricKeyAsPem) throws IOException {try (PemReader pemReader = new PemReader(new StringReader(asymmetricKeyAsPem))) {PemObject pemObject = pemReader.readPemObject();return BASE64_ENCODER.encodeToString(pemObject.getContent());}}/*** 从文件中提取密钥* @param pemFilePath* @return 无---BEGIN---和---END---前后缀的密钥字符串* @throws Exception*/public static String readKeyFromPath(String pemFilePath) throws Exception {try (PemReader pemReader = new PemReader(new InputStreamReader(Files.newInputStream(Paths.get(pemFilePath))))) {PemObject pemObject = pemReader.readPemObject();return BASE64_ENCODER.encodeToString(pemObject.getContent());}}/*** 将PKCS1公钥转换为PKCS8公钥* @param pubKeyInPKCS1 PKCS1形式公钥* @return PKCS8形式公钥* @throws Exception*/public static String transformPubKeyFromPkcs1ToPkcs8(String pubKeyInPKCS1) throws Exception {RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(BASE64_DECODER.decode(pubKeyInPKCS1));KeySpec keySpec = new RSAPublicKeySpec(rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent());KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);PublicKey publicKey = keyFactory.generatePublic(keySpec);return BASE64_ENCODER.encodeToString(publicKey.getEncoded());}/*** 将PKCS8公钥转换为PKCS1公钥* @param pubKeyInPKCS8 PKCS8公钥* @return PKCS1公钥*/public static String transformPubKeyFromPkcs8ToPkcs1(String pubKeyInPKCS8) {ASN1Sequence publicKeyASN1Object = ASN1Sequence.getInstance(BASE64_DECODER.decode(pubKeyInPKCS8));DERBitString derBitString = (DERBitString) publicKeyASN1Object.getObjectAt(1);return BASE64_ENCODER.encodeToString(derBitString.getBytes());}/*** 将PKCS1私钥转换为PKCS8公钥* @param privateKeyInPKCS1 PKCS1公钥* @return PKCS8公钥* @throws Exception*/public static String transformPrivateKeyFromPkcs1ToPkcs8(String privateKeyInPKCS1) throws Exception {KeySpec keySpec = new PKCS8EncodedKeySpec(BASE64_DECODER.decode(privateKeyInPKCS1));KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return BASE64_ENCODER.encodeToString(privateKey.getEncoded());}/*** 将PKCS1私钥转换为PKCS8私钥* @param privateKeyInPKCS8 PKCS8私钥* @return PKCS1私钥* @throws Exception*/public static String transformPrivateKeyFromPkcs8ToPkcs1(String privateKeyInPKCS8) throws Exception {PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(BASE64_DECODER.decode(privateKeyInPKCS8));RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(privateKeyInfo.parsePrivateKey());return BASE64_ENCODER.encodeToString(rsaPrivateKey.getEncoded());}public enum KeyFormat {/*** PKCS1格式RSA私钥*/RSA_PRIVATE_KEY_PKCS1("RSA PRIVATE KEY"),/*** PKCS8格式RSA私钥*/RSA_PRIVATE_KEY_PKCS8("PRIVATE KEY"),/*** PKCS1格式RSA公钥*/RSA_PUBLIC_KEY_PKCS1("RSA PUBLIC KEY"),/*** PKCS8格式RSA公钥*/RSA_PUBLIC_KEY_PKCS8("PUBLIC KEY");private String name;KeyFormat(String name) {this.name = name;}public String getName() {return name;}}}

备注:必须要添加Bouncy Castle提供者,代码中Security.addProvider(new BouncyCastleProvider())展示的是动态添加,也可以静态添加,更多请参考 Bouncy Castle提供者安装。


三、测试用例

1、密钥文件

准备.pem两个文件,里面分别是PKCS#1格式公钥和PKCS#1格式私钥,内容如下:

  • publicKeyInPkcs1.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4
o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu+9CwKy5Sfrh5RXiTgy0ZAfg0
Lw2T+Ml2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQAB
AoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE+4gc
+j9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXj
OegGJG9+RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2d
zv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3+H
fLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8
AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsb+fXbHaFKrG07bjcosD
7GUsKenKvpG350XiMuNDAU+jnxJ9Lha+drXf4OlKsq1V3enaGXu+dMDP+W5hAkAn
i0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9
ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZW+
AblMqqb3iwqP+LWoES3SqAKRmA6clh/9DUqtOn6610gk
-----END RSA PRIVATE KEY-----
  • privateKeyInPkcs1.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAK3e6LCQixjb1WXzx+JX0WRmoXrlVbx6Z+QEUl8RWr3Ytmrq/Dij/ct1
1rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJ+uHlFeJODLRkB+DQvDZP4
yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAE=
-----END RSA PUBLIC KEY-----

2、公私钥PKCS1和PKCS8格式互相转换

public class Test {/*** 密钥保存在用户目录下keys文件夹*/private static final String BASE_PATH = Paths.get(System.getProperty("user.home"), "keys").toString();private static final String PRIVATE_KEY_PKCS1 = Paths.get(BASE_PATH, "privateKeyInPkcs1.pem").toString();private static final String PUBLIC_KEY_PKCS1 = Paths.get(BASE_PATH, "publicKeyInPkcs1.pem").toString();public static void main(String[] args) throws Exception {String pubicKeyInPkcs1 = AsymmetricKeyUtils.readKeyFromPath(PUBLIC_KEY_PKCS1);System.out.println("读取到的PKCS1格式公钥为:\n" + pubicKeyInPkcs1);String publicKeyInPkcs8 = AsymmetricKeyUtils.transformPubKeyFromPkcs1ToPkcs8(pubicKeyInPkcs1);System.out.println("转换后的PKCS8格式公钥为:\n" + publicKeyInPkcs8);pubicKeyInPkcs1 = AsymmetricKeyUtils.transformPubKeyFromPkcs8ToPkcs1(publicKeyInPkcs8);System.out.println("转换后的PKCS1格式公钥为:\n" + pubicKeyInPkcs1);System.out.println();String privateKeyInPkcs1 = AsymmetricKeyUtils.readKeyFromPath(PRIVATE_KEY_PKCS1);System.out.println("读取到的PKCS1格式私钥为:\n" + privateKeyInPkcs1);String privateKeyInPkcs8 = AsymmetricKeyUtils.transformPrivateKeyFromPkcs1ToPkcs8(privateKeyInPkcs1);System.out.println("转换后的PKCS8格式私钥为:\n" + privateKeyInPkcs8);privateKeyInPkcs1 = AsymmetricKeyUtils.transformPrivateKeyFromPkcs8ToPkcs1(privateKeyInPkcs8);System.out.println("转换后的PKCS1格式私钥为:\n" + privateKeyInPkcs1);}
}

控制台输出如下:

读取到的PKCS1格式公钥为:
MIGJAoGBAK3e6LCQixjb1WXzx+JX0WRmoXrlVbx6Z+QEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJ+uHlFeJODLRkB+DQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAE=
转换后的PKCS8格式公钥为:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu+9CwKy5Sfrh5RXiTgy0ZAfg0Lw2T+Ml2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQAB
转换后的PKCS1格式公钥为:
MIGJAoGBAK3e6LCQixjb1WXzx+JX0WRmoXrlVbx6Z+QEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJ+uHlFeJODLRkB+DQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAE=读取到的PKCS1格式私钥为:
MIICXQIBAAKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu+9CwKy5Sfrh5RXiTgy0ZAfg0Lw2T+Ml2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQABAoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE+4gc+j9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXjOegGJG9+RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2dzv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3+HfLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsb+fXbHaFKrG07bjcosD7GUsKenKvpG350XiMuNDAU+jnxJ9Lha+drXf4OlKsq1V3enaGXu+dMDP+W5hAkAni0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZW+AblMqqb3iwqP+LWoES3SqAKRmA6clh/9DUqtOn6610gk
转换后的PKCS8格式私钥为:
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK3e6LCQixjb1WXzx+JX0WRmoXrlVbx6Z+QEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJ+uHlFeJODLRkB+DQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAECgYEAiIQqDWAgZu9MeZVUTyqGlR9kELt6etddNRITnuNgbQl4CTDhwpM4VYT7iBz6P2CL96WPKMInAvKdYWwAkukp+sJ3NvN3vjxde4XF8U6p3zDqWw7bw9uGrLhi9eM56AYkb35HJ9laFM/0mZT966ae0sWQQuvmbzRKqKJgija5jQECQQDTt6R63ZQDLZ3O/eMwPfBtwSA/H3un+RNxOrie1ZQDle4I8LdNvQZ73+Jma7V61lwO0+m1Aq93f4d8uaYVDIRhAkEA0jzHLU+d++pbyVFtv1MJCbkGa+YdcI40d00ALdRbaMn1xQP3+jwCI82/xleZOCxJsG8Bb12VR7fmOhZoEC+UeQJBALmdal2xv59dsdoUqsbTtuNyiwPsZSwp6cq+kbfnReIy40MBT6OfEn0uFr52td/g6UqyrVXd6doZe750wM/5bmECQCeLRQ+RxS6II2GXjmQJU07f3YRYETuFk/rIofr80YDBVBgNqgwIU4K2hZbiDTDSq72i84sl+Bk4TvaoFkTNHkkCQGbC4fjwrpDconFS9AOnDoGCHbMZrKjLXYF0NAzRlb4BuUyqpveLCo/4tagRLdKoApGYDpyWH/0NSq06frrXSCQ=
转换后的PKCS1格式私钥为:
MIICXQIBAAKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu+9CwKy5Sfrh5RXiTgy0ZAfg0Lw2T+Ml2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQABAoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE+4gc+j9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXjOegGJG9+RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2dzv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3+HfLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsb+fXbHaFKrG07bjcosD7GUsKenKvpG350XiMuNDAU+jnxJ9Lha+drXf4OlKsq1V3enaGXu+dMDP+W5hAkAni0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZW+AblMqqb3iwqP+LWoES3SqAKRmA6clh/9DUqtOn6610gk

备注:可以将转换后的公私钥在RSA加/解密平台测试一下,博主亲测是okay的。

非对称密钥PKCS#1和PKCS#8格式互相转换(Java)相关推荐

  1. PHP rsa私钥pkcs8加密,Openssl rsa私钥的PKCS#1和PKCS#8格式以及加密和转化

    这里主要介绍: 私钥的PKCS#1格式,及PKCS#8格式 格式PKCS#1和PKCS#8之间的互相转化 私钥的加密,解密 PKCS#1 -> PKCS#8 生成PKCS#1私钥 $ opens ...

  2. PKCS#1、PKCS#5、PKCS#7、PKCS#8到底是什么?

    今天在看源码的时候,出现了一个后缀pkcs5,很是疑惑,这里来扫盲. 首先PKCS是什么? The Public-Key Cryptography Standards (PKCS)是由美国RSA数据安 ...

  3. Python RSA PKCS#1 转 PKCS#8

    Python RSA PKCS#1 转 PKCS#8 Python中使用RSA库生成公钥和私钥,只能以PKCS#1 DER或PEM格式保存公钥和私钥.但是我们有时候需要PKCS#8这种格式 impor ...

  4. 你不知道的对称密钥与非对称密钥

    (一)对称加密(Symmetric Cryptography) 对称密钥加密,又称私钥加密,即信息的发送方和接收方用一个密钥去加密和解密数据.它的最大优势是加/解密速度快,适合于对大数据量进行加密,对 ...

  5. 数据加密 第五篇:非对称密钥

    非对称密钥(Asymmetric Keys)跟对称密钥相对,它使用一对密钥(算法),一个密钥用于加密,另一个密钥用于解密,加密的密钥称为私钥(private key),解密的密钥称为公钥(public ...

  6. PKI基础知识(数字信封与数字签名过程,对称密钥与非对称密钥)

    1.数字信封 关于对称密码术和非对称密码:前者具有加密速度快.运行时占用资源少等特点,后者可以用于密钥交换.一般来说,并不直接使用非对称加密算法加密明文,而仅用它保护实际加密明文的对称密钥,来减少运算 ...

  7. mysql 非对称密钥_sqlser 2005 对称加密,非对称加密笔记

    一:对称加密 原始明文---密钥---加密数据---密钥---原始明文 速度快,通过算法将明文混淆,占用系统资源少 二:非对称加密 加密解密速度慢,较高的系统资源占用 三:混合数据加密 加密过程:随机 ...

  8. 对称密钥,非对称密钥,单向散列函数—William chu的学习之路(信息安全)

    今天也是元气满满的一天鸭!(土豪巨巨们要是觉得有用,支持一下吧~) 对称密钥密码技术 对称密钥又称为保密密钥,非对称密钥也称公有和私有密钥,对称密钥中加密和解密用相同的密钥如DES和IDEA等. 非对 ...

  9. (2)非对称密钥加密——RSA算法ECC算法(简介)

    一:目前主流的加密密钥分为两大类:对称密钥和非对称密钥 1)对称密钥:数据发送方和接收方使用的是同一个密钥,即加密和解密的密钥是同一个(K) 2)非对称密钥:数据发送方使用接收方的公钥进行加密,接收方 ...

最新文章

  1. 我在思考的时候神告诉我的(大学里的爱恋)
  2. Future和CompletableFuture的区别和对比,以及Future主要的四个缺点——不能回调会阻塞、批量任务处理彼此依赖会阻塞、不能多个任务级联执行、得不到最先完成的任务
  3. android studio3.12,Android Studio V3.12环境下TV开发教程(六)提供卡片视图
  4. Linux 下的 AddressSanitizer
  5. Docker精华问答 | 多个 Docker 容器之间共享数据怎么办?
  6. java naive方法_朴素贝叶斯方法(Naive Bayes Method)
  7. 如何安装tensorflow
  8. java的技术定义_java基础知识——Java的定义,特点和技术平台
  9. python 命令行 模块_深入浅析Python 命令行模块 Click
  10. Android - Broadcast机制
  11. vim忽略大写和小写查找配置
  12. 计算机组装常用工具有锤子,工具箱中常用的五金工具有哪些?
  13. MAC 安装 Redis 客户端
  14. DELL linux 网卡驱动升级
  15. java脚本引擎parseint方法_autojs脚本引擎调用java的jsoup爬取科学网博客的指定id的好友名字...
  16. Linux IPTABLES 防火墙专题讲座 - 上篇-龙小威-专题视频课程
  17. C++学习心得和进阶路线总结
  18. Android 无需root实现apk的静默安装
  19. LOJ 10155. 「一本通 5.2 例 3」数字转换
  20. 解放双手——Android的自动化构建及发布

热门文章

  1. 看这里看这里:结构体的超级详细讲解
  2. QT Designer
  3. 2022年辽宁审计师考试考前冲刺题及答案
  4. 在Python中使用OpenCV将RGB格式的图像转换为HSV格式的图像
  5. cuda2 向量加法
  6. 【自然语言处理与文本分析】文本特征提取方法总结。关键词提取方法。公认效果较好的IDF,RCF。
  7. App-V软件排序参考之(二):Office 2007英文版+多国语言包 (1)
  8. 十二个SOLIDWORKS使用小技巧,解决日常绘图令你抓狂的瞬间!
  9. CCS6创建TMS320F2812工程
  10. 课程设计:通讯录管理系统