Fork me on GitHub

Java加密算法

前言

最近总结了一些加密算法的相关Java代码,特此整理如下,以备不时之需。

正文

MD5信息摘要算法

此算法为不可逆加密算法,是一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值,用于确保信息传输完整一致。

后来该算法被证实存在弱点,无法防止碰撞破解,因此不适用于安全性认证,对于需要高度安全性的数据,可以采用其他加密算法。

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
@Slf4j
public class MD5Utils {

/**
* 加密算法
*/
private static final String KEY_ALGORITHM = "MD5";

/**
* 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
*/
private static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

private static MessageDigest messagedigest = null;

static {
try {
messagedigest = MessageDigest.getInstance(KEY_ALGORITHM);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
}

/**
* 生成字符串的md5校验值
*
* @param s
* @return
*/
public static String getMD5String(String s) {
return getMD5String(s.getBytes());
}

public static String getMD5String(byte[] bytes) {
messagedigest.update(bytes);
return bufferToHex(messagedigest.digest());
}

private static String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}

private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}

private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
char c0 = hexDigits[(bt & 0xf0) >> 4];
// 取字节中低 4 位的数字转换
char c1 = hexDigits[bt & 0xf];
stringbuffer.append(c0);
stringbuffer.append(c1);
}

/**
* 生成字符串指定部分的md5校验值
* @param s
* @param start
* @param end
* @return
*/
public static String getMD5String(String s,int start,int end) {
if(StringUtils.isEmpty(s)){
return "";
}
s = s.toUpperCase();
if(end > start && end > 0 && s.length() >= end){
s = s.substring(start, end);
}
return getMD5String(s.getBytes()).toUpperCase();
}

public static void main(String[] args) {
System.out.println(getMD5String("123456"));
}
}

SHA安全散列算法

我们这儿提到的SHA安全散列算法一般指的它的密码散列函数家族,其有5个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384和SHA-512。

其加密强度依次上升,SHA加密算法也是一种不可逆加密算法。

由于目前SHA-1存在暴力破解(碰撞破解)的可能性,因此推荐使用SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)进行数据加密。这4个算法函数都将讯息对应到更长的讯息摘要。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
@Slf4j
public class SHAUtils {

/**
* 加密算法
*/
private static final String KEY_SHA_1 = "SHA1";

private static final String KEY_SHA_224 = "SHA-224";

private static final String KEY_SHA_256 = "SHA-256";

private static final String KEY_SHA_384 = "SHA-384";

private static final String KEY_SHA_512 = "SHA-512";

/**
* 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
*/
private static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

private static MessageDigest messagedigestSHA1 = null;
private static MessageDigest messagedigestSHA224 = null;
private static MessageDigest messagedigestSHA256 = null;
private static MessageDigest messagedigestSHA384 = null;
private static MessageDigest messagedigestSHA512 = null;

static {
try {
messagedigestSHA1 = MessageDigest.getInstance(KEY_SHA_1);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
try {
messagedigestSHA224 = MessageDigest.getInstance(KEY_SHA_224);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
try {
messagedigestSHA256 = MessageDigest.getInstance(KEY_SHA_256);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
try {
messagedigestSHA384 = MessageDigest.getInstance(KEY_SHA_384);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
try {
messagedigestSHA512 = MessageDigest.getInstance(KEY_SHA_512);
} catch (NoSuchAlgorithmException ex) {
log.error(ex.getMessage(),ex);
}
}

private static String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}

private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}

private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
char c0 = hexDigits[(bt & 0xf0) >> 4];
// 取字节中低 4 位的数字转换
char c1 = hexDigits[bt & 0xf];
stringbuffer.append(c0);
stringbuffer.append(c1);
}

/**
* 生成字符串的sha1校验值
*
* @param s
* @return
*/
public static String getSHA1String(String s) {
return getSHA1String(s.getBytes());
}
public static String getSHA1String(byte[] bytes) {
messagedigestSHA1.update(bytes);
return bufferToHex(messagedigestSHA1.digest());
}

/**
* 生成字符串的sha224校验值
*
* @param s
* @return
*/
public static String getSHA224String(String s) {
return getSHA224String(s.getBytes());
}
public static String getSHA224String(byte[] bytes) {
messagedigestSHA224.update(bytes);
return bufferToHex(messagedigestSHA224.digest());
}

/**
* 生成字符串的sha256校验值
*
* @param s
* @return
*/
public static String getSHA256String(String s) {
return getSHA256String(s.getBytes());
}
public static String getSHA256String(byte[] bytes) {
messagedigestSHA256.update(bytes);
return bufferToHex(messagedigestSHA256.digest());
}

/**
* 生成字符串的sha384校验值
*
* @param s
* @return
*/
public static String getSHA384String(String s) {
return getSHA384String(s.getBytes());
}
public static String getSHA384String(byte[] bytes) {
messagedigestSHA384.update(bytes);
return bufferToHex(messagedigestSHA384.digest());
}

/**
* 生成字符串的sha512校验值
*
* @param s
* @return
*/
public static String getSHA512String(String s) {
return getSHA512String(s.getBytes());
}
public static String getSHA512String(byte[] bytes) {
messagedigestSHA512.update(bytes);
return bufferToHex(messagedigestSHA512.digest());
}


public static void main(String[] args) {
System.out.println("SHA1:"+getSHA1String("123456"));
System.out.println("SHA224:"+getSHA224String("123456"));
System.out.println("SHA256:"+getSHA256String("123456"));
System.out.println("SHA384:"+getSHA384String("123456"));
System.out.println("SHA512:"+getSHA512String("123456"));
}
}

Hmac哈希消息认证码

Hmac是一种基于Hash函数和密钥进行消息认证的方法,在IPSec和其他网络协议(如SSL)中有广泛应用,现在已经成为Internet安全标准。

它也是一种不可逆加密算法。

Hmac运算利用hash算法,以一个消息M和一个密钥K作为输入,生成一个定长的消息摘要作为输出。

由于存在加密密钥K,因此认证时,加密方和认证方都是需要知道密钥K的。因此需要保证密钥K不被泄露。

同时密钥K的长度也影响加密算法强度,推荐密钥K随机生成且长度大于n(hash输出值)。

Hmac根据hash运算的不同,有6种算法,分别是Hmac-SHA1、Hmac-SHA224、Hmac-SHA256、Hmac-SHA284、Hmac-SHA512和Hmac-MD5。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
public class HmacUtils {

/**
* 加密算法
*/
private static final String KEY_HMAC_SHA1 = "HmacSHA1";

private static final String KEY_HMAC_SHA224 = "HmacSHA224";

private static final String KEY_HMAC_SHA256 = "HmacSHA256";

private static final String KEY_HMAC_SHA384 = "HmacSHA384";

private static final String KEY_HMAC_SHA512 = "HmacSHA512";

private static final String KEY_HMAC_MD5 = "HmacMD5";

/**
* 得到指定算法的一个密钥
* @param algorithm
* @return
* @throws Exception
*/
public static String initMacKey(String algorithm) throws Exception {
//得到一个 指定算法密钥的密钥生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
//生成一个密钥
SecretKey secretKey = keyGenerator.generateKey();
byte[] bytes = secretKey.getEncoded();
return Base64.encodeBase64String(bytes);
}

/**
* HmacSHA 加密算法
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
private static String hmacSHAEncrypt(String encryptText, String encryptKey,String algorithm) throws Exception {
byte[] data = encryptKey.getBytes(StandardCharsets.UTF_8);
SecretKey secretKey = new SecretKeySpec(data, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secretKey);
byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);
byte[] bytes = mac.doFinal(text);
return Base64.encodeBase64String(bytes);
}

/**
* HmacSHA1
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_SHA1);
}

/**
* HmacSHA224
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacSHA224Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_SHA224);
}

/**
* HmacSHA256
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacSHA256Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_SHA256);
}

/**
* HmacSHA384
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacSHA384Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_SHA384);
}

/**
* HmacSHA512
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacSHA512Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_SHA512);
}

/**
* HmacMD5
* @param encryptText
* @param encryptKey
* @return
* @throws Exception
*/
public static String hmacMD5Encrypt(String encryptText, String encryptKey) throws Exception{
return hmacSHAEncrypt(encryptText,encryptKey,KEY_HMAC_MD5);
}

public static void main(String[] args) throws Exception{
String sha1Key = initMacKey(KEY_HMAC_SHA1);
System.out.println("HmacSHA1_Key:"+sha1Key);
System.out.println("HmacSHA1_Result:"+hmacSHA1Encrypt("123456",sha1Key));

String sha224Key = initMacKey(KEY_HMAC_SHA224);
System.out.println("HmacSHA224_Key:"+sha224Key);
System.out.println("HmacSHA224_Result:"+hmacSHA224Encrypt("123456",sha224Key));

String sha256Key = initMacKey(KEY_HMAC_SHA256);
System.out.println("HmacSHA256_Key:"+sha256Key);
System.out.println("HmacSHA256_Result:"+hmacSHA256Encrypt("123456",sha256Key));

String sha384Key = initMacKey(KEY_HMAC_SHA384);
System.out.println("HmacSHA384_Key:"+sha384Key);
System.out.println("HmacSHA384_Result:"+hmacSHA384Encrypt("123456",sha384Key));

String sha512Key = initMacKey(KEY_HMAC_SHA512);
System.out.println("HmacSHA512_Key:"+sha512Key);
System.out.println("HmacSHA512_Result:"+hmacSHA512Encrypt("123456",sha512Key));

String md5Key = initMacKey(KEY_HMAC_MD5);
System.out.println("HmacMD5_Key:"+md5Key);
System.out.println("HmacMD5_Result:"+hmacMD5Encrypt("123456",md5Key));
}
}

DES加密算法

DES全称为Data Encryption Standard,直译即数据加密标准,是一种使用密钥加密的块算法。

它是一种对称可逆加密算法。

DES的加密密钥也是需要加密方和解密方都知道,因此存在泄漏的可能性。需要保护好密钥。

同时DES被证明是可以破解的,明文+密钥=密文,这个公式只要知道任何两个,就可以推导出第三个。

在已经知道明文和对应密文的情况下,通过穷举和暴力破解是可以破解DES的。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
public class DESUtils {

/**
* 加密算法
*/
private static final String KEY_ALGORITHM = "DESede";

/**
* 默认的加密算法
*/
private static final String CIPHER_ALGORITHM = "DESede/CBC/PKCS5Padding";

/**
* 加密数据
*
* @param data
* @param key
* @param iv
* @return
* @throws Exception
*/
public static String encrypt(String data, String key,String iv) throws Exception {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
if(keyBytes.length < 24){
throw new Exception("Key字节长度需大于等于24");
}
if(ivBytes.length != 8){
throw new Exception("IV偏移量需要为8字节");
}

byte[] bt = encrypt(data.getBytes(StandardCharsets.UTF_8), keyBytes,ivBytes);
return Base64.encodeBase64String(bt);
}

/**
* 解密数据
*
* @param data
* @param key
* @param iv
* @return
* @throws Exception
*/
public static String decrypt(String data, String key,String iv) throws Exception {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
if(keyBytes.length < 24){
throw new Exception("Key字节长度需大于等于24");
}
if(ivBytes.length != 8){
throw new Exception("IV偏移量需要为8字节");
}

if (data == null) {
return null;
}
byte[] buf = Base64.decodeBase64(data);
byte[] bt = decrypt(buf, keyBytes,ivBytes);
return new String(bt, StandardCharsets.UTF_8);
}

/**
* DES加密数据
*
* @param data
* @param key
* @param iv
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] data, byte[] key,byte[] iv) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();

// 从原始密钥数据创建DESKeySpec对象
DESedeKeySpec dks = new DESedeKeySpec(key);

// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(dks);

// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

IvParameterSpec ips = new IvParameterSpec(iv);

// 用密钥初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, secretKey,ips, sr);

return cipher.doFinal(data);
}

/**
* DES解密数据
*
* @param data
* @param key
* @param iv
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] data, byte[] key,byte[] iv) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();

// 从原始密钥数据创建DESKeySpec对象
DESedeKeySpec dks = new DESedeKeySpec(key);

// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(dks);

IvParameterSpec ips = new IvParameterSpec(iv);

// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

// 用密钥初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, secretKey,ips, sr);

return cipher.doFinal(data);
}

public static void main(String[] args) throws Exception{
String text = "12345611111111111111111111111";
String key = "111111111111111111111张";
String iv = "张三81";
String result = encrypt(text,key,iv);
System.out.println("DES加密:"+ result);
System.out.println("DES解密:"+decrypt(result,key,iv));
}
}

AES加密算法

AES(Advanced Encryption Standard),高级加密标准,这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。

它是一种对称可逆加密算法。

AES的加密密钥也是需要加密方和解密方都知道,因此也需要保护好密钥。

在使用AES加密时,我们一般使用CBC加密模式,这种加密模式安全性好,适合传输长报文,缺点是需要初始化向量IV。

对称加密的加密模式一般有4种,优缺点如下:

对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。对于流加密,需要将分组密码转化为流模式工作。对于块加密(或称分组加密),如果要加密超过块大小的数据,就需要涉及填充和链加密模式。

  • ECB(Electronic Code Book电子密码本)模式

    ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

    优点:

    1. 简单; 
    2. 有利于并行计算;
    3. 误差不会被传送;

    缺点: 

    1. 不能隐藏明文的模式; 
    2. 可能对明文进行主动攻击; 

    因此,此模式适于加密小消息。

  • CBC(Cipher Block Chaining,加密块链)模式

    优点:

    1. 不容易主动攻击;
    2. 安全性好于ECB;
    3. 适合传输长度长的报文,是SSL、IPSec的标准。 

    缺点: 

    1. 不利于并行计算; 
    2. 误差传递; 
    3. 需要初始化向量IV
  • CFB(Cipher FeedBack Mode,加密反馈)模式

    优点:

    1. 隐藏了明文模式; 
    2. 分组密码转化为流模式; 
    3. 可以及时加密传送小于分组的数据; 

    缺点: 

    1. 不利于并行计算; 
    2. 误差传送:一个明文单元损坏影响多个单元; 
    3. 唯一的IV;
  • OFB(Output FeedBack,输出反馈)模式

    优点:

    1. 隐藏了明文模式; 
    2. 分组密码转化为流模式; 
    3. 可以及时加密传送小于分组的数据; 

    缺点: 

    1. 不利于并行计算; 
    2. 对明文的主动攻击是可能的; 
    3. 误差传送:一个明文单元损坏影响多个单元

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
@Slf4j
public class AESUtils {

/**
* 加密算法
*/
private static final String KEY_ALGORITHM = "AES";

/**
* 默认的加密算法
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

/**
* 随机数算法
*/
private static final String RANDOM_ALGORITHM = "SHA1PRNG";

/**
* IV向量长度必须为16
*/
private static final int IV_PARAM_LENGTH = 16;

/**
* AES支持的密钥长度
*/
private static final int SECRET_KEY_LENGTH_128 = 128;
private static final int SECRET_KEY_LENGTH_192 = 192;
private static final int SECRET_KEY_LENGTH_256 = 256;

/**
* 密钥种子
*/
private String secretKeySeed = null;

/**
* IV向量
*/
private String ivParameterSeed = null;

public AESUtils(String secretKeySeed, String ivParameterSeed) {
this.secretKeySeed = secretKeySeed;
if (ivParameterSeed.length() != IV_PARAM_LENGTH) {
throw new RuntimeException("iv向量长度必须为16");
}
this.ivParameterSeed=ivParameterSeed;
}

/**
* 加密
* @param content
* @return
* @throws Exception
*/
public String encrypt(String content) throws Exception {
// AES加密
byte[] encryptStr = encrypt(content, secretKeySeed,ivParameterSeed);
// BASE64位加密
return Base64.encodeBase64String(encryptStr);
}

/**
* 解密
* @param encryptStr
* @return
* @throws Exception
*/
public String decrypt(String encryptStr) throws Exception {
// BASE64位解密
byte[] decodeBase64 = Base64.decodeBase64(encryptStr);
// AES解密
return new String(decrypt(decodeBase64, secretKeySeed,ivParameterSeed),StandardCharsets.UTF_8);
}

/**
* 生成加密秘钥
* @param secretKeySeed
* @return
*/
private static SecretKeySpec getSecretKeySpec(final String secretKeySeed) {
try {
//生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
// 防止linux下 随机生成key
SecureRandom secureRandom = SecureRandom.getInstance(RANDOM_ALGORITHM);
secureRandom.setSeed(secretKeySeed.getBytes());
//AES 要求密钥长度为 128/192/256
keyGenerator.init(SECRET_KEY_LENGTH_128, secureRandom);
//生成一个密钥
SecretKey secretKey = keyGenerator.generateKey();
// 转换为AES专用密钥
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
// //注意:ios不支持使用 KeyGenerator、SecureRandom、SecretKey 生成
// return new SecretKeySpec(secretKeySeed.getBytes(), KEY_ALGORITHM);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
return null;
}

/**
* 生成向量秘钥
* @param ivParameterSeed
* @return
*/
private static IvParameterSpec getIvParameterSpec(final String ivParameterSeed) {
//使用CBC模式,需要一个向量iv,可增加加密算法的强度
return new IvParameterSpec(ivParameterSeed.getBytes());
}

/**
* 加密
* @param content
* @param secretKeySeed
* @param ivParameterSeed
* @return
* @throws Exception
*/
private static byte[] encrypt(String content, String secretKeySeed,String ivParameterSeed) throws Exception {
// 创建密码器
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// 初始化为加密模式的密码器
cipher.init(Cipher.ENCRYPT_MODE, getSecretKeySpec(secretKeySeed),getIvParameterSpec(ivParameterSeed));
// 加密
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}

/**
* 解密
* @param content
* @param secretKeySeed
* @param ivParameterSeed
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] content, String secretKeySeed,String ivParameterSeed) throws Exception {
// 创建密码器
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// 初始化为加密模式的密码器
cipher.init(Cipher.DECRYPT_MODE, getSecretKeySpec(secretKeySeed),getIvParameterSpec(ivParameterSeed));
// 解密
return cipher.doFinal(content);
}


public static void main(String[] args) throws Exception {
String secretKeySeed = "test123456";
String ivParameterSeed = "ivPar-test-hello";
String message = "test1234567890";
AESUtils aesUtils = new AESUtils(secretKeySeed,ivParameterSeed);
String a= aesUtils.encrypt(message);
System.out.println("加密后的字符:" + a);
System.out.println("解密后的字符:" + aesUtils.decrypt(a));
}
}

RSA加密算法

它是一种非对称可逆加密算法,其密钥由公钥和私钥组成,公钥外部暴露,用于数据加密,私钥保密,用于解密数据。

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

RSA的安全性依赖于大数分解,但是否等同于大数分解一直未能得到理论上的证明,也并没有从理论上证明破译。RSA的难度与大数分解难度等价。

RSA算法的保密强度随其密钥的长度增加而增强。但是,密钥越长,其加解密所耗用的时间也越长。因此,要根据所保护信息的敏感程度与攻击者破解所要花费的代价值不值得以及系统所要求的反应时间来综合考虑。一般情况下,公钥长度最好选择1024位及以上。

由于进行的都是大数计算,使得RSA最快的情况也比DES慢上好几倍,无论是软件还是硬件实现。速度一直是RSA的缺陷。一般来说只用于少量数据加密。RSA的速度比对应同样安全级别的对称密码算法要慢1000倍左右。

由于RSA加密数据长度不超过 密钥长度/8 - 11,解密长度不超过 密钥长度/8,因此对于较长数据,一般有两种方法进行处理:一是在使用RSA加密前,先使用一些对称加密算法将数据加密,使得加密后长度在RSA允许范围内,在使用RSA加密;二是使用RSA分段加密。

下面代码提供了RSA分段加密的算法,一般情况下,由于RSA加解密速度慢,耗资源,我们在双方通信中,先使用RSA进行通信,成功后协定双方对称加密密钥(如AES密钥),而后在使用对称加密算法(如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
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
@Slf4j
public class RSAUtils {

/**
* 数字签名,密钥算法
*/
private static final String RSA_KEY_ALGORITHM = "RSA";

/**
* 数字签名签名/验证算法
*/
private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

/**
* RSA密钥长度,RSA算法的默认密钥长度是1024密钥长度必须是64的倍数,在512到65536位之间
* PS:值改变后 最大加密字节数、最大解密字节数会随之变化
*/
private static final int KEY_SIZE = 2048;

/**
* bits转换为byte单位
*/
private static final int BASE_SIZE = 8;

/**
* 最大加密字节数,超出最大字节数需要分组加密
*/
private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / BASE_SIZE - 11;

/**
* 最大解密字节数,超出最大字节数需要分组解密
*/
private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / BASE_SIZE;

/**
* 生成密钥对
* @return
* @throws Exception
*/
private static Map<String, String> initKey() throws Exception {
KeyPairGenerator keygen = KeyPairGenerator.getInstance(RSA_KEY_ALGORITHM);
//初始化密钥生成器
keygen.initialize(KEY_SIZE);
KeyPair keys = keygen.genKeyPair();

byte[] pubKey = keys.getPublic().getEncoded();
String publicKeyString = Base64.encodeBase64String(pubKey);

byte[] priKey = keys.getPrivate().getEncoded();
String privateKeyString = Base64.encodeBase64String(priKey);

Map<String, String> keyPairMap = new HashMap<>();
keyPairMap.put("publicKeyString", publicKeyString);
keyPairMap.put("privateKeyString", privateKeyString);

return keyPairMap;
}

/**
* 密钥转成byte[]
*
* @param key
* @return
*/
public static byte[] decodeBase64(String key) {
return Base64.decodeBase64(key);
}

/**
* 获取公钥
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
return keyFactory.generatePublic(keySpec);
}

/**
* 获取私钥
*
* @param privateKey 私钥字符串
* @return
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
return keyFactory.generatePrivate(keySpec);
}

/**
* 公钥加密
*
* @param data 加密前的字符串
* @param publicKey 公钥
* @return 加密后的字符串
* @throws Exception
*/
public static String encryptByPubKey(String data, String publicKey) throws Exception {
byte[] pubKey = RSAUtils.decodeBase64(publicKey);
byte[] enSign = encryptByPubKey(data.getBytes(), pubKey);
return Base64.encodeBase64String(enSign);
}

/**
* 公钥加密
*
* @param data 待加密数据
* @param pubKey 公钥
* @return
* @throws Exception
*/
public static byte[] encryptByPubKey(byte[] data, byte[] pubKey) throws Exception {
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
PublicKey publicKey1 = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey1);

// 标识
int offSet = 0;
byte[] resultBytes = {};
byte[] cache = {};
int inputLength = data.length;
while (inputLength - offSet > 0) {
if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
offSet += MAX_ENCRYPT_BLOCK;
} else {
cache = cipher.doFinal(data, offSet, inputLength - offSet);
offSet = inputLength;
}
resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
}
return resultBytes;
}

/**
* 私钥解密
*
* @param data 待解密的数据
* @param priKey 私钥
* @return
* @throws Exception
*/
public static byte[] decryptByPriKey(byte[] data, byte[] priKey) throws Exception {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
PrivateKey privateKey1 = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey1);

int inputLen = data.length;

int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
byte[] decryptedData = new byte[0];

try(ByteArrayOutputStream out = new ByteArrayOutputStream()){
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
decryptedData = out.toByteArray();
}catch (Exception e){
log.error(e.getMessage(),e);
throw e;
}

return decryptedData;
}

/**
* 私钥解密
*
* @param data 解密前的字符串
* @param privateKey 私钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decryptByPriKey(String data, String privateKey) throws Exception {
byte[] priKey = RSAUtils.decodeBase64(privateKey);
byte[] design = decryptByPriKey(Base64.decodeBase64(data), priKey);
return new String(design);
}

/**
* 签名
*
* @param signVo 待签名数据
* @param privateKey 私钥
* @return 签名
*/
public static String sign(SignVo signVo, String privateKey) throws Exception {
PrivateKey privateKeys = getPrivateKey(privateKey);
String data = toSignStrMap(signVo);
byte[] keyBytes = privateKeys.getEncoded();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
PrivateKey key = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(key);
signature.update(data.getBytes());
return new String(Base64.encodeBase64(signature.sign()));
}


/**
* 验签
*
* @param signVo 签名实体
* @param publicKey 公钥
* @param sign 签名
* @return 是否验签通过
*/
public static boolean verify(SignVo signVo, String publicKey, String sign) throws Exception {
PublicKey publicKeys = getPublicKey(publicKey);
String srcData = toSignStrMap(signVo);
byte[] keyBytes = publicKeys.getEncoded();
// 初始化公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
// 产生公钥
PublicKey key = keyFactory.generatePublic(keySpec);
// 实例化Signature
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
// 初始化Signature
signature.initVerify(key);
signature.update(srcData.getBytes());
return signature.verify(Base64.decodeBase64(sign.getBytes()));
}

/**
* 签名串拼接 格式:标志A&标志B&标志C..... 中间用 & 连接
* @param signVo
* @return
*/
public static String toSignStrMap(SignVo signVo) {
StringBuilder sb = new StringBuilder();
sb.append(signVo.getSignA()).append("&").append(signVo.getSignB()).append("&").append(signVo.getSignC());
return sb.toString();
}

public static void main(String[] args) {
try {
Map<String, String> keyMap = initKey();
String publicKeyString = keyMap.get("publicKeyString");
String privateKeyString = keyMap.get("privateKeyString");
System.out.println("公钥:" + publicKeyString);
System.out.println("私钥:" + privateKeyString);

// 待加密数据
String data = "{\"code\":\"0000\",\"data\":{\"list\":[{\"address\":\"互联网创业中心\",\"amount\":120000.0,\"applicationDate\":1594174666000,\"createDate\":1594174666000,\"ecCode\":\"MC0001\",\"ecName\":\"ARJ\",\"ecOrderNumber\":\"20202070817261111\",\"orderNumber\":\"AR202007081017453500\",\"payOrderNumber\":\"\",\"phone\":\"1860000000\",\"productList\":[{\"name\":\"小米18\",\"number\":2,\"pictureUrl\":\"https://dss0.bdstatic.com/-0U0bnSm1A5BphGlnYG/tam-ogel/93d9d2b0e5373b93ca5032d13866fd14_254_144.jpg\",\"price\":60000.0}],\"repayDay\":\"08\",\"stageAmount\":40000.0,\"stageNumber\":3,\"status\":\"01\",\"total\":2,\"updateDate\":1594261066000,\"userId\":\"56f72c55c0cc11ea8c81fa163efd3ee0\"},{\"address\":\"互联网创业中心\",\"amount\":60000.0,\"applicationDate\":1594173896000,\"createDate\":1594173896000,\"ecCode\":\"MC0001\",\"ecName\":\"ARJ\",\"ecOrderNumber\":\"20202070817260000\",\"orderNumber\":\"AR202007081004565300\",\"payOrderNumber\":\"\",\"phone\":\"137777777\",\"productList\":[{\"name\":\"华为P40\",\"number\":2,\"pictureUrl\":\"https://consumer-img.huawei.com/content/dam/huawei-cbg-site/common/mkt/pdp/phones/p40-pro-plus-specs/cn/dimage.jpg\",\"price\":30000.0}],\"repayDay\":\"08\",\"stageAmount\":20000.0,\"stageNumber\":3,\"status\":\"01\",\"total\":2,\"updateDate\":1594260296000,\"userId\":\"56f72c55c0cc11ea8c81fa163efd3ee0\"}]},\"msg\":\"成功\",\"showMsg\":\"success\"}";
// 公钥加密
String encrypt = RSAUtils.encryptByPubKey(data, publicKeyString);
// 私钥解密
String decrypt = RSAUtils.decryptByPriKey(encrypt, privateKeyString);

System.out.println("加密前:" + data);
System.out.println("加密后:" + encrypt);
System.out.println("解密后:" + decrypt);

SignVo signVo = new SignVo();
signVo.setSignA("testA");
signVo.setSignB("testB");
signVo.setSignC("testC");
String sign = RSAUtils.sign(signVo,privateKeyString);

System.out.println("签名:"+sign);

boolean result = RSAUtils.verify(signVo,publicKeyString,sign);

System.out.println("验签结果:"+result);


} catch (Exception e) {
e.printStackTrace();
}
}
}
@Data
class SignVo{
/**
* 标志A
*/
private String signA;
/**
* 标志B
*/
private String signB;
/**
* 标志C
*/
private String signC;
}

DH加密算法

上面我们说到非对称加密算法加密速度慢,耗资源,可以使用非对称加密算法进行通信,协商密钥后,在使用对称加密算法进行数据传输,这就是DH加密算法的核心。

其实也可以说DH加密算法是一种建立密钥的方法,而不是加密方法。

我们以甲乙双方发送数据为模型进行分析:

  1. 甲方(消息发送方,下同)构建密钥对(公钥+私钥),甲方公布公钥给乙方(消息接收方,下同);

  2. 乙方以甲方发送过来的公钥作为参数构造密钥对(公钥+私钥),将构造出来的公钥公布给甲方;

  3. 甲方用“甲方的私钥 + 乙方的公钥”构造本地密钥;

  4. 乙方用“乙方的私钥 + 甲方的公钥”构造本地的密钥;

  5. 这个时候,甲乙两方本地新构造出来的密钥应该一样,甲乙双方可以通过本地密钥进行数据的加密和解密;

  6. 然后就可以使用AES/DES这类对称加密算法进行数据的安全传送了。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
public class DHUtils {

/**
* 加密算法
*/
public static final String ALGORITHM = "DH";

/**
* 默认密钥字节数
* 需要为64的倍数,且在512到1024之间
*/
private static final int KEY_SIZE = 1024;

/**
* DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。
*/
public static final String SECRET_ALGORITHM = "DES";

/**
* 公钥私钥Key值,便于从Map获取
*/
private static final String PUBLIC_KEY = "DHPublicKey";
private static final String PRIVATE_KEY = "DHPrivateKey";

/**
* 初始化甲方密钥
*
* @return
* @throws Exception
*/
public static Map<String, Object> initKey() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);

KeyPair keyPair = keyPairGenerator.generateKeyPair();

// 甲方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();

// 甲方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();

Map<String, Object> keyMap = new HashMap<>(2);

keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}

/**
* 初始化乙方密钥
*
* @param key 甲方公钥
* @return
* @throws Exception
*/
public static Map<String, Object> initKey(String key) throws Exception {
// 解析甲方公钥
byte[] keyBytes = Base64.decodeBase64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

// 由甲方公钥构建乙方密钥
DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
keyPairGenerator.initialize(dhParamSpec);

KeyPair keyPair = keyPairGenerator.generateKeyPair();

// 乙方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();

// 乙方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();

Map<String, Object> keyMap = new HashMap<>(2);

keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);

return keyMap;
}

/**
* 加密
*
* @param data 待加密数据
* @param publicKey 甲方公钥
* @param privateKey 乙方私钥
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data, String publicKey,String privateKey) throws Exception {

// 生成本地密钥
SecretKey secretKey = getSecretKey(publicKey, privateKey);

// 数据加密
Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

return cipher.doFinal(data);
}

/**
* 加密
* @param data 待加密数据
* @param publicKey 甲方公钥
* @param privateKey 乙方私钥
* @return
* @throws Exception
*/
public static String encrypt(String data, String publicKey,String privateKey) throws Exception {
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
byte[] result = encrypt(bytes,publicKey,privateKey);
return Base64.encodeBase64String(result);
}

/**
* 解密
*
* @param data 待解密数据
* @param publicKey 乙方公钥
* @param privateKey 乙方私钥
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data, String publicKey, String privateKey) throws Exception {

// 生成本地密钥
SecretKey secretKey = getSecretKey(publicKey, privateKey);
// 数据解密
Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, secretKey);

return cipher.doFinal(data);
}

/**
* 解密
* @param data 待解密数据
* @param publicKey 乙方公钥
* @param privateKey 甲方私钥
* @return
* @throws Exception
*/
public static String decrypt(String data, String publicKey, String privateKey) throws Exception {
byte[] bytes = Base64.decodeBase64(data);
byte[] result = decrypt(bytes,publicKey,privateKey);
return new String(result,StandardCharsets.UTF_8);
}

/**
* 构建密钥
*
* @param publicKey 公钥
* @param privateKey 私钥
* @return
* @throws Exception
*/
private static SecretKey getSecretKey(String publicKey, String privateKey) throws Exception {
// 初始化公钥
byte[] pubKeyBytes = Base64.decodeBase64(publicKey);

KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

// 初始化私钥
byte[] priKeyBytes = Base64.decodeBase64(privateKey);

PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);

KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
keyAgree.init(priKey);
keyAgree.doPhase(pubKey, true);

// 生成本地密钥
SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);

return secretKey;
}

/**
* 取得私钥
*
* @param keyMap
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap){
Key key = (Key) keyMap.get(PRIVATE_KEY);

return Base64.encodeBase64String(key.getEncoded());
}

/**
* 取得公钥
*
* @param keyMap
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap){
Key key = (Key) keyMap.get(PUBLIC_KEY);

return Base64.encodeBase64String(key.getEncoded());
}


public static void main(String[] args) throws Exception {
// 生成甲方密钥对
Map<String, Object> aKeyMap = DHUtils.initKey();
String aPublicKey = DHUtils.getPublicKey(aKeyMap);
String aPrivateKey = DHUtils.getPrivateKey(aKeyMap);

System.out.println("甲方公钥:" + aPublicKey);
System.out.println("甲方私钥:" + aPrivateKey);

// 由甲方公钥产生本地密钥对
Map<String, Object> bKeyMap = DHUtils.initKey(aPublicKey);
String bPublicKey = DHUtils.getPublicKey(bKeyMap);
String bPrivateKey = DHUtils.getPrivateKey(bKeyMap);

System.out.println("乙方公钥:" + bPublicKey);
System.out.println("乙方私钥:" + bPrivateKey);

String aInput = "abc ";
System.out.println("原数据: " + aInput);

// 由甲方公钥,乙方私钥构建密文
String aCode = DHUtils.encrypt(aInput, aPublicKey,bPrivateKey);

System.out.println("加密:"+aCode);

// 由乙方公钥,甲方私钥解密
String aDecode = DHUtils.decrypt(aCode, bPublicKey, aPrivateKey);

System.out.println("解密: " + aDecode);


String bInput = "def ";
System.out.println("原数据: " + bInput);

// 由乙方公钥,甲方私钥构建密文
String bCode = DHUtils.encrypt(bInput, bPublicKey,aPrivateKey);

System.out.println("加密:"+bCode);

// 由甲方公钥,乙方私钥解密
String bDecode = DHUtils.decrypt(bCode, aPublicKey, bPrivateKey);

System.out.println("解密: " + bDecode);

}
}

ECC椭圆加密算法

椭圆加密算法(ECC)是一种公钥加密体制,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性。

因此其也是一种非对称可逆加密算法。

相比RSA加密算法,ECC加密算法的安全性更高,有研究表明160位的椭圆密钥与1024位的RSA密钥安全性相同。

同时在私钥的加密解密速度上,ECC算法比RSA速度更快。

Java目前不支持ECC算法的加解密,只支持公私钥的生成,这儿我们引入org.bouncycastle.bcprov-jdk15on包,来实现Java下的ECC加密算法。

pom文件:

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
public class ECCUtils {

private static final String ALGORITHM = "EC";

private static final String PROVIDER = "BC";

private static final String TRANSFORM = "ECIES";

private static final int SIZE = 256;

/**
* Map key值
*/
private static final String PUBLIC_KEY = "publicKey";
private static final String PRIVATE_KEY = "privateKey";


/**
* Java目前不支持ECC加解密,只支持公私钥的生成
* 这儿我们使用BouncyCastleProvider来支持ECC加密算法
*/
static{
Security.addProvider(new BouncyCastleProvider());
}


/**
* 生成秘钥对
* @return
* @throws Exception
*/
public static KeyPair getKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);

keyPairGenerator.initialize(SIZE, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;

}


/**
* 获取公钥
* @param keyPair
* @return
*/
public static String getPublicKey(KeyPair keyPair){
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
byte[] bytes = publicKey.getEncoded();
return Base64.encodeBase64String(bytes);
}


/**
* 获取私钥
* @param keyPair
* @return
*/
public static String getPrivateKey(KeyPair keyPair){
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
byte[] bytes = privateKey.getEncoded();
return Base64.encodeBase64String(bytes);

}


/**
* 将Base64编码后的公钥转换成PublicKey对象
* @param pubStr
* @return
* @throws Exception
*/
public static ECPublicKey string2PublicKey(String pubStr) throws Exception{

byte[] keyBytes = Base64.decodeBase64(pubStr);

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM,PROVIDER);

ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);

return publicKey;

}


/**
* 将Base64编码后的私钥转换成PrivateKey对象
* @param priStr
* @return
* @throws Exception
*/
public static ECPrivateKey string2PrivateKey(String priStr) throws Exception{

byte[] keyBytes = Base64.decodeBase64(priStr);

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);

ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);

return privateKey;
}


/**
* 使用公钥加密数据
* @param content
* @param publicKey
* @return
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] content,PublicKey publicKey) throws Exception{

Cipher cipher = Cipher.getInstance(TRANSFORM,PROVIDER);

cipher.init(Cipher.ENCRYPT_MODE,publicKey);

byte[] bytes = cipher.doFinal(content);

return bytes;
}


/**
* 私钥解密
* @param content
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] content, PrivateKey privateKey) throws Exception{

Cipher cipher = Cipher.getInstance(TRANSFORM,PROVIDER);

cipher.init(Cipher.DECRYPT_MODE,privateKey);

byte[] bytes = cipher.doFinal(content);

return bytes;
}

/**
* 加密数据
* @param content
* @param publicKey
* @return
* @throws Exception
*/
public static String encrypt(String content,String publicKey) throws Exception{
ECPublicKey pubKey = string2PublicKey(publicKey);
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
byte[] result = encryptByPublicKey(bytes,pubKey);
return Base64.encodeBase64String(result);
}

/**
* 解密数据
* @param cipherText
* @param privateKey
* @return
* @throws Exception
*/
public static String decrypt(String cipherText,String privateKey) throws Exception{
ECPrivateKey priKey = string2PrivateKey(privateKey);
byte[] bytes = Base64.decodeBase64(cipherText);
byte[] result = decryptByPrivateKey(bytes,priKey);
return new String(result,StandardCharsets.UTF_8);
}

/**
* 生成一组密钥对
* @return
*/
public static Map<String,String> initKeyPairStr() throws Exception{
KeyPair keyPair = ECCUtils.getKeyPair();
String publicKeyStr =ECCUtils.getPublicKey(keyPair);
String privateKeyStr = ECCUtils.getPrivateKey(keyPair);
Map<String,String> map = new HashMap<>();
map.put(PUBLIC_KEY,publicKeyStr);
map.put(PRIVATE_KEY,privateKeyStr);
return map;
}


public static void main(String[] args) throws Exception{
String text = "131sdfsfd张庆伟金额取";
Map<String,String> keyPair = initKeyPairStr();
String publicKey = keyPair.get(PUBLIC_KEY);
String privateKey = keyPair.get(PRIVATE_KEY);
System.out.println("公钥:"+publicKey);
System.out.println("私钥:"+privateKey);
String encrypt = encrypt(text,publicKey);
System.out.println("加密数据:"+encrypt);
String decrypt = decrypt(encrypt,privateKey);
System.out.println("解密数据:"+decrypt);
}
}

总结

以上就是比较常用的一些加密算法,当然有一些其他的加密算法,如DSA等这儿未作涉及,有兴趣的也可以查看相关资料等。

了解一些加密算法,以便在设计系统时可以正确选择合适的数据加密算法,来保证系统更加稳定、可靠的运行。




-------------文章结束啦 ~\(≧▽≦)/~ 感谢您的阅读-------------

SakuraTears wechat
扫一扫关注我的公众号
您的支持就是我创作的动力!
0%