编码算法
URL 编码
来源
一些服务器只能识别 ASCII 字符,所以需要将其他字符转化为服务器能识别的。
编码方式
原本字符为 A-Z a-z 0-9 - _ . * 保持不变
其他字符先转化为 UTF-8 编码然后每个字写变为 %XX,组合在一起
实现
String URLEncoder.encode(String,charset);
String URLDecoder.decode(String,charset);
Base64 编码
来源
一些协议只能接收 ASCII 字符,对于二进制文件传输,需要一种编码方式将其转化为 ASCII
编码方式
将三字节数据分为四份,每份 6bit,然后只需要 64 种字符即可进行编码(A-Z a-z 0-9 + / =)
如果不足三字节用 0x00 补齐,对应字符为 = 补齐
实现
byte[] Base64.getEncoder().encode(byte[]);
byte[] Base64.getDecoder().decode(byte[]);
哈希算法
概念
对输入数据计算一个固定长度的摘要
特点
相同的输入得到相同的输出
不同的输入极大概率得到不同的输出
类型
MD5
128 bit
16 byte
SHA-1
160 bit
20 byte
SHA-256
256 bit
32 byte
SHA-512
512 bit
54 byte
实现
调用 MessageDigest.getInstance(String) 获取一个 MessageDigest 实例,其中参数 String 为哈希算法的名字,如 "MD5"
然后调用实例的方法 update(byte[]) 输入需要加密的数据,多次调用会进行数据拼接。
最后调用实例方法byte[] digest() 返回被哈希加密过的结果,返回为字节数组,可以自行转化为十六进制字符串
安全
原因
因为哈希算法相同输入必定相同输出,所以可以用哈希表进行哈希碰撞,得到明文。
解决
所以可以在明文加密的时候,往里面 “加盐” ,即添加一些无法预测的参数,改变其明文内容,防止哈希碰撞出明文。
实现
Hmac ( Hash-based Message Atuthentication Code ) 即 密钥散列消息认证码来作为盐。
1. 用 KeyGenerator.getInstance("HmacMD5") 来获取一个 keyGen 实例作为盐的生成器,里面填充Hash 算法类型。
2. 用 KeyGenerator 的实例的 generateKey() 方法获取盐,即 SecretKey 实例。
3. 用 SecretKey 实例的 getEncoded() 方法返回盐为 byte[] 数组,这个盐的值一定要保存好,验证数据的时候会用到。
4. 用 Mac.getInstance("HmacMD5") 获取一个 Mac 实例, 里面填充 Hash 算法类型。
5. 使用 Mac 实例的 init(SecretKey) 方法将盐的数值传入。
6. 调用 Mac 实例的 update(byte[]) 方法传入需要加密的数据。
7. 调用 Mac 实例的 doFinal() 方法返回加密过后的数据。
验证
我们需要将 SecretKey.getEncoded() 返回的 byte[] 数组的盐,和需要加密数据进行获取 Hash 值,只需要 new SecretKeySpec(byte[], String) 可以返回一个 SecretKey 实例 ,然后传入 Mac 实例的 init(SecretKey) 即可,剩下的步骤如上。
非对称加密
传输密钥交换信息
需求
因为密钥交换的时候无法确认接收人是否是本人,所以需要一种加密和解密分离的密钥,直接传递只有指定人才能解开的信息,防止接收人被伪造。
用途
非对称加密的加密密钥和解密密钥是分离的,信息经过加密密钥加密之后,只能由解密密钥解密。虽说非对称加密速度慢,但是可以只用来进心密钥交换阶段的通信,通常使用的是 RSA 算法进心非对称加密。
实现
1. 使用 KeyPairGenerator.getInstance("RSA") 获取 KeyPairGenerator 实例,然后调用实例方法 initialize(int keysize) 来初始化并确定密钥对的长度。
2. 使用 KeyPairGenerator 初始化过的实例的 generateKeyPair() 获取 KeyPair 实例。
3. 使用 KeyPair 实例的 getPrivate() 方法返回 PrivateKey 实例,getPublic() 方法返回 PublicKey 实例。两实例都可以调用 getEncoded() 返回对应密钥的字节数组。
4. Cipher.getInstance("RSA") 获取 Cipher 的 RSA 算法实例,然后 init(Cipher.ENCRYPT_MODE,PublicKey) 方法来初始化实例。其中第一个参数可以设置加密解密模式,第二个参数填入需要的 PublicKey 和 PrivateKey 实例。
5. 最后一步调用 Cipher 实例的 doFinal(byte[] Message) 来对 Message 进行 RSA 加密/解密。
恢复密钥
PublicKey
KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(byte[] PublicKeyData)) 返回一个 PublicKey 实例
PrivateKey
KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(byte[] PrivateKeyData)) 返回一个 PrivateKey 实例
对信息进行签名
用途
用私钥对信息的哈希值进行加密处理(签名),然后其他人用公钥解密得到哈希值进行验证明文信息。因为只有拥有私钥的人才能发出公钥解开的信息,所以可以确定信息来源的唯一性和完整性。
实现
获取密钥对
1. KeyPairGenerator,getInstance("RSA"); 返回 RSA 算法所需密钥对生成实例 KeyPairGenerator
2. 用返回的 KeyPairGenerator 实例的方法 initialize(int size); 确定密钥对长度。
3. 初始化确定长度和算法之后,用方法 generateKeyPair() 获取密钥对 KeyPair。
4. 获取 KeyPair 的 getPrivate() 和 getPublic() 方法获取 PrivateKey 和 PublicKey 实例。
私钥签名
1. 用 Signature.getInstance("SHA1withRSA") 确定使用 RSA 非对称加密 SHA1 计算的哈希值,并返回一个 Signature 实例。
2. 使用 Signature 实例方法 initSign(PrivateKey); 确定需要签名并且签名使用的私钥。
3. 使用 Signature 实例方法 update(byte[] message) 传入需要被签名的信息。
4. 调用 Signature 实例方法 sign() 对已经传入的信息进行签名(计算 SHA1 值并对 SHA1 值进行 RSA 私钥加密)然后返回 byte[] 类型的签名结果。
公钥验证
1. 用 Signature.getInstance("SHA1withRSA") 确定使用 RSA 非对称加密 SHA1 计算的哈希值,并返回一个 Signature 实例。
2. 使用 Signature 实例方法 initVerify(PublicKey); 确定需要验证签名且验证时候需要使用的公钥。
3. 使用 Signature 实例方法 update(byte[] message) 传入需要被验证签名的信息。
4. 调用 Signature 实例方法 boolean verify(byte[] Signed) 验证已经传入的信息的 SHA1 值和传入的公钥解密签名结果是否相同。
密钥交换
用途
在不安全信道上传输加密数据的密钥
实现
发送人
生成素数 p,底数 g,个人私钥 a,计算得出个人公钥 A=g^a mod p。然后将 p g A 传送给接收人。
利用接收人公钥 B 和个人私钥 a 计算出来加密数据密钥 c=B^a mod p。
接收人
同样也生成个人私钥 b,利用接收的 p 和 g 生成个人公钥 B=g^b mod p。然后将 B 传送给发送人。
利用发送人公钥 A 和个人私钥 b 计算出来加密数据密钥 c=A^b mod p。
c 计算结果相同
缺点
无法防御中间人攻击,即无法确定接收人没有被伪造
对称加密
固定长度密钥加密
算法
DES 56/64bit
AES 128/192/256bit
IDEA 128bit
AES 实现加密
1. 构造 128bit 的 Byte[] 密钥 和 byte[] 数据
2. Cipher.getInstance("AES/ECB/PKCS5Padding") 获取一个 Cipher 实例,参数为: 算法名称/工作模式/填充模式
3. new SecretKeySpec(byte[], String) 创建一个 SecretKey 实例,其中 byte[] 为自己构造的 128bit的密钥, String 为实现算法名称。
4. Cipher 实例的 init(Cipher.ENCRYPT_MODE , SecretKey) 方法初始化 Cipher 实例。其中第一个参数为设定加密模式,第二个参数为刚刚构造的 SecretKey 实例。
5. 调用 Cipher 实例的 doFinal(byte[]) 输入需要加密数据之后,返回加密结果。
AES 实现解密
步骤和加密相同,只是最后 doFinal(byte[]) 填充的是加密结果,返回的是明文。
非固定长度密钥加密
这个实现太麻烦了,所以直接密码 MD5 然后调用固定长度密钥加密好了
Loading...