网站首页 > java教程 正文
大纲
- 数字签名
- 数字签名的过程
- 单向散列函数,哈希函数
- 国产商用密码算法(国密)
- 证书颁发机构CA
- 使用 openssl自行生成用户证书
- 通过 java 代码生成证书,密钥对
数字签名
数据的完整性 : 传输数据的双方都总希望确认消息未在传输的过程中被修改
数字签名技术: 将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者用发送者的公钥解密被加密的摘要信息, 然后用HASH函数对收到的原文产生一个摘要信息 ,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改, 否则说明信息被修改过,因此数字签名能够验证信息的完整性
数字签名涉及到哈希函数、接收者的公钥、发送方的私钥.
数字签名是非对称密钥加密技术与数字摘要技术的应用.
数字签名有两种功效:
- 能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。
- 数字签名能确定消息的完整性。因为数字签名的特点是它代表了文件的特征,文件如果发生改变,数字摘要的值也将发生变化。不同的文件将得到不同的数字摘要。
个人开发过程中数字签名常用场景:
- 微信支付宝 api 接口验签
- 支付类接口,银行接口对接 验签
数字签名的过程
每个人都有一对“钥匙”(密钥对),其中私钥由本人保管,公钥对外公开。消息发送者用私钥签名,消息接受者使用公钥验证签名,确认消息真实完整。
1 发送报文时,
- 发送方用一个哈希函数从报文文本中"生成报文摘要",
- 然后用发送方的私钥"对报文摘要进行加密"(这个摘要非对称加密后的密文,也就是数字签名), - 这个"加密后的摘要"将作为报文的数字签名和报文一起发送给接收方,
2 接收方
- 首先用与发送方一样的哈希函数"从接收到的原始报文中计算出报文摘要"
- 接着再"用发送方的公钥" 来对"报文的数字签名进行解密" (解密后的摘要),
- 把上一步得到的两份摘要进行比较、如果两份摘要相等,说明消息是真实完整的
单向散列函数,哈希函数
参考文档 https://blog.csdn.net/Q221022/article/details/123298302
单向散列函数有一个输入和一个输出,其中输入的称为消息,输出的称为散列值,
单项散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性
单向散列函数特点
- 单向性 消息不同散列值也不同
- 根据任意长度的消息计算出固定长度的散列值
- 能够快速计算出散列值
专有名词
- 碰撞:两个不同的消息产生同一个散列值的情况称为碰撞
- 单向散列函数也称为消息摘要函数、哈希函数或者杂凑函数,输入单向散列函数的消息也称为"原像",输出的散列值也称为"消息摘要或者指纹"
单项散列函数的具体例子: 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比特
单项散列函数的实际应用
- 检测软件是否被篡改
- 基于口令的加密
- 消息认证码
- 数字签名
- 为随机数生成器
- 一次性口令
国产商用密码算法(国密)
> 参考文档 https://zhuanlan.zhihu.com/p/132352160
> 国产商密算法是我国自主研发、具有自主知识产权的一系列密码算法,具有较高安全性,由国家密码局公开并大力推广
> 我国公开的国产商用密码算法包括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)
- 参考文档 https://zhuanlan.zhihu.com/p/423506052
- 使用脚本生成自定义证书 https://www.jianshu.com/p/3361fdba88aa
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.csr
2.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 代码生成证书,密钥对
参考文档 https://blog.csdn.net/weixin_43915808/article/details/114210542
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;
}
猜你喜欢
- 2024-10-04 谷歌Bard可使用C++、Python等20多种语言生成、调试和注释代码
- 2024-10-04 java代码生成word文档(1)(java代码生成xml文件)
- 2024-10-04 GitHub 2W 星:一键生成前后端代码
- 2024-10-04 【Spring系列】10 MyBatis-Plus 如何自动生成代码 #java
- 2024-10-04 一键生成前后端代码,一个36k星的企业级低代码平台
- 2024-10-04 推荐一个基于SpringBoot + Mybatis + Vue的代码生成器
- 2024-10-04 一个简单的代码生成器(代码生成器思路)
- 2024-10-04 Java 开源的支持多种sql的基于spring boot的代码生成器的调试
- 2024-10-04 java开发开源工具,api文档自动生成工具
- 2024-10-04 使用mybatis-generator自动生成代码(附GitHub下载地址)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)