文章目录
- 前言
- 1 数字签名简介
- 2 基本原理
- 3 数字证书
- 4 网页加密
- 5 edge的网站连接图标
- 6 代码实现
- 7 keytool工具使用
- 7.1 常用命令:
- 7.2 生成私钥公钥[未实践成功]
- 7.3 导出公钥
前言
- 有关keytool的使用部分,未实现,先记录下来!!
1 数字签名简介
- 数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
- 它是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。
- 一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
- 数字签名是非对称密钥加密技术与数字摘要技术的应用。
- 数字签名的含义是:在网络中传输数据时候,给数据添加一个数字签名,表示是谁发的数据,而且还能证明数据没有被篡改。
2 基本原理
话说张三有俩好哥们A、B。由于工作原因,张三和A,B写邮件的时候为了安全都需要加密。于是张三想到了数字签名:
- 第一步:加密采用非对称加密,张三有三把钥匙,两把公钥,送给朋友。一把私钥留给自己。
- 第二步:A或者B写邮件给张三:A先用公钥对邮件加密,然后张三收到邮件之后使用私钥解密。
- 第三步:张三写邮件给A或者B:
- 张三写完邮件,先用hash函数生成邮件的摘要,附着在文章上面,这就完成了数字签名,然后张三再使用私钥加密,就可以把邮件发出去。
- A或者是B收到邮件之后,先把数字签名取下来,然后使用自己的公钥解密即可。这时候取下来的数字签名中的摘要若和张三的一致,那就认为是张三发来的,再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。
3 数字证书
- 对签名进行验证时,需要用到公钥。如果公钥是伪造的,那我们无法验证数字签名了,也就根本不可能从数字签名确定对方的合法性了。这时候证书就闪亮登场了。我们可能都有考各种证书的经历,比如说普通话证书,四六级证书等等,但是归根结底,到任何场合我们都能拿出我们的证书来证明自己确实已经考过了普通话,考过了四六级。这里的证书也是同样的道理。
- 证书的生成
4 网页加密
一个应用“数字证书”的实例:https协议。这个协议主要用于网页加密
- 首先,客户端向服务器发出加密请求。
- 服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。
- 客户端(浏览器)的“证书管理器”,有“受信任的根证书颁发机构”列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。
- 如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。
5 edge的网站连接图标
- Microsoft Edge 浏览 Web 时,地址栏中会显示一个图标,指示与要访问的网站的连接的安全性。 此图标可帮助您确定是否可以安全发送和接收网站的信息。 连接会告知发送到站点和从站点发送的信息(如密码、地址或信用卡)是否安全发送,且无法被攻击者截获。 该连接不会告知站点信誉。 但是,如果地址是已知的钓鱼或恶意软件网站,Microsoft Defender SmartScreen 将确定并指示该地址。
- 地址栏中的连接图标具有四种不同的状态。 以下信息说明了每种状态的含义,并提供有关如何为浏览做出智能决策的提示:
- 连接安全 (有效的证书)
- 没有完全安全 (证书证书)
- 过期的安全配置 (无效、已过期、自签名)
- 可疑或危险网站 (网络仿冒或恶意软件)
- 连接安全 (有效的证书)
6 代码实现
package com.atguigu.Signature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class SignatureDemo {
public static void main(String[] args) throws Exception {
String a = "123";
PublicKey publicKey = getPublicKey( "a.pub","RSA");
PrivateKey privateKey = getPrivateKey("a.pri","RSA");
String signaturedData = getSignature(a, "sha256withrsa", privateKey);
boolean b = verifySignature(a, "sha256withrsa", publicKey, signaturedData);
System.out.println(b);
}
/**
* 读取公钥
* @param publicPath 公钥路径
* @param algorithm 算法
* @return
*/
public static PublicKey getPublicKey(String publicPath, String algorithm) throws Exception{
String publicKeyString = FileUtils.readFileToString(new File(publicPath), Charset.defaultCharset());
// 创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 创建公钥规则
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
return keyFactory.generatePublic(keySpec);
}
/**
* 读取私钥
* @param priPath 私钥的路径
* @param algorithm 算法
* @return 返回私钥的key对象
*/
public static PrivateKey getPrivateKey(String priPath, String algorithm) throws Exception{
String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
// 创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 创建私钥key的规则
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
// 返回私钥对象
return keyFactory.generatePrivate(keySpec);
}
/**
* 生成签名
*
* @param input : 原文
* @param algorithm : 算法
* @param privateKey : 私钥
* @return : 签名
* @throws Exception
*/
private static String getSignature(String input, String algorithm, PrivateKey privateKey) throws Exception {
// 获取签名对象
Signature signature = Signature.getInstance(algorithm);
// 初始化签名
signature.initSign(privateKey);
// 传入原文
signature.update(input.getBytes());
// 开始签名
byte[] sign = signature.sign();
// 对签名数据进行Base64编码
return Base64.encodeBase64String(sign);
}
/**
* 校验签名
*
* @param input : 原文
* @param algorithm : 算法
* @param publicKey : 公钥
* @param signaturedData : 签名
* @return : 数据是否被篡改
* @throws Exception
*/
private static boolean verifySignature(String input, String algorithm, PublicKey publicKey, String signaturedData) throws Exception {
// 获取签名对象
Signature signature = Signature.getInstance(algorithm);
// 初始化签名
signature.initVerify(publicKey);
// 传入原文
signature.update(input.getBytes());
// 校验数据
return signature.verify(Base64.decodeBase64(signaturedData));
}
}
7 keytool工具使用
- keytool工具路径:
C:\Program Files\Java\jdk-19\bin
7.1 常用命令:
- 生成keypair
keytool -genkeypair keytool -genkeypair -alias lisi(后面部分是为证书指定别名,否则采用默认的名称为mykey)
- 查看keystore中项目:
keytool -list或keytool -list -v keytool -exportcert -alias lisi -file lisi.cer
- 生成可打印的证书:
keytool -exportcert -alias lisi -file lisi.cer –rfc
- 显示数字证书文件中的证书信息:
keytool -printcert -file lisi.cer
- 直接双击lisi.cer,用window系统的内置程序打开lisi.cer
7.2 生成私钥公钥[未实践成功]
- 生成密钥证书 下边命令生成密钥证书,采用RSA 算法每个证书包含公钥和私钥
keytool -genkeypair -alias guigu -keyalg RSA -keypass guigugu -keystore guigu.jks -storepass guigugu
-
Keytool 是一个java提供的证书管理工具
-alias:密钥的别名 -keyalg:使用的hash算法 -keypass:密钥的访问密码 -keystore:密钥库文件名,xc.keystore保存了生成的证书 -storepass:密钥库的访问密码
- 查询证书信息
keytool -list -keystore guigu.jks
- 删除别名
keytool -delete -alias guigu -keystore guigu.jsk
7.3 导出公钥
- openssl是一个加解密工具包,这里使用openssl来导出公钥信息。
- 安装 openssl
- 安装资料目录下的Win64OpenSSL-1_1_0g.exe,配置openssl的path环境变量,如下图:
- cmd进入guigu.jks文件所在目录执行如下命令(如下命令在windows下执行,会把-变成中文方式,请将它改成英文的-):
keytool -list -rfc --keystore guigu.jks | openssl x509 -inform pem -pubkey
- 下面段内容是公钥
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvFsEiaLvij9C1Mz+oyAm
t47whAaRkRu/8kePM+X8760UGU0RMwGti6Z9y3LQ0RvK6I0brXmbGB/RsN38PVnh
cP8ZfxGUH26kX0RK+tlrxcrG+HkPYOH4XPAL8Q1lu1n9x3tLcIPxq8ZZtuIyKYEm
oLKyMsvTviG5flTpDprT25unWgE4md1kthRWXOnfWHATVY7Y/r4obiOL1mS5bEa/
iNKotQNnvIAKtjBM4RlIDWMa6dmz+lHtLtqDD2LF1qwoiSIHI75LQZ/CNYaHCfZS
xtOydpNKq8eb1/PGiLNolD4La2zf0/1dlcr5mkesV570NxRmU1tFm8Zd3MZlZmyv
9QIDAQAB
-----END PUBLIC KEY-----
- 将上边的公钥拷贝到文本public.key文件中,合并为一行,可以将它放到需要实现授权认证的工程中。