Java实现3DES加密算法

加密简介

单向加密:通过对数据进行摘要计算生成密文,密文不可逆推还原。算法代表:MD5,SHA

双向加密:与单向加密相反,可以把密文逆推还原成明文,双向加密又分为对称加密和非对称加密

对称加密:指数据使用者必须拥有相同的密钥才可以进行加密解密。算法代表:DES,3DES,AES,IDEA,RC4,RC5;

非对称加密:非对称加密是一种“信息公开的密钥交换协议”。非对称加密需要公开密钥和私有密钥两组密钥,公开密钥和私有密钥是配对起来的,也就是说使用公开密钥进行数据加密,只有对应的私有密钥才能解密。算法代表:RSA,DSA。

3DES算法:3DES是三重数据加密,且可以逆推的一种算法方案。但由于3DES的算法是公开的,所以算法本身没有密钥可言,主要依靠唯一密钥来确保数据加解密的安全。到目前为止,仍没有人能破解3DES。

3DES加密类

CBC模式(需要指定IV加密向量)

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
package cn.appblog.util;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings({ "restriction" })
public class ThreeDES {
private static final String IV = "1234567-";
public static final String KEY = "AppBlog.CN";

/**
* DESCBC加密
*
* @param src
* 数据源
* @param key
* 密钥,长度必须是8的倍数
* @return 返回加密后的数据
* @throws Exception
*/
public String encryptDESCBC(final String src, final String key) throws Exception {

// --生成key,同时制定是des还是DESede,两者的key长度要求不同
final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

// --加密向量
final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

// --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE, secretKey)即可
final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

// --通过base64,将加密数组转换成字符串
final BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b);
}

/**
* DESCBC解密
*
* @param src
* 数据源
* @param key
* 密钥,长度必须是8的倍数
* @return 返回解密后的原始数据
* @throws Exception
*/
public String decryptDESCBC(final String src, final String key) throws Exception {
// --通过base64,将字符串转成byte数组
final BASE64Decoder decoder = new BASE64Decoder();
final byte[] bytesrc = decoder.decodeBuffer(src);

// --解密的key
final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

// --向量
final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

// --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE, secretKey)即可
final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
final byte[] retByte = cipher.doFinal(bytesrc);

return new String(retByte);

}

// 3DESECB加密,key必须是长度大于等于 3*8 = 24 位
public String encryptThreeDESECB(final String src, final String key) throws Exception {
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);

final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, securekey);
final byte[] b = cipher.doFinal(src.getBytes());

final BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b).replaceAll("\r", "").replaceAll("\n", "");
}

// 3DESECB解密,key必须是长度大于等于 3*8 = 24 位
public String decryptThreeDESECB(final String src, final String key) throws Exception {
// --通过base64,将字符串转成byte数组
final BASE64Decoder decoder = new BASE64Decoder();
final byte[] bytesrc = decoder.decodeBuffer(src);
// --解密的key
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);

// --Chipher对象解密
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, securekey);
final byte[] retByte = cipher.doFinal(bytesrc);

return new String(retByte);
}
}

ECB模式(无需指定IV加密向量)

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
/**
* 3DES的密钥必须是24位的byte数组
* 随便拿一个String.getBytes()是不行的,会报如下错误
*   java.security.InvalidKeyException: Invalid key length: 59 bytes
*   解决方法有很多,①按密钥固定长度重新定义字符串;②先把字符串用Base64或者MD5加密,然后截取固定长度的字符转成byte数组;③字符串转成Byte数组,针对该数组进行修改,若长度过长则只截取一部分,若长度不够则补零
*  
* 加密结果的编码方式要一致
* 从byte数组转成字符串,一般有两种方式,base64处理和十六进制处理。
*/
public class DESedeHelper {
//定义加密算法,有DES、DESede(即3DES)、Blowfish
private static final String Algorithm = "DESede";
private static final String charset = "UTF-8";

private final String PASSWORD_CRYPT_KEY;
private DESedeHelper(String key) {
this.PASSWORD_CRYPT_KEY = key;
}

public static DESedeHelper getInstance(String key) {
return new DESedeHelper(key);
}

/**
* 加密方法
*
* @param src 源数据的字节数组
* @return
*/
public String encryptMode(String src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm); //生成密钥
Cipher cipher = Cipher.getInstance(Algorithm); //实例化负责加密/解密的Cipher工具类
cipher.init(Cipher.ENCRYPT_MODE, deskey); //初始化为加密模式
return Base64.encodeBase64String(cipher.doFinal(src.getBytes(charset)));
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (Exception e3) {
e3.printStackTrace();
}
return null;
}

/**
* 解密函数
*
* @param src 密文的字节数组
* @return
*/
public String decryptMode(String src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);
Cipher cipher = Cipher.getInstance(Algorithm);
cipher.init(Cipher.DECRYPT_MODE, deskey); //初始化为解密模式

return new String(cipher.doFinal(Base64.decodeBase64(src)), charset);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (Exception e3) {
e3.printStackTrace();
}
return null;
}

/*
* 根据字符串生成密钥字节数组
* @param keyStr 密钥字符串
* @return
* @throws UnsupportedEncodingException
*/
public byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
byte[] key = new byte[24]; //声明一个位的字节数组,默认里面都是0
byte[] temp = keyStr.getBytes(charset); //将字符串转成字节数组

/*
* 执行数组拷贝
* System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位)
*/
if (key.length > temp.length) {
//如果temp不够位,则拷贝temp数组整个长度的内容到key数组中
System.arraycopy(temp, 0, key, 0, temp.length);
} else {
//如果temp大于位,则拷贝temp数组个长度的内容到key数组中
System.arraycopy(temp, 0, key, 0, key.length);
}
return key;
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.net.URLEncoder;
import cn.appblog.util.ThreeDES;

public class ThreeDESTest {
public static void main(String[] args) throws Exception {
final String key = "AppBlog.CN";
// 加密流程
String homepage = "http://www.appblog.cn";
ThreeDES threeDES = new ThreeDES();
String telePhone_encrypt = "";
homepageEncrypt = threeDES.encryptThreeDESECB(URLEncoder.encode(telePhone, "UTF-8"), key);
System.out.println(homepageEncrypt);

// 解密流程
String homepageDecrypt = threeDES.decryptThreeDESECB(telePhone_encrypt, key);
System.out.println("模拟代码解密: " + homepageDecrypt);
}
}

注意:(1)3DES密钥的长度必须是8的倍数,可取24位或32位;(2)加密结果的byte数组转换为字符串,一般采用两种方式:Base64处理或十六进制处理。

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :