1、发展历史
1.1、古典密码学
凯撒密码、滚筒密码
1.2、近代密码学
德国 Enigma 机、被图灵破解
1.3、现代密码学
2、编码算法
不是加密和解密、而是为了在网络间更方便安全的传输数据/本地存储 而产生
2.1、base64
由 A ~ Z、a ~ z、0 ~ 9、+、/ 共 64个字符组成、去掉 i I o O + / 即 Base58
索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |
<!-- 用commons-codec 实现base64 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
/**
* 使用 JDK原生来实现Base64
*/
@Test
public void test1() throws UnsupportedEncodingException {
String str = "atCloud";
// 编码 1.8 才提供的
String encodeStr = Base64.getEncoder().encodeToString(str.getBytes(UTF8));
System.out.println("encode:" + encodeStr); // YXRDbG91ZA==
// 解码
byte[] decode = Base64.getDecoder().decode(encodeStr.getBytes(UTF8));
System.out.println("decode:" + new String(decode,UTF8));// atCloud
}
/**
* 使用 commons-codec 来实现base64
*/
@Test
public void test2() throws UnsupportedEncodingException {
String str = "atCloud";
// 编码
String encodeBase64String = org.apache.commons.codec.binary.Base64.encodeBase64String(str.getBytes(UTF8));
// YXRDbG91ZA==
System.out.println("encodeBase64String:" + encodeBase64String);
// 解码
byte[] decodeBase64 = org.apache.commons.codec.binary.Base64.decodeBase64(encodeBase64String.getBytes(UTF8));
// atCloud
System.out.println("decodeBase64:" + new String(decodeBase64,UTF8));
}
/**
* 测试 = 补充
*/
@Test
public void test3() throws UnsupportedEncodingException {
String str = "武";
// 编码
String encodeBase64String = org.apache.commons.codec.binary.Base64.encodeBase64String(str.getBytes("gbk"));
// zuQ=
System.out.println("encodeBase64String:" + encodeBase64String);
String str1 = "abc";
// 编码
String encodeBase64String1 = org.apache.commons.codec.binary.Base64.encodeBase64String(str1.getBytes("gbk"));
// YWJj
System.out.println("encodeBase64String:" + encodeBase64String1);
}
注意:base64 以三个字节为一组、如果最后一组不足三个字节、则用 = 补充
2.2、URL编码
application/x-www-from-urlencoded
public class UrlTest {
private static final String UTF8 = StandardCharsets.UTF_8.name();
/**
* URL实现 编码/解码
*/
@Test
public void test1() throws Exception{
String str = "AtCloud 武";
// 编码
String encode = URLEncoder.encode(str, UTF8);
System.out.println("encode:" + encode);
// 解码
String decode = URLDecoder.decode(encode, UTF8);
System.out.println("decode:" + decode);
}
}
2.3、十六进制和字节数组互转
/**
* 把16进制字符串(一定是偶数位、因为converBytes2HexStr已经处理过了、如果是单个位、会自动补零)转为字节数组
* @param hexStr
* @return
*/
public static byte[] convertHex2Bytes(String hexStr){
// 一个字节可以转为两个16进制字符
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < result.length; i++) {
// hexStr: abcd
// Integer.parseInt:把s转为10进制数、redix指定s是什么进制的数
// 获取每个字节的高四位,hexStr.substring(2,3) => c
int high4 = Integer.parseInt(hexStr.substring(i * 2,i * 2 + 1), 16);
// 获取每个字节的低四位,hexStr.substring(3,4) => d
int low4 = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2));
result[i] = (byte) (high4 * 16 + low4);
}
return result;
}
3、摘要算法
3.1、定义
又叫 Hash 算法、散列函数、数字摘要、消息摘要。它是一种单向算法、用户可以通过 hash 算法对目标信息生成一段特定长度的唯一 hash 值、但不能通过这个 hash 值重新获得目标信息
3.2、应用场景
- 密码、信息完整性校验、数字签名
3.3、常见算法
- MD5:Message-Digest Algorithm,结果占128位 ⇒ 16个byte
/**
* 使用Codec实现MD5
*/
@Test
public void test2() throws Exception{
String str = "AtCloud 武";
System.out.println(DigestUtils.md5Hex(str.getBytes(UTF8)));
}
/**
* 使用JDK原生API实现MD5
*/
@Test
public void test1() throws Exception{
String str = "AtCloud 武";
// 编码
String algorithm = "MD5";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String hexStr = MessageDigestUtils.doDigest(str,algorithm);
System.out.println("hexStr:" + hexStr);
}
public class HexUtils {
/**
* 把字节数组转为十六进制字符串、如果一个字节转为16进制字符后不足两位、则前面补0
* @param digest
* @return
*/
public static String converBytes2HexStr(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
// 获取 b 的补码的后八位
String hex = Integer.toHexString(((int)b) & 0xff);
// 15 --> Integer.toHexString(15 & 0xff) -->f-->0f
// 16 --> Integer.toHexString(16 & 0xff)
if (hex.length() == 1){
hex = "0" + hex;
}
sb.append(hex);
}
return sb.toString();
}
}
/**
* @author Cloud
*/
public class MessageDigestUtils {
private static final String UTF8 = StandardCharsets.UTF_8.name();
/**
* 执行消息摘要
* @param originalContent 原始字符串
* @param algorithm 算法名字、如MD5
* @return 摘要内容
*/
public static String doDigest(String originalContent,String algorithm){
try {
// 获取消息摘要算法对象
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 获取带原始内容的字节数组
byte[] bytes = originalContent.getBytes(UTF8);
// 获取到摘要结果
byte[] digest = messageDigest.digest(bytes);
// 当 bytes 比较大的时候、循环的进行update()
// messageDigest.update(bytes);
// messageDigest.digest();
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String hexStr = HexUtils.converBytes2HexStr(digest);
return hexStr;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- SHA:安全散列算法
- sha-256
- 其他如 sha-0、sha-1、sha-512
public class Sha256Test {
private static final String UTF8 = StandardCharsets.UTF_8.name();
/**
* 使用Codec实现Sha256
*/
@Test
public void test2() throws Exception{
String str = "AtCloud 武";
System.out.println(DigestUtils.sha256Hex(str.getBytes(UTF8)));
}
/**
* 使用JDK原生API实现Sha256
*/
@Test
public void test1() throws Exception{
String str = "AtCloud 武";
// 编码
String algorithm = "SHA-256";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String hexStr = MessageDigestUtils.doDigest(str,algorithm);
System.out.println("hexStr:" + hexStr);
}
}
public class Sha512Test {
private static final String UTF8 = StandardCharsets.UTF_8.name();
/**
* 使用Codec实现Sha512
*/
@Test
public void test2() throws Exception{
String str = "AtCloud 武";
System.out.println(DigestUtils.sha512Hex(str.getBytes(UTF8)));
}
/**
* 使用JDK原生API实现Sha512
*/
@Test
public void test1() throws Exception{
String str = "AtCloud 武";
// 编码
String algorithm = "SHA-512";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String hexStr = MessageDigestUtils.doDigest(str,algorithm);
System.out.println("hexStr:" + hexStr);
}
}
- MAC(Message Authentication Code):消息认证码、是一种带有密钥的 hash 函数
public class MacTest {
private static final String UTF8 = StandardCharsets.UTF_8.name();
/**
* 使用Codec实现Mac
*/
@Test
public void test2() throws Exception{
String str = "AtCloud 武";
// 指定密钥
String key = "123";
String hmacMD5Hex = new HmacUtils(HmacAlgorithms.HMAC_MD5, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
String HmacSHA256 = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
String HmacSHA512 = new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
}
/**
* 使用JDK原生API实现Mac
*/
@Test
public void test1() throws Exception{
String str = "AtCloud 武";
// 指定密钥、Mac摘要算法和digest算法(MD5、Sha) 不同的地方就是加了盐
String key = "123";
String algorithm = "HmacMD5";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String HmacMD5 = doMacDigest(str,key,algorithm);
// 返回32位加密数据
System.out.println("HmacMD5:" + HmacMD5);
String algorithm1 = "HmacSHA256";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String HmacSHA256 = doMacDigest(str,key,algorithm1);
// 返回64位加密数据
System.out.println("HmacSHA256:" + HmacSHA256);
String algorithm2 = "HmacSHA512";
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String HmacSHA512 = doMacDigest(str,key,algorithm2);
// 返回128位加密数据
System.out.println("HmacSHA512:" + HmacSHA512);
}
/**
* 获取Mac消息摘要
* @param originalContent 原始内容
* @Param key Mac算法的key
* @param algorithm 算法名字、如HmacMD5
* @return
*/
public static String doMacDigest(String originalContent,String key,String algorithm){
try {
// 获取消息摘要算法对象
Mac mac = Mac.getInstance(algorithm);
// 获取key对象并初始化mac
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(UTF8), algorithm);
mac.init(secretKeySpec);
// 获取带原始内容的字节数组
byte[] bytes = originalContent.getBytes(UTF8);
// 获取到摘要结果
byte[] macBytes = mac.doFinal(bytes);
// 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
String hexStr = HexUtils.converBytes2HexStr(macBytes);
return hexStr;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 其他如 MD2、MD4、HAVAL 就暂时不一 一解答了