GVKun编程网logo

Java不同类型密钥库之PKCS12和JCEKS(jks密钥库使用专用格式)

11

对于Java不同类型密钥库之PKCS12和JCEKS感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解jks密钥库使用专用格式,并且为您提供关于.NETCoreRSA密钥的xml、pkcs1、

对于Java不同类型密钥库之PKCS12和JCEKS感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解jks密钥库使用专用格式,并且为您提供关于.NET Core RSA密钥的xml、pkcs1、pkcs8格式转换和JavaScript、Java等语言进行对接、iOS:如何以编程方式在应用程序中从私钥和x509certificate创建PKCS12(P12)密钥库?、Java 9中的SunPKCS11提供程序、java PKCS12 证书生成的宝贵知识。

本文目录一览:

Java不同类型密钥库之PKCS12和JCEKS(jks密钥库使用专用格式)

Java不同类型密钥库之PKCS12和JCEKS(jks密钥库使用专用格式)

摘要:密钥库是一个存放加密密钥和证书的存储设施,它们经常用于SSL通信来标明服务器和客户机的身份,本文所列的为Java密钥库中的PKCS12和JCEKS类型。介绍了其存储和加载密钥、证书所使用的代码片段。


编者注:密钥库是一个存放加密密钥和证书的存储设施,它们经常用于SSL通信来标明服务器和客户机的身份,一个密钥库可以是一份文件或硬件设备。Java中不同类型的密钥库包含:PrivateKey、SecretKey、JKS、PKCS12、JCEKS等。其中JKS的详细介绍可参考《Java不同密钥库类型之JKS》。本文所讲诉的为PKCS12和JCEKS的用法。

以下为译文:

JCEKS

JCEKS是Java平台的一个密钥库格式,将密钥存储在密钥库中以防止加密密钥的暴露。在JCEKS中存储和装载不同条目的过程类似于JKS,只需在调用KeyStore.getInstance()时更改相应的JCEKS密钥库类型。

存储密钥

密钥可以通过一下代码存储到JCEKS中:


try{ KeyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(null, null); KeyGenerator keyGen = KeyGenerator.getInstance("DES"); keyGen.init(56);; Key key = keyGen.generateKey(); keyStore.setKeyEntry("secret", key, "password".toCharArray(), null); keyStore.store(new FileOutputStream("output.jceks"), "password".toCharArray()); } catch (Exception ex) { ex.printStackTrace(); }


加载密钥

代码如下:


try{ KeyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(new FileInputStream("output.jceks"), "password".toCharArray()); Key key = keyStore.getKey("secret", "password".toCharArray()); System.out.println(key.toString()); } catch (Exception ex) { ex.printStackTrace(); }


输出代码:

javax.crypto.spec.SecretKeySpec@fffe7b9b

PKCS12

PKCS12是公钥加密标准,它规定了可包含所有私钥、公钥和证书。其以二进制格式存储,也称为 PFX 文件,在windows中可以直接导入到密钥区。注意,PKCS12的密钥库保护密码同时也用于保护Key。

创建PKCS12密钥库

在把一个条目存入PKCS12之前必须先加载密钥库,这意味着我们必须首先创建一个密钥库。简单创建一个PKCS12密钥库的方式如下:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(null, null); keyStore.store(new FileOutputStream("output.p12"), "password".toCharArray()); } catch (Exception ex){ ex.printStackTrace(); }


需要注意的是,在调用keyStore.load(null, null)时,两个null是作为输入密钥流和密码传递的。这是因为我们没有可用的密钥库。运行这段代码后,当前工作目录中应该会输出一个名为output.p12的文件。

存储密钥

代码如下:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(null, null); KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(128); Key key = keyGen.generateKey(); keyStore.setKeyEntry("secret", key, "password".toCharArray(), null); keyStore.store(new FileOutputStream("output.p12"), "password".toCharArray()); } catch (Exception ex){ ex.printStackTrace(); }

存储私钥

密钥库包含可用于网络上的SSL通信的私钥和证书:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); // keyStore.load(new FileInputStream("output.p12"),"password".toCharArray()); keyStore.load(null, null);; CertAndKeyGen gen = new CertAndKeyGen("RSA","SHA1WithRSA"); gen.generate(1024); Key key=gen.getPrivateKey(); X509Certificate cert=gen.getSelfCertificate(new X500Name("CN=ROOT"), (long)365*24*3600); X509Certificate[] chain = new X509Certificate[1]; chain[0]=cert; keyStore.setKeyEntry("private", key, "password".toCharArray(), chain); keyStore.store(new FileOutputStream("output.p12"), "password".toCharArray()); }catch(Exception ex){ ex.printStackTrace(); }


别忘了调用keyStore.store()来保存密钥,否则条目在程序退出时会丢失。

存储证书

存储证书可以调用KeyStore.setCertificateEntry():


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); // keyStore.load(new FileInputStream("output.p12"),"password".toCharArray()); keyStore.load(null, null);; CertAndKeyGen gen = new CertAndKeyGen("RSA","SHA1WithRSA"); gen.generate(1024); X509Certificate cert=gen.getSelfCertificate(new X500Name("CN=ROOT"), (long)365*24*3600); keyStore.setCertificateEntry("cert", cert); keyStore.store(new FileOutputStream("output.p12"), "password".toCharArray()); }catch(Exception ex){ ex.printStackTrace(); }


存储的证书可以通过调用提供别名的KeyStore.getCertificate() 来提取,例如:

Certificate cert = keyStore.getCertificate("cert");

加载私钥


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream("output.p12"), "password".toCharArray()); Key pvtKey = keyStore.getKey("private", "password".toCharArray()); System.out.println(pvtKey.toString()); } catch (Exception ex){ ex.printStackTrace(); }


代码输出:

sun.security.rsa.RSAPrivateCrtKeyImpl@ffff2466

加载证书链

如果一个证书链存在密钥库中,我们可以通过调用KeyStore.getCertificateChain()来加载:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream("output.p12"), "password".toCharArray()); Key pvtKey = keyStore.getKey("private", "password".toCharArray()); System.out.println(pvtKey.toString()); java.security.cert.Certificate[] chain = keyStore.getCertificateChain("private"); for(java.security.cert.Certificate cert:chain){ System.out.println(cert.toString()); } } catch (Exception ex){ ex.printStackTrace(); }


输出:


[ [ Version: V3 Subject: CN=ROOT Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5 Key: Sun RSA public key, 1024 bits modulus: 107262652552256813768678166856978781385254195794582600239703451044252881438814396239031781495369251659734172714120481593881055888193254336293673302267462500060447786562885955334870856482264000504019061160524587434562257067298291769329550807938162702640388267016365640782567817416484577163775446236245223552189 public exponent: 65537 Validity: [From: Mon Jan 05 13:03:29 SGT 2015, To: Tue Jan 05 13:03:29 SGT 2016] Issuer: CN=ROOT SerialNumber: [ 5e5ca8a4] ] Algorithm: [SHA1withRSA] Signature: 0000: 22 21 BF 73 A6 6D 12 9B F7 49 6C 0E B3 50 6A 9D "!.s.m...Il..Pj. 0010: FA 30 43 22 32 FF 54 95 80 2E B3 8B 6F 59 D4 B5 .0C"2.T.....oY.. 0020: 6C A6 AE 89 B7 18 9A A8 35 7D 65 37 BF ED A3 F4 l.......5.e7.... 0030: E7 DB 5D 5F 9B DA 4B FA 39 04 9B 4D DB C2 3E FA ..]_..K.9..M..>. 0040: 3B C2 63 F8 1E BE 03 F3 BD 1C D4 8A 8E 3C 51 68 ;.c..........


注:如何在Java中创建证书链?可参考:点此进入

加载证书

加载证书可以通过调用KeyStore.getCertificate()来实现:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream("output.p12"), "password".toCharArray()); java.security.cert.Certificate cert = keyStore.getCertificate("private"); System.out.println(cert); } catch (Exception ex){ ex.printStackTrace(); }


输出:

[ [ Version: V3 Subject: CN=ROOT Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5 Key: Sun RSA public key, 1024 bits modulus: 107262652552256813768678166856978781385254195794582600239703451044252881438814396239031781495369251659734172714120481593881055888193254336293673302267462500060447786562885955334870856482264000504019061160524587434562257067298291769329550807938162702640388267016365640782567817416484577163775446236245223552189 public exponent: 65537 Validity: [From: Mon Jan 05 13:03:29 SGT 2015, To: Tue Jan 05 13:03:29 SGT 2016] Issuer: CN=ROOT SerialNumber: [ 5e5ca8a4] ] Algorithm: [SHA1withRSA] Signature: 0000: 22 21 BF 73 A6 6D 12 9B F7 49 6C 0E B3 50 6A 9D "!.s.m...Il..Pj. 0010: FA 30 43 22 32 FF 54 95 80 2E B3 8B 6F 59 D4 B5 .0C"2.T.....oY.. 0020: 6C A6 AE 89 B7 18 9A A8 35 7D 65 37 BF ED A3 F4 l.......5.e7.... 0030: E7 DB 5D 5F 9B DA 4B FA 39 04 9B 4D DB C2 3E FA ..]_..K.9..M..>. 0040: 3B C2 63 F8 1E BE 03 F3 BD 1C D4 8A 8E 3C 51 68 ;.c..........


导入导出密钥和证书

PKCS12密钥库可以用于导入导出密钥和证书,下面的代码演示了从PKCS12导出一个私钥并导入到JKS密钥库中:


try{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream("output.p12"), "password".toCharArray()); Key pvtKey = keyStore.getKey("private", "password".toCharArray()); java.security.cert.Certificate[] chain = keyStore.getCertificateChain("private"); KeyStore jksStore = KeyStore.getInstance("JKS"); jksStore.load(null, null);; jksStore.setKeyEntry("jksPrivate", pvtKey, "newpassword".toCharArray(), chain); jksStore.store(new FileOutputStream("output.jks"), "password".toCharArray()); } catch (Exception ex){ ex.printStackTrace();



本文分享自微信公众号 - JAVA乐园(happyhuangjinjin88)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

.NET Core RSA密钥的xml、pkcs1、pkcs8格式转换和JavaScript、Java等语言进行对接

.NET Core RSA密钥的xml、pkcs1、pkcs8格式转换和JavaScript、Java等语言进行对接

众所周知在.NET下的RSA类所生成的密钥为Xml格式,而其他语言比如java一般使用pkcs8格式的密钥,JavaScript一般使用pkcs1格式。我们在开发过程中很可能遇到需要与其他语言开发的api进行对接,如果遇到RSA加密解密,我们肯定需要保证key是相同的,才能保证数据的正确处理,我们肯定需要对密钥进行转换,下面我将我自己的使用经验分享给大家。

pkcs1和pkcs8的操作借助了开源项目bouncycastle

RSAUtil 项目

RSAUtil 项目是.NET Core下RSA算法使用帮助工具,支持使用RSA算法对数据进行加密,解密,签名和验证签名,支持xml,pkcs1,pkcs8三种密钥格式,支持这三种格式的密钥相互转换。最后还支持pem格式化。

使用

生成密钥

使用“RsaKeyGenerator”类。返回的结果是一个有两个元素的字符串的列表,元素1是私钥,元素2是公钥。

格式:XML

var keyList = RsaKeyGenerator.XmlKey(2048);
var privateKey = keyList [0];
var publicKey = keyList [1];

格式:Pkcs1

var keyList = RsaKeyGenerator.Pkcs1Key(2048);
var privateKey = keyList [0];
var publicKey = keyList [1];

格式:Pkcs8

var keyList = RsaKeyGenerator.Pkcs8Key(2048);
var privateKey = keyList [0];
var publicKey = keyList [1];

RSA密钥转换

使用“RsaKeyConvert”类。它支持这三种格式的密钥转换,即:xml,pkcs1,pkcs8。

XML-> Pkcs1:
  • 私钥:RsaKeyConvert.PrivateKeyXmlToPkcs1()
  • 公钥:RsaKeyConvert.PublicKeyXmlToPem()
XML-> Pkcs8:
  • 私钥:RsaKeyConvert.PrivateKeyXmlToPkcs8()
  • 公钥:RsaKeyConvert.PublicKeyXmlToPem()
Pkcs1-> XML:
  • 私钥:RsaKeyConvert.PrivateKeyPkcs1ToXml()
  • 公钥:RsaKeyConvert.PublicKeyPemToXml()
Pkcs1-> Pkcs8:
  • 私钥:RsaKeyConvert.PrivateKeyPkcs1ToPkcs8()
  • 公钥:不需要转换
Pkcs8-> XML:
  • 私钥:RsaKeyConvert.PrivateKeyPkcs8ToXml()
  • 公钥:RsaKeyConvert.PublicKeyPemToXml()
Pkcs8-> Pkcs1:
  • 私钥:RsaKeyConvert.PrivateKeyPkcs8ToPkcs1()
  • 公钥:不需要转换

加密,解密,签名和验证签名

XML,Pkcs1,Pkcs8分别对应类:RsaXmlUtilRsaPkcs1UtilRsaPkcs8Util。它们继承自抽象类RSAUtilBase

  • 加密:RSAUtilBase.Encrypt()
  • 解密:RSAUtilBase.Decrypt()
  • Sign:RSAUtilBase.SignData()
  • 验证:RSAUtilBase.VerifyData()

PEM格式化

使用类“RsaPemFormatHelper”。

  • 格式化Pkcs1格式私钥:RsaPemFormatHelper.Pkcs1PrivateKeyFormat()
  • 删除Pkcs1格式私钥格式:RsaPemFormatHelper.Pkcs1PrivateKeyFormatRemove()
  • 格式化Pkcs8格式私钥:RsaPemFormatHelper.Pkcs8PrivateKeyFormat()
  • 删除Pkcs8格式的私钥格式:RsaPemFormatHelper.Pkcs8PrivateKeyFormatRemove()

其他说明

本项目已开源,如果对您有帮助,欢迎来个star:https://github.com/stulzq/RSAUtil

为了方便使用已经上传Nuget:https://www.nuget.org/packages/XC.RSAUtil/

直接使用命令安装:

Install-Package XC.RSAUtil

iOS:如何以编程方式在应用程序中从私钥和x509certificate创建PKCS12(P12)密钥库?

iOS:如何以编程方式在应用程序中从私钥和x509certificate创建PKCS12(P12)密钥库?

这个问题显然很相似,但没有任何答案: Programmatically create a x509 certificate for iPhone without using OpenSSL

在我们的应用程序(服务器,客户端)中,我们正在实现客户端身份验证(基于X509Certificate的SSL).我们已经有办法生成密钥对,创建PKCS10证书签名请求,由自签名CA签名并创建X509Certificate,然后发回.但是,要在SSL请求中使用此证书,必须将私钥和X509Certificate导出到PKCS12(P12)密钥库.

有没有人知道如何做到这一点,或者即使它可能?客户端必须生成P12文件(我们不想发出私钥),客户端正在运行iOS,并且是移动设备.该解决方案适用于Android使用BouncyCastle(spongycastle),但我们没有找到任何iOS.

编辑:在Java中,此导出由以下内容完成:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
    KeyStore ks = KeyStore.getInstance("PKCS12",BouncyCastleProvider.PROVIDER_NAME);
    ks.load(null);
    ks.setKeyEntry("key-alias",(Key) key,password.tochararray(),new java.security.cert.Certificate[] { x509Certificate });
    ks.store(bos,password.tochararray());
    bos.close();
    return bos.toByteArray();

解决方法

如果使用openssl,则不必将完整的源代码复制到项目中,只需添加lib和头文件即可,因此可以使用openssl库而不会出现任何大小问题.
您可以使用openssl生成密钥和证书:
EVP_PKEY * pkey;
pkey = EVP_PKEY_new();

RSA * rsa;
rsa = RSA_generate_key(
        2048,/* number of bits for the key - 2048 is a sensible value */
        RSA_F4,/* exponent - RSA_F4 is defined as 0x10001L */
        NULL,/* callback - can be NULL if we aren't displaying progress */
        NULL    /* callback argument - not needed in this case */
);

EVP_PKEY_assign_RSA(pkey,rsa);

X509 * x509;
x509 = X509_new();

ASN1_INTEGER_set(X509_get_serialNumber(x509),1);

X509_gmtime_adj(X509_get_notBefore(x509),0);
X509_gmtime_adj(X509_get_notAfter(x509),31536000L);

X509_set_pubkey(x509,pkey);

X509_NAME * name;
name = X509_get_subject_name(x509);

X509_NAME_add_entry_by_txt(name,"C",MBSTRING_ASC,(unsigned char *)"CA",-1,0);
X509_NAME_add_entry_by_txt(name,"O",(unsigned char *)"MyCompany Inc.","CN",(unsigned char *)"localhost",0);

X509_set_issuer_name(x509,name);

//X509_sign(x509,pkey,EVP_sha1());

const EVP_CIPHER *aConst = EVP_des_ede3_cbc();

你可以用这些函数把它写成pem格式:

PEM_write_PrivateKey(f,NULL,NULL);


PEM_write_X509(
            f,/* write the certificate to the file we've opened */
            x509 /* our certificate */
);

之后可以将这些文件写入p12文件,源自此处:
https://github.com/luvit/openssl/blob/master/openssl/demos/pkcs12/pkwrite.c

/* pkwrite.c */

#include <stdio.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>

/* Simple PKCS#12 file creator */
int main(int argc,char **argv)
{
    FILE *fp;
    EVP_PKEY *pkey;
    X509 *cert;
    PKCS12 *p12;
    if (argc != 5) {
        fprintf(stderr,"Usage: pkwrite infile password name p12file\n");
        exit(1);
    }
    SSLeay_add_all_algorithms();
    ERR_load_crypto_strings();
    if (!(fp = fopen(argv[1],"r"))) {
        fprintf(stderr,"Error opening file %s\n",argv[1]);
        exit(1);
    }
    cert = PEM_read_X509(fp,NULL);
    rewind(fp);
    pkey = PEM_read_PrivateKey(fp,NULL);
    fclose(fp);
    p12 = PKCS12_create(argv[2],argv[3],cert,0);
    if(!p12) {
        fprintf(stderr,"Error creating PKCS#12 structure\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    if (!(fp = fopen(argv[4],"wb"))) {
        fprintf(stderr,argv[1]);
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    i2d_PKCS12_fp(fp,p12);
    PKCS12_free(p12);
    fclose(fp);
    return 0;
}

Java 9中的SunPKCS11提供程序

Java 9中的SunPKCS11提供程序

在Java 8之前,SunPKCS11提供程序的加载方式如下:

Provider provider = new sun.security.pkcs11.SunPKCS11 (new ByteArrayInputStream (configFile.getBytes ()));
Security.addProvider (provider);

configFile是带有配置参数的字符串。因此,如果应用程序需要使用多个连接的智能卡,则可以创建多个提供程序。要访问每个提供程序,使用的名称是“
SunPKCS11-”,后跟我们在配置中指示的名称。

在Java 8中,sun.security.pkcs11.SunPKCS11该类已在JDK中删除。因此,我必须通过反射对上一个调用进行编程。

Java 9中的PKCS#11提供程序的操作似乎非常不同:

  • SunPKCS11构造已更改为空单。配置是通过“ configure”方法加载的,因此必须将其保存在磁盘上的文件中,并且我无法再通过流将其加载到字符串中。

  • 如果我们尝试使用反射,则会出现以下警告:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by PruebaTarjeta

(file:/C:/temp/pkcs11java9/classes/) to constructor
sun.security.pkcs11.SunPKCS11()
WARNING: Please consider reporting this to the maintainers of
PruebaTarjeta
WARNING: Use –illegal-access=warn to enable warnings of further illegal
reflective access operations
WARNING: All illegal access operations will be denied in a future
release

  • 在Java 9中,将自动生成SunPKCS11提供程序,该程序位于加密提供程序的列表中。可以从列表中获取并进行配置。问题是您只能在列表中加载一个PKCS#11提供程序。在Java的9文档表明,我们可以得到的PKCS#11提供商,“SunPKCS11-”之后,我们在配置中指示的名字,但事实并非如此。如果我们查看提供商列表,则只有一个是“ SunPKCS11”,因此每个智能卡都不能有一个提供商。

别人也会这样吗?有什么办法吗?

java PKCS12 证书生成

java PKCS12 证书生成

引入依赖

<dependency>
                            <groupId>org.bouncycastle</groupId>
                            <artifactId>bcprov-jdk15on</artifactId>
                            <version>1.49</version>
                    </dependency>
                    <dependency>
                            <groupId>org.bouncycastle</groupId>
                            <artifactId>bcpkix-jdk15on</artifactId>
                            <version>1.49</version>
                    </dependency>

直接上代码

package test;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 成都一方思致科技有限公司
 *
 * @author 蒋昌宝
 * @version 1.0
 * @date 2019/8/23 9:26
 * @description 证书生成工具类
 * =========================================================================
 * 变更履历:
 * -------------------------------------------------------------------------
 * 变更编号     变更时间    变更人   变更原因    变更内容
 * -------------------------------------------------------------------------
 */

public class GenerateCertificateUtil {

private static KeyPair getKey() throws NoSuchAlgorithmException {
    // 密钥对 生成器,RSA算法 生成的  提供者是 BouncyCastle
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA",new BouncyCastleProvider());
    // 密钥长度 1024
    generator.initialize(1024);
    // 证书中的密钥 公钥和私钥
    KeyPair keyPair = generator.generateKeyPair();
    return keyPair;
}

/**
 * @param password  密码
 * @param issuerStr 颁发机构信息
 * @param subjectStr 使用者信息
 * @param certificateCRL 颁发地址
 * @return
 */
public static Map<String,byte[]> createCert(String password,String issuerStr,String subjectStr,String certificateCRL) {

    Map<String,byte[]> result = new HashMap<String,byte[]>();
    ByteArrayOutputStream out = null;
    try {
        //  生成JKS证书
        //  KeyStore keyStore = KeyStore.getInstance("JKS");
        //  标志生成PKCS12证书
        KeyStore keyStore = KeyStore.getInstance("PKCS12",new BouncyCastleProvider());
        keyStore.load(null,null);
        KeyPair keyPair = getKey();
        //  issuer与 subject相同的证书就是CA证书
        Certificate cert = generateCertificateV3(issuerStr,subjectStr,keyPair,result,certificateCRL,null);
        // cretkey随便写,标识别名
        keyStore.setKeyEntry("cretkey",keyPair.getPrivate(),password.tochararray(),new Certificate[] { cert });
        out = new ByteArrayOutputStream();
        cert.verify(keyPair.getPublic());
        keyStore.store(out,password.tochararray());
        byte[] keyStoreData = out.toByteArray();
        result.put("keyStoreData",keyStoreData);
        return result;
    } catch (Exception e) {
        e.printstacktrace();
    } finally {
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
            }
        }
    }
    return result;
}

/**
 * @param issuerStr
 * @param subjectStr
 * @param keyPair
 * @param result
 * @param certificateCRL
 * @param extensions
 * @return
 */
public static Certificate generateCertificateV3(String issuerStr,KeyPair keyPair,Map<String,byte[]> result,String certificateCRL,List<Extension> extensions) {

    ByteArrayInputStream bout = null;
    X509Certificate cert = null;
    try {
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        Date notBefore = new Date();
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(notBefore);
        // 日期加1年
        rightNow.add(Calendar.YEAR,1);
        Date notAfter = rightNow.getTime();
        // 证书序列号
        BigInteger serial = BigInteger.probablePrime(256,new Random());
        X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
                new X500Name(issuerStr),serial,notBefore,notAfter,new X500Name(subjectStr),publicKey);
        JcaContentSignerBuilder jBuilder = new JcaContentSignerBuilder( "SHA1withRSA");
        Secur删除eRandom secur删除eRandom = new Secur删除eRandom();
        jBuilder.setSecur删除eRandom(secur删除eRandom);
        ContentSigner singer = jBuilder.setProvider(  new BouncyCastleProvider()).build(privateKey);
        // 分发点
        ASN1ObjectIdentifier cRLdistributionPoints = new ASN1ObjectIdentifier( "2.5.29.31");
        GeneralName generalName = new GeneralName( GeneralName.uniformResourceIdentifier,certificateCRL);
        GeneralNames seneralNames = new GeneralNames(generalName);
        distributionPointName distributionPoint = new distributionPointName( seneralNames);
        distributionPoint[] points = new distributionPoint[1];
        points[0] = new distributionPoint(distributionPoint,null,null);
        CRLdistPoint cRLdistPoint = new CRLdistPoint(points);
        builder.addExtension(cRLdistributionPoints,true,cRLdistPoint);
        // 用途
        ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier( "2.5.29.15");
        // | KeyUsage.nonRepudiation | KeyUsage.keyCertSign
        builder.addExtension(keyUsage,new KeyUsage( KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
        // 基本限制 X509Extension.java
        ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
        builder.addExtension(basicConstraints,new BasicConstraints(true));
        // privKey:使用自己的私钥进行签名,CA证书
        if (extensions != null){
            for (Extension ext : extensions) {
                builder.addExtension(
                        new ASN1ObjectIdentifier(ext.getoid()),ext.isCritical(),ASN1Primitive.fromByteArray(ext.getValue()));
            }
        }
        X509CertificateHolder holder = builder.build(singer);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        bout = new ByteArrayInputStream(holder.toASN1Structure() .getEncoded());
        cert = (X509Certificate) cf.generateCertificate(bout);
        byte[] certBuf = holder.getEncoded();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 证书数据
        result.put("certificateData",certBuf);
        //公钥
        result.put("publicKey",publicKey.getEncoded());
        //私钥
        result.put("privateKey",privateKey.getEncoded());
        //证书有效开始时间
        result.put("notBefore",format.format(notBefore).getBytes("utf-8"));
        //证书有效结束时间
        result.put("notAfter",format.format(notAfter).getBytes("utf-8"));
    } catch (Exception e) {
        e.printstacktrace();
    } finally {
        if (bout != null) {
            try {
                bout.close();
            } catch (IOException e) {
            }
        }
    }
    return cert;
}

class Extension {

    private String oid;
    private boolean critical;
    private byte[] value;

    public String getoid() {
        return oid;
    }

    public void setoid(String oid) {
        this.oid = oid;
    }

    public boolean isCritical() {
        return critical;
    }

    public void setCritical(boolean critical) {
        this.critical = critical;
    }

    public byte[] getValue() {
        return value;
    }

    public void setValue(byte[] value) {
        this.value = value;
    }
}

/**

  • 测试证书生成
  • @throws Exception
    */
    public static void main(String[] args) throws Exception{
    // CN: 名字与姓氏 OU : 组织单位名称
    // O :组织名称 L : 城市或区域名称 E : 电子邮件
    // ST: 州或省份名称 C: 单位的两字母国-家代码
    String issuerStr = "CN=jcb凭证,OU=研发部,O=jcb有限公司,C=CN,[email protected],L=北京,ST=北京";
    String subjectStr = "CN=jcb有限公司,OU=用户,O=test,[email protected],ST=北京";
    String certificateCRL = "https://jcb.cn";
    Map<String,byte[]> result = GenerateCertificateUtil.createCert("123456",issuerStr,certificateCRL);
    // 生成.p12
    FileOutputStream outPutStream = new FileOutputStream("d:/keystore_jcb.p12");
    outPutStream.write(result.get("keyStoreData"));
    outPutStream.flush();
    outPutStream.close();
    //生成.cer颁发给用户的证书
    // FileOutputStream fos = new FileOutputStream(new File("d:/zheng.cer"));
    // fos.write(result.get("certificateData"));
    // fos.flush();
    // fos.close();
    }

}

关于Java不同类型密钥库之PKCS12和JCEKSjks密钥库使用专用格式的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于.NET Core RSA密钥的xml、pkcs1、pkcs8格式转换和JavaScript、Java等语言进行对接、iOS:如何以编程方式在应用程序中从私钥和x509certificate创建PKCS12(P12)密钥库?、Java 9中的SunPKCS11提供程序、java PKCS12 证书生成等相关知识的信息别忘了在本站进行查找喔。

本文标签:

上一篇Spine.js 1.6.0 发布,JavaScript 的 MVC 框架(js mvvm框架)

下一篇Java中Arrays类与Math类(java的arrays类)