最近确实比较忙,有一个SM2协同签名算法需要通过java实现,这个确实想了非常非常久,不过最近也差不多将这个项目初步解决了,等着后面的对接。项目顺利结束后,我会将在该项目中的所学分享出来,我觉得这个技术确实非常值得分享,因为从资料上确实很难找到,神奇的gpt虽然能提供思路但是并不符合给我的论文标准,所以我只能通过论文一行行翻成java代码写出,也得到了很多大佬的帮助。
后面有空也会继续ES的学习,然后近日除了上面的项目外,接了一个校验X509证书有效性的一个项目,这个项目有很多专业性的知识,比如OCSP和CRL,这个之前完全不知道,所以通过这篇文章分享一下我的所学。这篇文章更多的是概念,感兴趣的小伙伴可以了解一下。
我们如果对相关领域进行过一点学习的人,都应该对下面的java中的几个类非常熟悉,其实它们都和PKI有关:
java.security.KeyPair:表示公钥和私钥对,可用于加密和解密数据。
java.security.PublicKey:表示公钥,可用于验证数字签名或加密数据。
java.security.PrivateKey:表示私钥,可用于创建数字签名或解密数据。
java.security.cert.Certificate:表示数字证书,包括X509证书。
java.security.cert.X509Certificate:表示X509数字证书,常用于SSL / TLS安全协议中。
javax.net.ssl.SSLContext:提供安全套接字协议(SSL / TLS)的访问点。
javax.net.ssl.KeyManagerFactory:用于管理密钥的工厂类。
javax.net.ssl.TrustManagerFactory:用于管理信任的工厂类。
javax.crypto.Cipher:提供加密和解密功能的类。
javax.crypto.KeyGenerator:提供密钥生成器的类。这里是引用
这些类提供了处理PKI相关任务所需的基本API。使用这些类和API,开发人员可以构建安全的应用程序和服务,以确保网络通信的机密性、完整性和身份验证。
PKCS是公钥密码学标准(Public-Key Cryptography Standards)的缩写,是由RSA安全公司和其他一些安全公司共同发布的一系列密码学标准。
PKCS包括许多不同的标准,其中一些最常见的是:
PKCS#1:定义了RSA加密算法、数字签名算法以及散列函数等。
PKCS#7:定义了加密消息语法(CMS),用于在网络上传输被加密过的数据。
PKCS#8:定义了私钥信息语法标准,用于在网络上传输私钥。
PKCS#9:定义了扩展证书属性以及基于PKI应用的相关信息。
PKCS#10:定义了证书请求语法标准,用于向证书颁发机构(CA)请求数字证书。
PKCS#11:定义了加密设备API标准,允许应用程序与安全令牌、智能卡等加密设备进行交互。
PKCS#12:定义了个人信息交换语法标准,用于在不同平台之间交换个人身份信息、私钥和证书等。
可能大家比较熟悉的是p1,p7,p10,p12
在java中,我们一般比较熟悉PdfPKCS7这个类
PdfPKCS7是iText库中的一个类,用于实现数字签名和加密PDF文件,该类提供了以下主要方法:
getEncodedPKCS7(byte[] hash, PdfSigner.CryptoStandard subfilter, Certificate[] chain, OcspClient ocspClient, CrlClient crlClient, TSAClient tsaClient) //使用指定的哈希值对PDF文档进行数字签名,并返回签名结果的DER编码格式。
getAuthenticatedAttributeBytes(byte[] hash, PdfSigner.CryptoStandard subfilter, byte[] ocsp, byte[] crlBytes, long signingTime) //获取经过身份验证的属性数据。
getTimestampToken(byte[] imprint) //使用时间戳机构向签名添加时间戳。
其中,getEncodedPKCS7() 方法接受待签名数据的哈希值、签名类型、证书链、OCSP客户端、CRL客户端以及TSA客户端等参数,使用私钥对哈希值进行签名,并返回签名结果的DER编码格式。
getAuthenticatedAttributeBytes() 方法用于创建签名的身份验证属性。该方法接受待签名数据的哈希值、签名类型、OCSP响应、CRL字节数组、签名时间等参数,并返回经过身份验证的属性数据。
getTimestampToken() 方法用于在签名上添加时间戳。该方法接受待签名数据的哈希值,并返回经过时间戳机构签名的时间戳令牌。
PdfPKCS7类是iText库中实现数字签名的重要组成部分,它通过提供数字签名的核心算法和相关参数,实现了对PDF文档进行加密和签名的功能。
在java中,我们一般可以分为以下几步:
1.选择秘钥对的生成厂商,比如代码的第一行我们选择BC作为初始化密钥⼯⼚
2.生成密钥对,包括公钥,私钥
3.生成Dn,它主要包含客户信息,在java中的体现主要是下面的X500Name的构造过程
4.通过公钥,Dn生成证书请求CSR
5、用私钥对证书请求CSR进行签名,确保证书请求确实来自本人
6、构造P10
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator localKeyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
localKeyPairGenerator.initialize(256);
KeyPair localKeyPair = localKeyPairGenerator.genKeyPair();
X500NameBuilder localX500NameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
localX500NameBuilder.addRDN(BCStyle.CN, "39dian test");
localX500NameBuilder.addRDN(BCStyle.C, "CN");
localX500NameBuilder.addRDN(BCStyle.O, "39dian blog");
localX500NameBuilder.addRDN(BCStyle.L, "shanghai");
localX500NameBuilder.addRDN(BCStyle.ST, "shanghai");
localX500NameBuilder.addRDN(BCStyle.EmailAddress, "[email protected]");
X500Name localX500Name = localX500NameBuilder.build();
JcaPKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(localX500Name, localKeyPair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SM3WITHSM2");// 签名算法
ContentSigner signer = csBuilder.build(localKeyPair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);// PKCS10的请求
System.out.println(Base64.encodeBase64String(csr.getEncoded()));
}
然而,在传输过程中,如果未对PKCS#12文件进行适当的保护,文件内容可能会被截获并且可能会被恶意方访问到其中的私钥等敏感信息。因此,在传输PKCS#12文件之前需要采取一系列措施来确保它们的安全性,例如使用安全协议(如HTTPS)进行传输、使用加密算法对文件进行加密等等。
不过我们一般对于pfx文件,要么是内部进行传输,几乎不存在向外传输的可能,要么就只是做一个存储备份的功能,以防私钥等重要信息丢失。比如将pfx文件存进db,并且限制访问到这些数据的人员范围,以保证私钥和证书等敏感信息不会丢失。