网站制作公司北京网站建设公司哪家好,网站建设考试题,网站关于我们页面设计,做搜索的网站有哪些目录一、序言二、代码示例1、Maven依赖2、工具类封装三、测试用例1、密钥文件2、公私钥PKCS1和PKCS8格式互相转换一、序言
之前在 《前后端RSA互相加解密、加签验签、密钥对生成》 中提到过PKCS#1格式和PKCS#8格式密钥的区别以及如何生成密钥。实际有些场景中有可能也会涉及到…
目录一、序言二、代码示例1、Maven依赖2、工具类封装三、测试用例1、密钥文件2、公私钥PKCS1和PKCS8格式互相转换一、序言
之前在 《前后端RSA互相加解密、加签验签、密钥对生成》 中提到过PKCS#1格式和PKCS#8格式密钥的区别以及如何生成密钥。实际有些场景中有可能也会涉及到前后端密钥格式不一致这篇文章我们会讨论关于PKCS#1和PKCS#8格式密钥的互相转换。
这里我们会用到Bouncy Castle它提供了各种加密算法的Java实现其中Java相关的资料可以参考Bouncy Castle Github。 二、代码示例
1、Maven依赖
dependencygroupIdorg.bouncycastle/groupIdartifactIdbcpkix-jdk18on/artifactIdversion1.72/version
/dependency2、工具类封装
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/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu9CwKy5Sfrh5RXiTgy0ZAfg0
Lw2TMl2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQAB
AoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE4gc
j9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXj
OegGJG9RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2d
zv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3H
fLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8
AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsbfXbHaFKrG07bjcosD
7GUsKenKvpG350XiMuNDAUjnxJ9LhadrXf4OlKsq1V3enaGXudMDPW5hAkAn
i0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9
ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZW
AblMqqb3iwqPLWoES3SqAKRmA6clh/9DUqtOn6610gk
-----END RSA PRIVATE KEY-----privateKeyInPkcs1.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAK3e6LCQixjb1WXzxJX0WRmoXrlVbx6ZQEUl8RWr3Ytmrq/Dij/ct1
1rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJuHlFeJODLRkBDQvDZP4
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格式公钥为
MIGJAoGBAK3e6LCQixjb1WXzxJX0WRmoXrlVbx6ZQEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJuHlFeJODLRkBDQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAE
转换后的PKCS8格式公钥为
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu9CwKy5Sfrh5RXiTgy0ZAfg0Lw2TMl2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQAB
转换后的PKCS1格式公钥为
MIGJAoGBAK3e6LCQixjb1WXzxJX0WRmoXrlVbx6ZQEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJuHlFeJODLRkBDQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAE读取到的PKCS1格式私钥为
MIICXQIBAAKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu9CwKy5Sfrh5RXiTgy0ZAfg0Lw2TMl2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQABAoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE4gcj9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXjOegGJG9RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2dzv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3HfLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsbfXbHaFKrG07bjcosD7GUsKenKvpG350XiMuNDAUjnxJ9LhadrXf4OlKsq1V3enaGXudMDPW5hAkAni0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZWAblMqqb3iwqPLWoES3SqAKRmA6clh/9DUqtOn6610gk
转换后的PKCS8格式私钥为
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK3e6LCQixjb1WXzxJX0WRmoXrlVbx6ZQEUl8RWr3Ytmrq/Dij/ct11rkBAHRZlkgYgtChHDLutqIpteqbJ9newm770LArLlJuHlFeJODLRkBDQvDZP4yXaXvQpkqRxKIDJpFMzVg9xhcixChHKnzy1Kdi8ef2CGhqWNQaXZAgMBAAECgYEAiIQqDWAgZu9MeZVUTyqGlR9kELt6etddNRITnuNgbQl4CTDhwpM4VYT7iBz6P2CL96WPKMInAvKdYWwAkukpsJ3NvN3vjxde4XF8U6p3zDqWw7bw9uGrLhi9eM56AYkb35HJ9laFM/0mZT966ae0sWQQuvmbzRKqKJgija5jQECQQDTt6R63ZQDLZ3O/eMwPfBtwSA/H3unRNxOrie1ZQDle4I8LdNvQZ73Jma7V61lwO0m1Aq93f4d8uaYVDIRhAkEA0jzHLUdpbyVFtv1MJCbkGaYdcI40d00ALdRbaMn1xQP3jwCI82/xleZOCxJsG8Bb12VR7fmOhZoECUeQJBALmdal2xv59dsdoUqsbTtuNyiwPsZSwp6cqkbfnReIy40MBT6OfEn0uFr52td/g6UqyrVXd6doZe750wM/5bmECQCeLRQRxS6II2GXjmQJU07f3YRYETuFk/rIofr80YDBVBgNqgwIU4K2hZbiDTDSq72i84slBk4TvaoFkTNHkkCQGbC4fjwrpDconFS9AOnDoGCHbMZrKjLXYF0NAzRlb4BuUyqpveLCo/4tagRLdKoApGYDpyWH/0NSq06frrXSCQ
转换后的PKCS1格式私钥为
MIICXQIBAAKBgQCt3uiwkIsY29Vl88fiV9FkZqF65VW8emfkBFJfEVq92LZq6vw4o/3Ldda5AQB0WZZIGILQoRwy7raiKbXqmyfZ3sJu9CwKy5Sfrh5RXiTgy0ZAfg0Lw2TMl2l70KZKkcSiAyaRTM1YPcYXIsQoRyp88tSnYvHn9ghoaljUGl2QIDAQABAoGBAIiEKg1gIGbvTHmVVE8qhpUfZBC7enrXXTUSE57jYG0JeAkw4cKTOFWE4gcj9gi/eljyjCJwLynWFsAJLpKfrCdzbzd748XXuFxfFOqd8w6lsO28Pbhqy4YvXjOegGJG9RyfZWhTP9JmU/eumntLFkELr5m80SqiiYIo2uY0BAkEA07eket2UAy2dzv3jMD3wbcEgPx97p/kTcTq4ntWUA5XuCPC3Tb0Ge9/iZmu1etZcDtPptQKvd3HfLmmFQyEYQJBANI8xy1PnfvqW8lRbb9TCQm5BmvmHXCONHdNAC3UW2jJ9cUD9/o8AiPNv8ZXmTgsSbBvAW9dlUe35joWaBAvlHkCQQC5nWpdsbfXbHaFKrG07bjcosD7GUsKenKvpG350XiMuNDAUjnxJ9LhadrXf4OlKsq1V3enaGXudMDPW5hAkAni0UPkcUuiCNhl45kCVNO392EWBE7hZP6yKH6/NGAwVQYDaoMCFOCtoWW4g0w0qu9ovOLJfgZOE72qBZEzR5JAkBmwuH48K6Q3KJxUvQDpw6Bgh2zGayoy12BdDQM0ZWAblMqqb3iwqPLWoES3SqAKRmA6clh/9DUqtOn6610gk备注可以将转换后的公私钥在RSA加/解密平台测试一下博主亲测是okay的。