常用加密算法及Java实现

1、概述

加密在平时开发中也会经常用到,涉及登录、支付、接口设计等方面,可能都需要考虑到加密算法,加密算法分对称加密和非对称加密,对称加密使用的密钥只有一个,发送和接收双方都使用这个密钥对数据进行加密和解密,非对称加密算法,需要两个密钥,一个是公钥 (public key),另一个是私钥 (private key),如果使用公钥对数据 进行加密,只有用对应的私钥才能进行解密。如果使用私钥对数据 进行加密,只有用对应的公钥才能进行解密。

常用加密算法

2、MD5

MD5一般用于对一段信息产生信息摘要即生成数字签名,以 防止被篡改。无论是多长的输入,
MD5都会输出长度为128bits的一个串 (通常用16进制 表示为32个字符)。

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Md5Utils {

private static final String UTF8 = "utf-8";

/**
* 加密
*
* @param plainText 待加密字符串
* @return
*/
public final static String encoder(String plainText)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] bytes = plainText.getBytes(UTF8);
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(bytes);
byte[] md = mdInst.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < md.length; i++) {
int val = ((int) md[i]) & 0xff;
if (val < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString();
}

}

3、SHA1

SHA1 是和 MD5 一样流行的 消息摘要算法,然而 SHA1 比 MD5 的 安全性更强。对于长度小于 2 ^ 64 位的消息,SHA1 会产生一个 160 位的 消息摘要。基于 MD5、SHA1 的信息摘要一般而言不可逆 ,可以被应用在检查 文件完整性 以及 数字签名 等场景。

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.security.MessageDigest;

public final class Sha1Utils {
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

/**
* Takes the raw bytes from the digest and formats them correct.
* @param bytes the raw bytes from the digest.
* @return the formatted bytes.
*/
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}

public static String encode(String str) {
if (str == null) {
return null;
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(str.getBytes());
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

}

4、RSA

RSA 加密算法是目前比较优秀的公钥方案。RSA是第一个能同时用于加密和数字签名的算法,它能够抵抗到目前为止已知的 所有密码攻击,已被 ISO推荐为公钥数据加密标准。RSA 加密算法 基于一个十分简单的数论事实:将两个大 素数 相乘十分容易,但想要对其乘积进行 因式分解 却极其困难,因此可以将 乘积 公开作为 加密密钥。

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaUtils {

private static final String UTF8 = "UTF-8";

/**
* 随机生成密钥对
*
* @throws NoSuchAlgorithmException
*/
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 得到公钥字符串
String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
return new RsaKeyPair(publicKeyString, privateKeyString);
}

/**
* RSA公钥加密
*
* @param plainText 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception
*/
public static String encrypt(String plainText, String publicKey) throws Exception {
//base64编码的公钥
byte[] decoded = Base64.getDecoder().decode(publicKey.getBytes(UTF8));
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encodeBytes = Base64.getEncoder().encode(cipher.doFinal(plainText.getBytes(UTF8)));
return new String(encodeBytes, UTF8);
}

/**
* RSA私钥解密
*
* @param encryptText 加密字符串
* @param privateKey 私钥
* @return 明文
* @throws Exception
*/
public static String decrypt(String encryptText, String privateKey) throws Exception {
//64位解码加密后的字符串
byte[] inputByte = Base64.getDecoder().decode(encryptText.getBytes(UTF8));
//base64编码的私钥
byte[] decoded = Base64.getDecoder().decode(privateKey.getBytes(UTF8));
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}

private static class RsaKeyPair {
private String publicKey;
private String privateKey;

public RsaKeyPair() {
}

public RsaKeyPair(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}

public String getPublicKey() {
return publicKey;
}

public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}

public String getPrivateKey() {
return privateKey;
}

public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
}

public static void main(String[] args) throws Exception {
// 生成公钥和私钥
RsaKeyPair rsaKeyPair = generateKeyPair();
// 加密字符串
String message = "river106";
System.out.println("随机生成的公钥为:" + rsaKeyPair.getPublicKey());
System.out.println("随机生成的私钥为:" + rsaKeyPair.getPrivateKey());
System.out.println("原始内容: "+message);
String encryptText = encrypt(message, rsaKeyPair.getPublicKey());
System.out.println("加密后的字符串为:" + encryptText);
String messageDe = decrypt(encryptText, rsaKeyPair.getPrivateKey());
System.out.println("解密后的字符串为:" + messageDe);
}

}

5、DES

DES是 对称块加密算法加解密的过程是可逆的
DES 加密算法是一种 分组密码,以64位为分组对数据加密,它的密钥长度是56位,加密解密用同一算法。
DES 加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由DES加密算法加密的密文数据。因此,破译DES加密算法实际上就是搜索密钥的编码。对于56位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为2^56次。

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;


public class DesUtils {

private static final String UTF8 = "UTF-8";
private static byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};

/**
* DES加密
* @param plainText 待加密内容
* @param encryptKey 加密key
* @return
* @throws Exception
*/
public static String encrypt(String plainText, String encryptKey) throws Exception {
IvParameterSpec zeroIv = new IvParameterSpec(iv);
SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(), "DES");
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
byte[] encryptedData = cipher.doFinal(plainText.getBytes(UTF8));
return new String(Base64.getEncoder().encode(encryptedData), UTF8);
}

/**
* DES解密
* @param encryptedText 已加密内容
* @param decryptKey 解密key
* @return
* @throws Exception
*/
public static String decrypt(String encryptedText, String decryptKey) throws Exception {
IvParameterSpec zeroIv = new IvParameterSpec(iv);
SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(UTF8), "DES");
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
byte decryptedData[] = cipher.doFinal(Base64.getDecoder().decode(encryptedText.getBytes(UTF8)));
return new String(decryptedData, UTF8);
}

}

6、AES

AES是 对称块加密算法加解密 的过程是 可逆的
AES 加密算法是密码学中的高级加密标准,该加密算法采用 对称分组密码体制,密钥长度的最少支持为128位、192位、256位,分组长度128位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准。
AES 本身就是为了取代 DES 的,AES 具有更好的 安全性、效率和灵活性。

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

public class AesUtils {

/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return
*/
public static String encrypt(String content, String password) throws Exception {
StringBuilder sb = new StringBuilder();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
// 创建密码器
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
// 初始化
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(byteContent);
//将10进制字节数组转化为16进制字符串
for (int i = 0; i < result.length; i++) {
String hex = Integer.toHexString(result[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}

/**
* 解密
*
* @param content 待解密内容
* @param password 解密密钥
* @return
*/
public static String decrypt(String content, String password) throws Exception {
//将16进制字符创转为10进制字节数组
byte[] result = new byte[content.length() / 2];
for (int i = 0; i < content.length() / 2; i++) {
int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
// 创建密码器
Cipher cipher = Cipher.getInstance("AES");
// 初始化
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] data = cipher.doFinal(result);
return new String(data);
}

}

常用加密算法及Java实现
https://river106.cn/posts/25814cf3.html
作者
river106
发布于
2021年12月12日
许可协议