1、编码与解码
1.1、介绍




编码按适用范围可以简单分为:
- 美国编码(ASCII)
ASCII为基础编码,来源于美国;
其它编码都兼容ASCII编码; - 欧盟编码(ISO8859-1、WINDOWS-1252)
先是ISO-8858-1,后升级为WINDOWS-1252。两者互不兼容。 - 中华编码(GB2312、GBK、GB18030)
先是GB2312,接着GBK,最后是GB18030。字符数量依次扩容。 - 中国繁体编码(BIG5)
BIG5,主要用于港澳台。 - 世界编码(UNICODE)
世界编码:UNICODE,可以包括全世界所有编码,理论上可以存100多万字符。世界通用。不完全兼容基它编码。如BIG5编码的文件,用UNICODE打开后仍是乱码,但UNICODE可以显示繁体,要以UNICODE保存并打开。


1.2、URL编码
- URL编码是编码算法,不是加密算法
- URL编码的目的是把任意文本数据编码为%前缀表示的文本,便于浏览器和服务器处理
- URL编码是浏览器发送数据给服务器时使用的编码,它通常附加在URL的参数部分
例如:
https://www.baidu.com/s?wd=%E4%B8%AD%E6%96%87
之所以需要URL编码,是因为出于兼容性考虑,很多服务器只识别ASCII字符。但如果URL中包含中文、日文这些非ASCII字符怎么办?不要紧,URL编码有一套规则:
- 如果字符是
A`Z`,`a`z,0~9以及-、_、.、*,则保持不变; - 如果是其他字符,先转换为UTF-8编码,然后对每个字节以
%XX表示。
例如:字符
中的UTF-8编码是0xe4b8ad,因此,它的URL编码是%E4%B8%AD。URL编码总是大写。
- Java标准库提供了一个==URLEncoder.encode()==类来对任意字符串进行URL编码:
//编码
String encoded = URLEncoder.encode("中文!", StandardCharsets.UTF_8);
URLEncoder把空格字符编码成+,而现在的URL编码标准要求空格被编码为%20,不过,服务器都可以处理这两种情况
- 解码URLDecoder.decode
//解码
String decoded = URLDecoder.decode("%E4%B8%AD%E6%96%87%21", StandardCharsets.UTF_8);1.3、Base64编码
- Base64编码也是编码算法,不是加密算法
- Base64编码的目的是把任意二进制数据编码为文本,但编码后数据量会增加1/3
- 编码 Base64.getEncoder().encodeToString()
byte[] input = new byte[] { (byte) 0xe4, (byte) 0xb8, (byte) 0xad };
String b64encoded = Base64.getEncoder().encodeToString(input);
System.out.println(b64encoded);- 解码 Base64.getDecoder().decode()
byte[] output = Base64.getDecoder().decode("5Lit");
System.out.println(Arrays.toString(output)); // [-28, -72, -83]2、哈希算法
2.1、介绍
- 哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
- 哈希算法最重要的特点就是:
- 相同的输入一定得到相同的输出
- 不同的输入大概率得到不同的输出
- 哈希算法的目的就是为了验证原始数据是否被篡改
- Java字符串的
hashCode()就是一个哈希算法,它的输入是任意字符串,输出是固定的4字节int整数
2.2、哈希碰撞
- 哈希碰撞是指,两个不同的输入得到了相同的输出
"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0碰撞是一定会出现的,因为输出的字节长度是固定的,
String的hashCode()输出是4字节整数,最多只有4294967296种输出,但输入的数据长度是不固定的,有无数种输入。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞
- 碰撞不可怕,我们担心的不是碰撞,而是碰撞的概率,因为碰撞概率的高低关系到哈希算法的安全性。一个安全的哈希算法必须满足:
- 碰撞概率低;
- 不能猜测输出。
不能猜测输出是指,输入的任意一个bit的变化会造成输出完全不同,这样就很难从输出反推输入(只能依靠暴力穷举)
2.4、常用的哈希算法
算法 | 输出长度(位) | 输出长度(字节) |
MD5 | 128 bits | 16 bytes |
SHA-1 | 160 bits | 20 bytes |
RipeMD-160 | 160 bits | 20 bytes |
SHA-256 | 256 bits | 32 bytes |
SHA-512 | 512 bits | 64 bytes |
// 创建一个MessageDigest实例:
MessageDigest md = MessageDigest.getInstance("MD5");
// 反复调用update输入数据:
md.update("Hello".getBytes("UTF-8"));
md.update("World".getBytes("UTF-8"));
byte[] result = md.digest(); // 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6
System.out.println(new BigInteger(1, result).toString(16));2.4、哈希算法的用途
因为相同的输入永远会得到相同的输出,因此,如果输入被修改了,得到的输出就会不同
- 判断下载到本地的软件是原始的、未经篡改的文件。只需要自己计算一下本地文件的哈希值,再与官网公开的哈希值对比,如果相同,说明文件下载正确,否则,说明文件已被篡改
- 存储用户口令
2.5、防止彩虹表攻击
- 对每个口令额外添加随机数,称之为加盐(salt)
加盐的目的在于使黑客的彩虹表失效,即使用户使用常用口令,也无法从MD5反推原始口令
3、BouncyCastle
是一个提供了很多哈希算法和加密算法的第三方库
用法
3.1、加入jar包
bcprov-jdk15on-xxx.jar
3.2、注册BouncyCastle
- Java标准库的
java.security包提供了一种标准机制,允许第三方提供商无缝接入
// 注册BouncyCastle:
Security.addProvider(new BouncyCastleProvider());3.3、调用
// 按名称正常调用:
MessageDigest md = MessageDigest.getInstance("RipeMD160");
md.update("HelloWorld".getBytes("UTF-8"));
byte[] result = md.digest();
System.out.println(new BigInteger(1, result).toString(16));4、Hmac算法
- Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
- Hmac算法总是和某种哈希算法配合起来用的
例如,我们使用MD5算法,对应的就是HmacMD5算法,它相当于“加盐”的MD5:
HmacMD5 ≈ md5(secure_random_key, input)
- HmacMD5可以看作带有一个安全的key的MD5。使用HmacMD5而不是用MD5加salt,有如下好处:
- HmacMD5使用的key长度是64字节,更安全;
- Hmac是标准算法,同样适用于SHA-1等其他哈希算法;
- Hmac输出和原有的哈希算法长度一致。
- Hmac本质上就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key。
5、对称加密算法
- 对称加密算法使用同一个密钥进行加密和解密,常用算法有DES、AES和IDEA等;
- 密钥长度由算法设计决定,AES的密钥长度是128/192/256位;
- 使用对称加密算法需要指定算法名称、工作模式和填充模式。

6、口令加密算法
- PBE算法通过用户口令和安全的随机salt计算出Key,然后再进行加密;
- Key通过口令和安全的随机salt计算得出,大大提高了安全性;
- PBE算法内部使用的仍然是标准对称加密算法(例如AES)
7、密钥交换算法
- DH算法是一种密钥交换协议,通信双方通过不安全的信道协商密钥,然后进行对称加密传输。
- DH算法没有解决中间人攻击。
8、非对称加密算法
- 非对称加密就是加密和解密使用的不同的密钥:只有同一个公钥-私钥对才能正常加解密。
- 非对称加密的典型算法就是RSA算法,它是由Ron Rivest,Adi Shamir,Leonard Adleman这三个哥们一起发明的,所以用他们仨的姓的首字母缩写表示。
- 非对称加密相比对称加密的显著优点在于,对称加密需要协商密钥,而非对称加密可以安全地公开各自的公钥,在N个人之间通信的时候:使用非对称加密只需要N个密钥对,每个人只管理自己的密钥对。而使用对称加密需要则需要
N*(N-1)/2个密钥,因此每个人需要管理N-1个密钥,密钥管理难度大,而且非常容易泄漏。 - 非对称加密的缺点就是运算速度非常慢,比对称加密要慢很多
- 在实际应用的时候,非对称加密总是和对称加密一起使用
9、签名算法
数字签名就是用发送方的私钥对原始数据进行签名,只有用发送方公钥才能通过签名验证。
数字签名用于:
- 防止伪造;
- 防止抵赖;
- 检测篡改。
常用的数字签名算法包括:MD5withRSA/SHA1withRSA/SHA256withRSA/SHA1withDSA/SHA256withDSA/SHA512withDSA/ECDSA等。
10、数字证书
- 数字证书就是集合了多种密码学算法,用于实现数据加解密、身份认证、签名等多种功能的一种安全标准。
- 数字证书采用链式签名管理,顶级的Root CA证书已内置在操作系统中。
- 数字证书存储的是公钥,可以安全公开,而私钥必须严格保密。
















