概述
行走江湖,安全第一 | 非对称加密算法设计与实现
- 一、非对称加密算法介绍与实现
- (1) 非对称加密简介
- (2)Java实现非对称加密
- 二、数字签名原理与实现
- (1) 数字签名原理介绍
- (2) Java实现数字签名
一、非对称加密算法介绍与实现
(1) 非对称加密简介
非对称加密算法
,亦称为现代加密算法,是计算机通信安全的基石,保证了加密数据不会被破解。与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey) 和私密(privatekey)。
特点:非对称加密算法中,公开密钥和私有密钥是一对。特点是公钥加密-私钥解密
;私钥加密-公钥解密
。因为加密和解密使用的是两个不同的密钥,所以这种算法才被叫作非对称加密算法。当然,事物也有两面性,由于非对称加密安全级别较高,所以处理数据的速度相对较慢。
【通俗易懂的理解非对称加密】
以A向B发生一个敏感文件需要加密为例????
- 对称加密就是:A用锁锁住文件,发给B,然后A再发钥匙给B,B拿到锁和钥匙,解锁文件。
- 非对称加密是:A要向B发文件,B把自己的锁发给A,A锁好后给B,B的钥匙一直在自己手上,>用自己的钥匙(私钥)解自己的锁(公钥),这样就不用担心钥匙在传递过程中被窃取。
ECC算法 和 RSA算法的比较
RSA算法
:国际标准算法,应用较早,最为普及,比ECC算法的适用范围更广,兼容性更好,一般采用 2048 位的加密长度,但是对服务端性能消耗高。
ECC算法
:中文名称为椭圆加密算法,新一代算法趋势主流,一般采用 256 位加密长度,加密速度快,效率更高,对服务器资源消耗低,而且最重要的是更安全,抗攻击型更强。
(2)Java实现非对称加密
下面的代码演示了使用Java实现非对称加密算法,主要实现了下面这些方法:
- 使用密钥解密数据:public static String
decryptRSA
(String algorithm, Key key, String encrypted)- 使用密钥加密数据:public static String
encryptRSA
(String algorithm, Key key, String input)- 生成密钥对并保存在本地文件中:private static void
generateKeyToFile
(String algorithm, String pubPath, String priPath)- 读取私钥:public static PrivateKey
getPrivateKey
(String priPath, String algorithm)- 读取公钥:public static PublicKey
getPublicKey
(String pulickPath, String algorithm)
/**
* description: RSAdemo 生成公钥和私钥
* @author: gql
* @date: 2021/10
*/
public class RSAdemo {
public static void main(String[] args) throws Exception {
String input = "匿名攻城狮";
System.out.println("原文内容是 = " + input);
// 表示使用RSA加密算法
String algorithm = "RSA";
// 生成密钥对并保存在本地文件中
generateKeyToFile(algorithm, "a.pub", "a.pri");
System.out.println("密钥对保存至本地成功!");
// 读取私钥和公钥
PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
PublicKey publicKey = getPublicKey("a.pub", algorithm);
//加密
String s = encryptRSA(algorithm, privateKey, input);
// 解密
decryptRSA(algorithm, publicKey, s);
}
/**
* 使用密钥解密数据
*
* @param algorithm : 算法
* @param encrypted : 密文
* @param key : 密钥
* @return : 原文
* @throws Exception
*/
public static String decryptRSA(String algorithm, Key key, String encrypted) throws Exception {
// 创建加密对象
// 参数表示加密算法
Cipher cipher = Cipher.getInstance(algorithm);
// 私钥进行解密
cipher.init(Cipher.DECRYPT_MODE, key);
// 由于密文进行了Base64编码, 在这里需要进行解码
byte[] decode = Base64.decode(encrypted);
// 对密文进行解密,不需要使用base64,因为原文不会乱码
byte[] bytes1 = cipher.doFinal(decode);
System.out.println("公钥解密后 = " + new String(bytes1));
return new String(bytes1);
}
/**
* 使用密钥加密数据
*
* @param algorithm : 算法
* @param input : 原文
* @param key : 密钥
* @return : 密文
* @throws Exception
*/
public static String encryptRSA(String algorithm, Key key, String input) throws Exception {
// 创建加密对象
Cipher cipher = Cipher.getInstance(algorithm);
// 加密的模式,使用私钥或公钥加密
cipher.init(Cipher.ENCRYPT_MODE, key);
// 私钥加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 对密文进行Base64编码
System.out.println("私钥加密后 = " + Base64.encode(bytes));
return Base64.encode(bytes);
}
/**
* 生成密钥对并保存在本地文件中
*
* @param algorithm : 算法选型
* @param pubPath : 公钥保存路径
* @param priPath : 私钥保存路径
* @throws Exception
*/
private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
// 创建密钥对生成器对象
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 生成私钥和公钥
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 获取私钥和公钥的字节数组
byte[] privateKeyEncoded = privateKey.getEncoded();
byte[] publicKeyEncoded = publicKey.getEncoded();
// 同时对私钥和公钥进行base64编码
String privateKeyString = Base64.encode(privateKeyEncoded);
String publicKeyString = Base64.encode(publicKeyEncoded);
System.out.println("生成私钥 = " + privateKeyString);
System.out.println("生成公钥 = " + publicKeyString);
// 保存文件
FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
}
/**
* 读取私钥
* @param priPath 私钥存放路径
* @param algorithm 算法
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(String priPath, String algorithm) throws Exception {
// 将文件内容转为字符串
String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
// 获取密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 构建密钥规范 进行Base64解码
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
// 生成私钥
return keyFactory.generatePrivate(spec);
}
/**
* 读取公钥
* @param pulickPath 公钥存放路径
* @param algorithm 算法
* @return
* @throws Exception
*/
public static PublicKey getPublicKey(String pulickPath, String algorithm) throws Exception {
// 将文件内容转为字符串
String publicKeyString = FileUtils.readFileToString(new File(pulickPath), Charset.defaultCharset());
// 获取密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 构建密钥规范 进行Base64解码
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
// 生成公钥
return keyFactory.generatePublic(spec);
}
}
代码运行后,控制台显示了如下内容,并在项目中生成了a.pri和a.pub两个txt文件,保存了私钥和密钥。
原文内容是 = 匿名攻城狮
生成私钥 = MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/AtIjVD/1uumo8rrDlXIa3eUIyxThYcXgC2Vfy7pmnM4XA6zXVciVcL9+f9hBT5lDHrl5q6j2mufnGx6M+JMyOe3ceNrhs63i0VWpZ4lWRsCBZab6uxdPwGqhMYBpdYcARo3WtN7kmZxWtJW3q22Gj6zpNOv6eHAIGSKHzQlqmnNcvLEflrc0LRbAaXDl0bAAqMVnyg33hJesiD1cwSONPEFXKC6UXoQGm1Y+bvCGFyMstWAW8oHk2ERC8ZA6OA0k9UjezW++KxhIH9J/eLKoXpGto0vAfQYyvTiaUIjUVqJuf3WROkbwlGYisf1KocbdNFJmuKgPGH057X46QqCTAgMBAAECggEASJ/z8gbYgr/ck6YmqLKrvddce+lrOP6J09PBaZj2eIlqOonlL8KoD1ndFWXafYqcRU7rSn2gMpNXVSGUjhj9Ln2kGM3Cu0or9S+OmGiLaUhhbVGPGYoFJQeOA1fk8TQEbnBlAZunm9dj//uNaVY+wIjkP48loggk4I9d97BXwjXrBkjALQmZ6LcIzKOFTkkoH+3ibISHY7PjjfmO+1KJ30rKuJlTEGLStMHvQW7rRbeJEst48JWYGy/Gg82paLHLsKXzkWaM4l5/sP3dMDRCMY9nlV1dtLFun60WFxyBhFBKH4KbLnB5TzatpO/yacE8He9mJgBmp+p9qOB2NlxtcQKBgQDoWhpEX8niNgqIASw7ZsZrsqK6ZmIDCwbtC9zj5c1HoGeLZaWIZ+LekxodHTDSVufkIAluUVsi/cttdb5DBIFmCAfcEmSu+atdp4/nvqrndft+fpMZ7DL8YKpajd8i5t4NFF7AIbM071YZCV8W3Xo5icv6HPkdctBS5aidaiLu7QKBgQDSc5X35fq+5qkBE3rp0ntzjXlPbJem5Y2jtFzjwper003g6g0Z1ojOUwNEen+taeaVI8LmCefozwLLYayPU+KeyWftJOfV8UculNWM3xNsvgf/Q/iDVxUNu9gqdlvRIrDWcsGwwrpBqFB6D4GhrYh5tinRe5ct+sSAgu5SRGpdfwKBgATlaSpJrnJi2yP0il8SElpQoFc3MxeHUvUJy/TNcd7xhV0NnkhakBBKn0E/zTiRdj97YVd+xWHeYTwEQCcfYC6rOqcriA2b2z2U+1ZR0T4hYVRQDH9+V7CzxMM1vB77KHC0Hi8ERsd1x6WtaeCMeDfgLHkvxRwWwEcO6devVd8dAoGBAII8b4lq9EKhYeM9l+oNjMJUwcbqD+uD0aSGYJm+ebgm2uIeVZ8wyZbNfo8pM8wwZjbTW7CaXr8PJM6SEoTcR7k2MK9sEGCwoPltt74m6tF3xGEvQiKdiHToU3zrpCSHUGJVwBHQYA1zyOHQqMtSJcwUdEqkLkmRD3vsCuo0VpKnAoGBAIE1HGHbnRtYJiUQx1GShBpnAOldTVNG/zkNXYviB5HqCOcXrvHEo7tZdNKPUIhIvkQ9enL00YxGxcKic1byccrR9JOCfZKpkwASfmZErK+QLt36RkluaJ3/h9EEcdLTJw8Zeb5KDeoOPtnbxlJeQ5hNp9W8OglTDUWEXOiUoXL8
生成公钥 = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwLSI1Q/9brpqPK6w5VyGt3lCMsU4WHF4AtlX8u6ZpzOFwOs11XIlXC/fn/YQU+ZQx65eauo9prn5xsejPiTMjnt3Hja4bOt4tFVqWeJVkbAgWWm+rsXT8BqoTGAaXWHAEaN1rTe5JmcVrSVt6ttho+s6TTr+nhwCBkih80JappzXLyxH5a3NC0WwGlw5dGwAKjFZ8oN94SXrIg9XMEjjTxBVygulF6EBptWPm7whhcjLLVgFvKB5NhEQvGQOjgNJPVI3s1vvisYSB/Sf3iyqF6RraNLwH0GMr04mlCI1Faibn91kTpG8JRmIrH9SqHG3TRSZrioDxh9Oe1+OkKgkwIDAQAB
密钥对保存至本地成功!
私钥加密后 = RD10/pSv/tnAWgereonEmobu3vxKgK6GACmUrBnaD8yj05IUvj54IN2DAyvsRdGijQDrEdbSIoIJOQen5g0UYjE6hHDhHTvuJqpNn+coJ3XcNQzQC4/ANij/hTZGFVX6AinhtqbZgpUDKoIhloJi+g9PV+MOuKgYVD7Fv96VDSbgR2bsuqFMDDIXtBCGQdR//KZmt7vKZGQTCjnP8PPcgnu68iayKFS/Ja38IYojl1F/JdrmNMM9zBJDTF/RfcHrGSAty68MZwopm1EQ8iSrpmM9DD/1y4Nr5jJmac14d57EmifqTfQH3oB+3kqvrSiyvDOof78zpcrQylyFs5epYA==
公钥解密后 = 匿名攻城狮
加密后-密文内容是 = RD10/pSv/tnAWgereonEmobu3vxKgK6GACmUrBnaD8yj05IUvj54IN2DAyvsRdGijQDrEdbSIoIJOQen5g0UYjE6hHDhHTvuJqpNn+coJ3XcNQzQC4/ANij/hTZGFVX6AinhtqbZgpUDKoIhloJi+g9PV+MOuKgYVD7Fv96VDSbgR2bsuqFMDDIXtBCGQdR//KZmt7vKZGQTCjnP8PPcgnu68iayKFS/Ja38IYojl1F/JdrmNMM9zBJDTF/RfcHrGSAty68MZwopm1EQ8iSrpmM9DD/1y4Nr5jJmac14d57EmifqTfQH3oB+3kqvrSiyvDOof78zpcrQylyFs5epYA==
解密后-原文内容是 = 匿名攻城狮
二、数字签名原理与实现
(1) 数字签名原理介绍
数字签名,亦称公钥数字签名。属于非对称加密技术应用之一,非对称加密技术主要有两大应用:
- 使用 公钥加密-私钥解密 的
加密通信
;- 使用 私钥加密-公钥解密 的
数字签名
。
数字签名的含义:在网络中传输数据的时候,给数据添加一个数字签名,表示是谁发的数据,而且还能证明数据没有被篡改。
数字签名的作用:认证、防止抵赖、防篡改
。
数字签名原理图
数字签名的典型应用:用于网页加密的https协议
①首先,客户端向服务器发出加密请求。
②服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。
③客户端(浏览器)的 “证书管理器”,有 “受信任的根证书颁发机构” 列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。
④如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。
⑤如果这张数字证书不是由受信任的机构颁发的,浏览器会发出另一种警告。
⑥如果数字证书是可靠的,客户端就可以使用证书中的服务器公钥,对信息进行加密,然后与服务器交换加密信息。
(2) Java实现数字签名
下面的代码演示了使用Java实现数字签名,主要实现了 签名算法 和 验证算法:
- 签名算法:private static String
getSignature
(String str, String algorithm, PrivateKey privateKey)
签名算法使用 私钥加密来生成签名。
注意:签名算法不会对文件加密,只对文件的Hash值进行了加密- 验证算法:private static boolean
verifySignature
(String str, String algorithm, PublicKey publicKey, String signaturedData)
验证算法使用 公钥解密-校验签名。
/**
* description: SignatureDemo 数字签名
* @author: gql
* @date: 2021/10
*/
public class SignatureDemo {
public static void main(String[] args) throws Exception {
String str = "Hudie";
System.out.println("原文是 = " + str);
// 从文件中获取私钥和公钥
PrivateKey privateKey = RSAdemo.getPrivateKey("a.pri", "RSA");
PublicKey publicKey = RSAdemo.getPublicKey("a.pub", "RSA");
/**
* 签名算法:
* 输入:文件、私钥(签名Key)
* 输出:数字签名
*/
String signaturedData = getSignature(str, "sha256withrsa", privateKey);
System.out.println("生成的数字签名是 = " + signaturedData);
/**
* 验证算法:
* 输入:文件、数字签名、公钥(验证Key)
* 输出:YES/NO
*/
boolean flag = verifySignature(str, "sha256withrsa", publicKey, signaturedData);
System.out.println("使用公钥和生成的签名进行验证: = " + flag);
}
/**
* 签名算法:
* 私钥加密-生成签名
* 注意:签名算法不会对文件加密,只对文件的Hash值进行了加密
* @param str : 原文
* @param algorithm : 算法
* @param privateKey : 私钥
* @return : 数字签名
* @throws Exception
*/
private static String getSignature(String str, String algorithm, PrivateKey privateKey) throws Exception {
// 获取签名对象
Signature signature = Signature.getInstance(algorithm);
// 初始化签名
signature.initSign(privateKey);
// 传入原文
signature.update(str.getBytes());
// 开始签名
byte[] sign = signature.sign();
// 对签名数据进行Base64编码
return Base64.encode(sign);
}
/**
* 验证算法:
* 公钥解密-校验签名
* @param str : 原文
* @param algorithm : 算法
* @param publicKey : 公钥
* @param signaturedData : 数字签名
* @return : 数据是否被篡改
* @throws Exception
*/
private static boolean verifySignature(String str, String algorithm, PublicKey publicKey, String signaturedData) throws Exception {
// 获取签名对象
Signature signature = Signature.getInstance(algorithm);
// 初始化签名
signature.initVerify(publicKey);
// 传入原文
signature.update(str.getBytes());
// 校验数据
return signature.verify(Base64.decode(signaturedData));
}
}
部分内容参考:b站数字签名原理
最后
以上就是冷静毛巾为你收集整理的行走江湖,安全第一 | 非对称加密算法介绍与实现一、非对称加密算法介绍与实现二、数字签名原理与实现的全部内容,希望文章能够帮你解决行走江湖,安全第一 | 非对称加密算法介绍与实现一、非对称加密算法介绍与实现二、数字签名原理与实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复