龙空技术网

java 数字签名以及证书生成

javabus 127

前言:

当前同学们对“sm3算法数字证书签名接口”大概比较注重,各位老铁们都想要分析一些“sm3算法数字证书签名接口”的相关知识。那么小编在网上汇集了一些有关“sm3算法数字证书签名接口””的相关内容,希望同学们能喜欢,各位老铁们一起来学习一下吧!

大纲数字签名数字签名的过程单向散列函数,哈希函数国产商用密码算法(国密)证书颁发机构CA使用 openssl自行生成用户证书通过 java 代码生成证书,密钥对

数字签名

数据的完整性 : 传输数据的双方都总希望确认消息未在传输的过程中被修改

数字签名技术: 将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者用发送者的公钥解密被加密的摘要信息, 然后用HASH函数对收到的原文产生一个摘要信息 ,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改, 否则说明信息被修改过,因此数字签名能够验证信息的完整性

数字签名涉及到哈希函数、接收者的公钥、发送方的私钥.

数字签名是非对称密钥加密技术与数字摘要技术的应用.

数字签名有两种功效:

能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。数字签名能确定消息的完整性。因为数字签名的特点是它代表了文件的特征,文件如果发生改变,数字摘要的值也将发生变化。不同的文件将得到不同的数字摘要。

个人开发过程中数字签名常用场景:

微信支付宝 api 接口验签支付类接口,银行接口对接 验签

数字签名的过程

每个人都有一对“钥匙”(密钥对),其中私钥由本人保管,公钥对外公开。消息发送者用私钥签名,消息接受者使用公钥验证签名,确认消息真实完整。

1 发送报文时,

发送方用一个哈希函数从报文文本中"生成报文摘要",然后用发送方的私钥"对报文摘要进行加密"(这个摘要非对称加密后的密文,也就是数字签名), - 这个"加密后的摘要"将作为报文的数字签名和报文一起发送给接收方,

2 接收方

首先用与发送方一样的哈希函数"从接收到的原始报文中计算出报文摘要"接着再"用发送方的公钥" 来对"报文的数字签名进行解密" (解密后的摘要),把上一步得到的两份摘要进行比较、如果两份摘要相等,说明消息是真实完整的

单向散列函数,哈希函数

参考文档

单向散列函数有一个输入和一个输出,其中输入的称为消息,输出的称为散列值,

单项散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性

单向散列函数特点

单向性 消息不同散列值也不同 根据任意长度的消息计算出固定长度的散列值 能够快速计算出散列值

专有名词

碰撞:两个不同的消息产生同一个散列值的情况称为碰撞 单向散列函数也称为消息摘要函数、哈希函数或者杂凑函数,输入单向散列函数的消息也称为"原像",输出的散列值也称为"消息摘要或者指纹"

单项散列函数的具体例子: MD4 MD5 SHA1 SHA-224 SHA-256 SHA-384 SHA-512

- MD4和MD5(MD是消息摘要的缩写) MD4是由Rivest于1990年设计的单向散列函数,能够产生128比特的散列值,不过由于Dobbertin提出寻找MD4散列碰撞的方法,因此现在它已经不安全了 MD5是由Rivest于1991年设计的单向散列函数,能够产生128比特的散列值,比MD4更复杂,更安全

- SHA-1、SHA-256、SHA-384、SHA-512 SHA-1是由NIST设计的一种能够产生160比特的散列值的单项散列函数,SHA-1的消息长度存在上限,但这个值接近2^64比特

- SHA-256、SHA-384、SHA-512 SHA-256、SHA-384、SHA-512都是由NIST设计的单向散列函数,他们的散列值长度分别为256比特、384比特、512比特。 这些单向散列函数合起来统称SHA-2,他们的消息长度也存在上限,分别为2^64、2^128、2^128比特

单项散列函数的实际应用

检测软件是否被篡改 基于口令的加密 消息认证码 数字签名 为随机数生成器 一次性口令

国产商用密码算法(国密)

> 参考文档

> 国产商密算法是我国自主研发、具有自主知识产权的一系列密码算法,具有较高安全性,由国家密码局公开并大力推广

> 我国公开的国产商用密码算法包括SM1、SM2、SM3、SM4、SM7、SM9及祖冲之算法,> 其中SM2、SM3、SM4最为常用,用于对应替代RSA、DES、3DES、SHA等国际通用密码算法体系

证书颁发机构CA

> 证书颁发机构,即认证中心CA (Certification Authority),来将公钥与其对应的实体(人或机器)进行绑定(binding);即给公司或个人颁发证书

> 认证中心一般由政府出资建立。每个实体都有CA 发来的证书(certificate),里面有公钥及其拥有者的标识信息。此证书被 CA 进行了数字签名。任何用户都可从可信的地方获得认证中心 CA 的公钥,此公钥用来验证某个公钥是否为某个实体所拥有。有的大公司也提供认证中心服务

使用 openssl自行生成用户证书

生成证书需要使用openssl工具。

在生成证书的具体步骤之前,我们需要知道几个与证书相关的文件格式,

所有这些格式都属于PKCS(The Public-Key Cryptography Standards)标准:

.key文件:私钥文件,通常使用rsa算法,私钥需要自己保存,无需提交给CA机构

.csr文件:证书签名请求(证书请求文件),含有公钥信息,certificate signing request的缩写。生成该文件时需要用到自己的私钥。

.crt文件:CA认证后的证书文件,certificate的缩写。

.crl文件:证书吊销列表,Certificate Revocation List的缩写

.pem文件:用于导出,导入证书时候的证书的格式。该文件实际上是.crt文件和.key文件的合体,与windows下使用.pfx类似,不同的是.pem使用base64字符存储,而.pfx使用二进制存储。

通常情况,我们部署在内网的服务会采用自签名的证书

生成私钥(.key)-->生成证书请求(.csr)-->用CA根证书签名得到证书(.crt) 参考文档 使用脚本生成自定义证书

1 生成私钥-使用des3算法 (会让输入私钥密码,然后生成private-rsa.key私钥文件)openssl genrsa -des3 -out private-rsa.key 1024 2 使用私钥文件生成证书申请文件 (过程中需要私钥密码,并且填入一些信息)2.1 生成.csr 文件openssl req -new -key private-rsa.key -out ca.csr2.2 用户证书openssl x509 -req -days 365 -in ca.csr -signkey private-rsa.key -out public-rsa.crt也可以将 3.1 和 3.2 步骤合并生成证书 (.cer 和.crt 应该只是后缀不一致)openssl req -new -x509 -key private-rsa.key -days 3650 -out public-rsa.cer  ## 生成证书文件后,在 winddows 系统下是可以直接查看公钥信息的  有时需要用到pem格式的证书,可以用以下方式合并证书文件(crt)和私钥文件(key)来生成cat server.crt server.key > server.pem生成pfx即PKCS格式证书openssl pkcs12 -export -name test-alias -in public-rsa.cer -inkey private-rsa.key -out user-rsa.pfx

通过 java 代码生成证书,密钥对

参考文档

private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(),        x9ECParameters.getG(), x9ECParameters.getN());private static ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(),        x9ECParameters.getG(), x9ECParameters.getN());static {    if (Security.getProvider("BC") == null) {        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());    }}public static void main(String[] args) {    //生成密钥对    KeyPair kp = generateKeyPair();        //获取公钥    PublicKey publicKey = kp.getPublic();        //获取私钥    PrivateKey privateKey = kp.getPrivate();        //明文    String text = "SM2 Demo";    byte[] encrypt = encrypt(text.getBytes(), publicKey, "C1C3C2");    System.out.println(Base64.encodeBase64String(encrypt));        encrypt = decrypt(encrypt, privateKey, "C1C3C2");    System.out.println(new String(encrypt));}private static KeyPair generateKeyPair() {    try {        //根据算法名称 创建KeyPairGenerator对象  ;该对象为指定算法生成公钥/私钥对        // getInstance(String algorithm, String provider) /        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");        kpGen.initialize(ecParameterSpec, new SecureRandom());        return kpGen.generateKeyPair();    } catch (Exception e) {        throw new RuntimeException("算法不存在",e);    } }private static byte[] encrypt(byte[] data, PublicKey key, String standard) {    if ("C1C2C3".equals(standard)) {        return encryptNew(encryptOld(data, key));    }    return encryptOld(data, key);}private static byte[] decrypt(byte[] data, PrivateKey key, String standard) {    if ("C1C2C3".equals(standard)) {        return decryptOld(decryptNew(data), key);    }    return decryptOld(data, key);}private static byte[] encryptOld(byte[] data, PublicKey key) {    BCECPublicKey bcecPublicKey = (BCECPublicKey) key;    ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);    SM2Engine sm2Engine = new SM2Engine();    sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));    try {        return sm2Engine.processBlock(data, 0, data.length);    } catch (InvalidCipherTextException e) {        throw new RuntimeException(e);    }}private static byte[] encryptNew(byte[] c1c2c3) {    final int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;    final int c3Len = 32;    byte[] result = new byte[c1c2c3.length];    System.arraycopy(c1c2c3, 0, result, 0, c1Len);    System.arraycopy(c1c2c3, c1c2c3.length - c3Len, result, c1Len, c3Len);    System.arraycopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.length - c1Len - c3Len);    return result;}private static byte[] decryptOld(byte[] data, PrivateKey key) {    BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) key;    ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(), ecDomainParameters);    SM2Engine sm2Engine = new SM2Engine();    sm2Engine.init(false, ecPrivateKeyParameters);    try {        return sm2Engine.processBlock(data, 0, data.length);    } catch (InvalidCipherTextException e) {        throw new RuntimeException(e);    }}private static byte[] decryptNew(byte[] c1c3c2) {    final int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;    final int c3Len = 32;    byte[] result = new byte[c1c3c2.length];    System.arraycopy(c1c3c2, 0, result, 0, c1Len);    System.arraycopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.length - c1Len - c3Len);    System.arraycopy(c1c3c2, c1Len, result, c1c3c2.length - c3Len, c3Len);    return result;}

标签: #sm3算法数字证书签名接口