数据为什么要加密?
很喜欢的一句话:
信息时代,密码是生命线
很多内容为什么要加密?
当然是为了保密。
最早的密码应用,都伴随着阴谋与战争。
中国古代的“阴符”、“阴书”就是其中的代表。
到了近代,二战最著名的一个故事,就是纳粹德国的Enigma密码机
以及图灵和他发明的密码破解机。
可以说,现代战争中,信息安全极其重要
如果你的部署、命令都被对手知道
你收到的指令都是对手伪造的
这还怎么打?
在当下,加密数据和密码的应用,
从军事,到商业领域,以及科学界
乃至每个人普通的生活
如果没有数据加密,每个人的信息都是透明的
想想可怕的电话诈骗,你还觉得自己的信息安全吗?
有一句话说的是:
大数据时代,没有秘密
加密方式
最常见的计算机加密方式有三种:
对称、非对称、摘要
对称的意思是:
我有一个秘钥K,能把原文 A 加密成 A1,还能把 A1 还原成 A f(A, K) =A1 f(A1, K) =A
对称加密用途最为广泛,
操作简单,速度快,
适合场合多样
但缺点很明显,秘钥K太关键了
如果你需要让密文被其他授信的人访问
必须给他发秘钥
但问题是,
只要得到秘钥,就能破解一切,包括非法用户
非对称安全性稍微高一点
有2个秘钥,一般是成对的公钥和私钥
通常是用公钥加密,私钥解密
这种情况下,解决了对称加密的发送秘钥问题
现在公钥是公开的,私钥只有我自己有
永远不发送,就不会泄密
摘要加密一般采用的是hash算法,
只加密不解密,
适合于只验证对不对,而不验证是什么。
举个朴素例子:
二中的学生,学号格式是 L220130103 格式
三中的学生,学号格式是 PLE821 格式
现在我要验证这个人是哪个学校的,
其实无需关注具体内容,
简单判断一下长度就可以了
当然真正的算法没这么简单
下面具体来谈
便于大家统一理解
我们建一个项目
统一使用hutool工具包
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.5</version> </dependency>
对称加密
最简单的是des方法
他使用一个简单的秘钥,就可以实现加密和解密
我们写一个junit的test,或者写一个main也可以
class Test1 { @Test void test() { String text0 = "这是原文"; String key = "xiaomian"; DES des = new DES(key.getBytes()); String text1=des.encryptBase64(text0); System.out.println(text1); } }
运行结果是 +iJWs7q8+dyiRBouA8lDBA==
我们使用秘钥 “xiaomian”,
把“这是原文”,加密成了一个看不懂的字符串
然后开始解密
class Test1 { @Test void test() { String key = "xiaomian"; DES des = new DES(key.getBytes()); String text2=des.decryptStr("+iJWs7q8+dyiRBouA8lDBA=="); System.out.println(text2); } }
运行结果是 这是原文
还是同一个key,
用相反的方法,把原文解出来了
操作非常简单。
des就是一个最简单的对称加解密方法
类似的还有aes算法
可以使用hutool工具包,
操作差不多
非对称加密
使用非对称的主要原因
就是 安全、安全、还是安全
非对称在性能方面和对称没得比
因此,建议非对称使用短数据场合
而长数据使用对称实现。
最常用的是RSA算法
首先要生成一对秘钥,这个就没法人工创造了
我们可以借助工具
class Test2 { @Test void test() { KeyPair pair = SecureUtil.generateKeyPair("RSA"); String privateKey = Base64.encode(pair.getPrivate().getEncoded()); System.out.println("privateKey:" + privateKey); String publicKey = Base64.encode(pair.getPublic().getEncoded()); System.out.println("publicKey:" + publicKey); } }
输出结果为:
privateKey:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALBgrUOQySQB72VrGyijYZcaNM26t49oaKlNddu4SLpEdJzpUnVjXtIi9Nj/DkFBXgSB9FYdrv7MpQWzTmLw0do6pcfo2cekmBGPnFRdChtEf8Npq0pAV2LlNahwkB8fxZcbQYaaWBuBkx7aHT09JGsEpi9P3y7ae4vwYmFlWgEHAgMBAAECgYBVBnXgEWb1Zb1rLaPNBl3gQrDb0Dv29QUnQIElZ4QfzypMDipDDqFCObnA9cuAZ6uUDrWj4fFfQXX39oU+KwtuESddT9rJw1hPSy2i5ityEyYO5OZQRJaTVWPWzpph+bqFLkngaOvlr3OBG7YtywUL0P8toz2pOQKpoQOkffetuQJBAP26GKiOcs/sKhrzuM/t0S2ERXXDcu07jWxJ8gioQBuQaM7AA14tbiRzaZm3Xt+cGPjHJUGEJpDvGLQ9MavEZDMCQQCx9S+JevTGpxHMX/R3uUawlTsks1keyd0rqBtqQQx7V9Bm8htrlVU3QbhacFd/FJodWX7mGOAO6nLVGK/5qXvdAkB13zSBadvwuDg/WSZsgoEA8kgKk4gaqeXjft7QIsnVhFsMYauu3tAiYvOWE9ghbbU0LeAi9a+s+UayxRMERzJ9AkA5Y7fL32I2+kQMI9nEDnUUl1u2bzxLaJAx9wm4T3gGAwDLYkKjhEoyArjAOcCN1AgLdQQuklEXnlYgENEXc6flAkEAwDbTBfOtuP/6S5nU0gX9D5fYlF/fz4YTfBjHC2dZ/wrmWlJA0f7QFf5DysQB9AXJX6ZWL/3LkMtHPafqBMKpJw== publicKey:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwYK1DkMkkAe9laxsoo2GXGjTNurePaGipTXXbuEi6RHSc6VJ1Y17SIvTY/w5BQV4EgfRWHa7+zKUFs05i8NHaOqXH6NnHpJgRj5xUXQobRH/DaatKQFdi5TWocJAfH8WXG0GGmlgbgZMe2h09PSRrBKYvT98u2nuL8GJhZVoBBwIDAQAB
看吧,鬼也看不懂
不过能用就行
接下来,开始使用秘钥对,进行加密和解密
class Test2 { static String privateKey; static String publicKey; @BeforeAll static void createKey() { KeyPair pair = SecureUtil.generateKeyPair("RSA"); privateKey = Base64.encode(pair.getPrivate().getEncoded()); System.out.println("privateKey:" + privateKey); publicKey = Base64.encode(pair.getPublic().getEncoded()); System.out.println("publicKey:" + publicKey); } @Test void test() { String text = "这是原文"; RSA rsa = new RSA(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue(), privateKey, publicKey); String text1 = rsa.encryptBase64(text, KeyType.PublicKey); System.out.println("公钥加密: " + text1); String text2 = rsa.decryptStr(text1, KeyType.PrivateKey); System.out.println("私钥解密: " + text2); } }
输出结果为:
公钥加密: KSifTf6tS6LGlBT9LJC33VXzkXtaQEIGJcpf1BU2ptzRXTtBzvjx83EffCqntD7/M7ZciTr4MIBFBPFCxLs9NVEeC4K9/B8fQE/3hdsMzWBTnKQzQR2vd1i5mOgFaHYwTLwrq9Dbkv1YGluCb004YtLEqdjSO/Oljs7x2YVtvGc= 私钥解密: 这是原文
也可以反过来用
@Test void test() { String text = "这是原文"; RSA rsa = new RSA(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue(), privateKey, publicKey); String text1 = rsa.encryptBase64(text, KeyType.PrivateKey); System.out.println("私钥加密: " + text1); String text2 = rsa.decryptStr(text1, KeyType.PublicKey); System.out.println("公钥解密: " + text2); }
私钥加密: Ty5YGXHUajKHtlmQ7yGYJtc39Rjb3IvSIm7WWg4+Ge6u8MDeJ3TLYZokgBbAMZRcZBZ8bIWiou12+KxoW8moRwke4PlWVipgwhC2l6qo7WtTMiwnGh+0+B8wnY3OySFK4ZeOMQFgYuiTL2uZqofLXyNzwID7GKCfWI6EL29wtbE= 公钥解密: 这是原文
对称算法的特点就是
随便先用谁,然后用另一个解
一般来说,有意义的信息,加密传递
建议使用 公钥加密,私钥解密
这种方法,确保信息只能由你指定的对象收到
另一种反过来的做法,
私钥加密,公钥解密
用于数字签名场合
证明这个签名是某人做的
因为只有他有他自己的私钥
摘要加密
摘要加密是单向的
能加不能解
主要目的是生成特征码
常用算法包括 md5,sha 等等
class Test3 { @Test void test() { String text = "这是原文"; String text1 = DigestUtil.md5Hex(text); System.out.println(text1); } }
输出结果是:
531ffeed49bb13a6cf93049cc1e5ee53
比如系统密码,一般采用摘要加密
假设我的密码是 123456,
md5之后变成了 e10adc3949ba59abbe56e057f20f883e
如果有人能看到数据库表,
哪怕他找到了我的密码 e10adc3949ba59abbe56e057f20f883e,
也不知道我实际的密码是123456
当登录时,会对用户输入的密码再次md5,
如果结果还等于e10adc3949ba59abbe56e057f20f883e,
就表示输对了密码。
摘要加密的特点是
输出结果位数是固定的
比如上面列出的md5,加密后永远是固定长度
他的特点主要是:
输入不同,加密结果就不同 输入相同,加密结果一定相同
现在一般md5用的也少,主要是长度和复杂度
一般使用 sha256 或 sha512
他可以做简化验证
比如,我有一个文档,大小为 100M
如何验证他的内容发生窜改
我们不可能拿2个100M的文件,逐个字节比较
这时,只要对2者分别做摘要运算,
得到一个短的字符串,对他们比较就可以了
这种验证的特点是:我知道你对和不对,但我不知道哪错了
总结
三种方法中,一般使用原则是
- 速度快,用对称
- 安全高/数据少,用非对称
- 用于验证对错,保留特征码,用摘要
大家可以试试,顺便安利一下hutool,
非常优秀的工具包
之后我们会专文介绍国密算法