加密类型

加密对于特殊数据来说是很重要的,我们也在不断开发新的加密手法来保护数据不被破解。这次我想介绍下目前常用的几种加密方式与其对应的特点。最后会基于hutool来完成对应的加密例子,必须引入hutool的依赖!!

1
2
3
4
5
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>

对称加密

对称加密是最早出现也是最简单的一种加密方式,加密和解密都是通过一个密钥去实现,具有加密解密速度快的特点,所以适合数据量大的加解密。但缺点也很明显,因为密钥是相同的,所以安全性比较低。

常用的加密方式有DES、3DES和AES 特点:加密解密快,安全性低

非对称加密

非对称加密则是弥补了对称加密的缺点,使用2个密钥对数据做处理,公钥用于加密,私钥用于解密。但非对称加密涉及到复杂的数学计算,所以加密解密的速度完全不及对称加密。

常用的加密方式有RSA、ECC、DSA、ECDSA 特点:加密解密慢,安全性高

散列加密

也叫哈希加密,是一种单向函数。通过将加密的字符串通过哈希算法映射到固定长度的字符串,映射完成的字符串即为密文。因为是单向函数,所以该加密是不可逆的。

常用的加密方式有MD5、SHA-256、SHA-1 特点:加密解密快,安全性则需要考虑哈希碰撞所带来的误差

对称加密

AES

对称加密中,我们基本都会使用AES来完成。3DES和DES基本已经被AES取代。对于AES加密,密钥的大小必须是128位、192位或256位。注意是位数,不是字节。1字节等于8位,所以这些位数等于16字节、24字节和32字节。 而在Java中我们一般使用UTF-8作为字符编码。所以需要保证密钥为16或者24或者32个字符。

AES的测试案例如下,我们先创建一个AES对象,设置密钥。使用encryptHex方法和decryptStr方法来完成加密解密。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void AESTest() {

// 创建AES对象 并传入密钥
AES aes = new AES("NAYUTASORA331202".getBytes());

String str = "Sora33";

// 加密
String encryptHex = aes.encryptHex(str);
logger.info("加密的字符串:[{}]", str);
logger.info("AES加密后的字符串:[{}]", encryptHex);

// 加密
String decryptStr = aes.decryptStr(encryptHex);
logger.info("AES解密后的字符串:[{}]", decryptStr);

}

加密的字符串:[Sora33]
AES加密后的字符串:[6c8299b16ad9f918c86dd3174852274b]
AES解密后的字符串:[Sora33]

非对称加密

RSA

rsa是最早被广泛使用的非对称加密算法之一。一般用于数据加密、数字签名和密钥交换等场景。不过RSA的算法性能较低,加密解密的速度较慢。下面是一个rsa的案例

1
2
3
4
5
6
7
// 先获取rsa的私钥和公钥
@Test
public void getKey() {
RSA rsa = SecureUtil.rsa();
logger.info("rsa的私钥:" + rsa.getPrivateKeyBase64());
logger.info("rsa的公钥:" + rsa.getPublicKeyBase64());
}

rsa的私钥:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK4u5HSXON2sq8kiAQ8AvvLZMfYCCy22g4kbTMqG25eodeYzkVSfua8vSjViqwQ6HnjmMPZAxVE+cOOeky1TQFSmM8imHc/+q5aPlQHGNLKyhCkApyGYWdD2s1BtX1hBcxKOQww00B2NqrVMu1ykbXE7YyFJ0/+Bz81q0pl7oexzAgMBAAECgYALcnN7IhEPqHBluIFfTgo+hX2eEEZRy8PbN9sVGEXIMr8E0PDFIfYfCDmVRpW8omEsStx+4oTVMQhUPTCo8uawTaM6t4bHlb88U7m4qEB4xX2316GlnxG2An6ib8l94yW0EcIjdPMxOMUBWAFPDhjIk0FUxt1K/GxQ5W2GMhLXyQJBAONQTdN855EG+UK81Fjskvi7Zkpo+3S0I9o/MEBilgbSU+m2UVzMRY3Y9Umjgz7wPTiGz9b3JJsymCmzaEUa5/cCQQDEKiFxPUhy8ZUZmxybhFVXU1m5L4MeCkzeXKbWY+c4kmhAcY3I0diYj9ORDVM4cc9/vuT2ZSfUpVUCcvaDFNhlAkAl2RkcPY/Q9fhKxGYW6E0QXSOLAC/eHqBZlmvSTJfuStbt8w1ZBioOlDFDMZaIxDdtUgUJJd1Sefob92NFHlXBAkEAsz9AMcZq5kVkFfLLsDu688HBEduddxy4YtPMy8icJvB5fLGGeoNt5PI/w6KmccRlc/iOJawHOmMdC9Da+qpYlQJAXGw42Lgs+/UEqBtqs5PyXuzatwB1Q4EBIVVLkOXqqggM2WywQgXjm2NPAJ0E7LZtG+BEvCjhJj7FT3cEJ4g7gQ==
rsa的公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuLuR0lzjdrKvJIgEPAL7y2TH2AgsttoOJG0zKhtuXqHXmM5FUn7mvL0o1YqsEOh545jD2QMVRPnDjnpMtU0BUpjPIph3P/quWj5UBxjSysoQpAKchmFnQ9rNQbV9YQXMSjkMMNNAdjaq1TLtcpG1xO2MhSdP/gc/NatKZe6HscwIDAQAB

我们通过刚刚的rsa对象,获取其公钥和私钥,将其持久化或保存到配置文件内。然后将公钥和私钥设置为创建rsa的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void RSATest() {

String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK4u5HSXON2sq8kiAQ8AvvLZMfYCCy22g4kbTMqG25eodeYzkVSfua8vSjViqwQ6HnjmMPZAxVE+cOOeky1TQFSmM8imHc/+q5aPlQHGNLKyhCkApyGYWdD2s1BtX1hBcxKOQww00B2NqrVMu1ykbXE7YyFJ0/+Bz81q0pl7oexzAgMBAAECgYALcnN7IhEPqHBluIFfTgo+hX2eEEZRy8PbN9sVGEXIMr8E0PDFIfYfCDmVRpW8omEsStx+4oTVMQhUPTCo8uawTaM6t4bHlb88U7m4qEB4xX2316GlnxG2An6ib8l94yW0EcIjdPMxOMUBWAFPDhjIk0FUxt1K/GxQ5W2GMhLXyQJBAONQTdN855EG+UK81Fjskvi7Zkpo+3S0I9o/MEBilgbSU+m2UVzMRY3Y9Umjgz7wPTiGz9b3JJsymCmzaEUa5/cCQQDEKiFxPUhy8ZUZmxybhFVXU1m5L4MeCkzeXKbWY+c4kmhAcY3I0diYj9ORDVM4cc9/vuT2ZSfUpVUCcvaDFNhlAkAl2RkcPY/Q9fhKxGYW6E0QXSOLAC/eHqBZlmvSTJfuStbt8w1ZBioOlDFDMZaIxDdtUgUJJd1Sefob92NFHlXBAkEAsz9AMcZq5kVkFfLLsDu688HBEduddxy4YtPMy8icJvB5fLGGeoNt5PI/w6KmccRlc/iOJawHOmMdC9Da+qpYlQJAXGw42Lgs+/UEqBtqs5PyXuzatwB1Q4EBIVVLkOXqqggM2WywQgXjm2NPAJ0E7LZtG+BEvCjhJj7FT3cEJ4g7gQ==";
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuLuR0lzjdrKvJIgEPAL7y2TH2AgsttoOJG0zKhtuXqHXmM5FUn7mvL0o1YqsEOh545jD2QMVRPnDjnpMtU0BUpjPIph3P/quWj5UBxjSysoQpAKchmFnQ9rNQbV9YQXMSjkMMNNAdjaq1TLtcpG1xO2MhSdP/gc/NatKZe6HscwIDAQAB";

// 创建RSA对象
RSA rsa = SecureUtil.rsa(privateKey,publicKey);

String str = "Sora33";

// 加密
byte[] encryptData = rsa.encrypt(str, KeyType.PublicKey);
String encryptStr = Base64.encode(encryptData);
logger.info("加密后的字符串:" + encryptStr);

// 解密
byte[] decryptData = rsa.decrypt(Base64.decode(encryptStr), KeyType.PrivateKey);
String decryptStr = new String(decryptData);
logger.info("解密后的字符串:" + decryptStr);
}

这里需要注意,因为rsa的特性,同一个字符串使用同一个公钥去加密,加密后的字符串并不是百分百相同的。但使用对应的私钥是可以完成解密的。

加密后的字符串:EccQydZwLArI0RHIgZfOaFRwh2fZ4eGTz0U/ZVf2wqjKJqsMRgjTDAOzr+P4ljOomuqhUEY4dj+MtruI9ogdDAcGl+Bi3ug18nVRaFh211n8XXt5L2+DkxtuKy2Q52zf/v0/W9lS1SsmdE4qzNTJmt4RpmLxKeAAZa8hdde5wiI=
解密后的字符串:Sora33

散列加密

md5

md5计算出来的哈希值是128位,也就是32个字符。由于md5的计算速度相对较快,所以用于一些快速计算哈希值的场景以及不是非常重要的数据加密。我们一般配合加盐来提高安全性。

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void md5Test() {
String str = "Sora33";
// 盐值
String slat = "TOOOONAYUTAAAAAA";

// 计算SHA256哈希值
String sha256Hex = DigestUtil.md5Hex(str + slat);

// 打印MD5哈希值
logger.info("MD5 Hash: " + sha256Hex);
}

MD5 Hash: 84d6195640683af6b415374db1bce9c0

SHA-256

SHA-256则是由美国安全局设计的一种加密函数,哈希长度为256,64个字符。在安全性上是要比md5要好的,但速度上不及md5。所以我们需要根据实际场景来选择对应的散列加密。

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void SHA256Test() {
String str = "Sora33";
// 盐值
String slat = "TOOOONAYUTAAAAAA";

// 计算SHA256哈希值
String sha256Hex = DigestUtil.sha256Hex(str + slat);

// 打印SHA256哈希值
logger.info("SHA256 Hash: " + sha256Hex);
}

SHA256 Hash: f44640401967122154ae012576f976bf500b377d6048d61e10eff6abbb06b8cc

总结

以上就是我们常用的一些加密方式,每种加密方式都有对应的优缺点。对于特别重要的数据,我们可以选择非对称加密的RSA或者ECC(性能上比RSA强),如果是一般且更注重加密的速度可以考虑AES或者md5加盐加密。