在日常设计及开发中,为确保数据传输和数据存储的安全,可通过特定的算法,将数据明文加密成复杂的密文。目前主流加密手段大致可分为单向加密和双向加密。
- 单向加密:通过对数据进行摘要计算生成密文,密文不可逆推还原。算法代表:Base64,MD5,SHA;
双向加密:与单向加密相反,可以把密文逆推还原成明文,双向加密又分为对称加密和非对称加密。
对称加密:指数据使用者必须拥有相同的密钥才可以进行加密解密,就像彼此约定的一串暗号。算法代表:DES,3DES,AES,IDEA,RC4,RC5;
非对称加密:相对对称加密而言,无需拥有同一组密钥,非对称加密是一种“信息公开的密钥交换协议”。非对称加密需要公开密钥和私有密钥两组密钥,公开密钥和私有密钥是配对起来的,也就是说使用公开密钥进行数据加密,只有对应的私有密钥才能解密。这两个密钥是数学相关,用某用户密钥加密后的密文,只能使用该用户的加密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个密钥性质。这里把公开的密钥为公钥,不公开的密钥为私钥。算法代表:RSA,DSA。
3DES是三重数据加密,且可以逆推的一种算法方案。但由于3DES的算法是公开的,所以算法本身没有密钥可言,主要依靠唯一密钥来确保数据加解密的安全。到目前为止,仍没有人能破解3DES。
package com.me.util;
import java.security.Key;
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;
public class Des3 {
// 密钥
// private final static String secretKey = "uatspdbcccgame2014061800";
// 向量
private final static String iv = "01234567";
// 加解密的编码方统一使用式
private final static String encoding = "utf-8";
/**
* 3DES加密 key必须是长度大于等于 3*8 = 24 位
*
* @param plainText 数据源
* @param security_key 密钥
* @return
* @throws Exception
*/
public static String encode(String plainText, String security_key) throws Exception {
//生成key,同时制定是des还是DESede,两者的key长度要求不同
DESedeKeySpec spec = new DESedeKeySpec(security_key.getBytes());
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
Key deskey = keyfactory.generateSecret(spec);
//通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,
// cipher.init(Cipher.ENCRYPT_MODE,secretKey)就可以了.
Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
//加密向量
IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
//通过base64,将加密数组转换成字符串
return Base64.encode(encryptData);
}
/**
* 3DES解密 key必须是长度大于等于 3*8 = 24 位
*
* @param encryptText 数据源
* @param security_key 密钥
* @return
* @throws Exception
*/
public static String decode(String encryptText, String security_key) throws Exception {
//解密的key
DESedeKeySpec spec = new DESedeKeySpec(security_key.getBytes());
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
Key deskey = keyfactory.generateSecret(spec);
//Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,
// cipher.init(Cipher.DECRYPT_MODE,secretKey)就可以了.
Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
//加密向量
IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
//通过base64,将字符串转成byte数组
byte[] decryptData = cipher.doFinal(Base64.decode(encryptText));
return new String(decryptData, encoding);
}
/**
* DESCBC加密
*
* @param plainText 数据源
* @param security_key 密钥,长度必须是8的倍数
* @return 返回加密后的数据
* @throws Exception
*/
public String encryptDESCBC(final String plainText, final String security_key) throws Exception {
// 生成key,同时制定是des还是DESede,两者的key长度要求不同
DESKeySpec desKeySpec = new DESKeySpec(security_key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
//加密向量
final IvParameterSpec ips = 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, ips);
final byte[] b = cipher.doFinal(plainText.getBytes("UTF-8"));
//通过base64,将加密数组转换成字符串
return Base64.encode(b);
}
/**
* DESCBC解密
*
* @param encryptText 数据源
* @param security_key 密钥,长度必须是8的倍数
* @return 返回解密后的原始数据
* @throws Exception
*/
public String decryptDESCBC(final String encryptText, final String security_key) throws Exception {
// 解密的key
DESKeySpec desKeySpec = new DESKeySpec(security_key.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
//向量
final IvParameterSpec ips = 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, ips);
final byte[] retByte = cipher.doFinal(Base64.decode(encryptText));
return new String(retByte);
}
}
测试类
package test;
import java.net.URLEncoder;
import com.mes.util.ThreeDES;
public class ThreeDES_TEST {
public static void main(String[] args) throws Exception {
final String key = "cf410f84904a44cc8a7f48fc4134e8f9";
// 加密流程
String telePhone = "15629551180";
ThreeDES threeDES = new ThreeDES();
String telePhone_encrypt = "";
telePhone_encrypt = threeDES.encryptThreeDESECB(URLEncoder.encode(telePhone, "UTF-8"), key);
System.out.println(telePhone_encrypt);// nWRVeJuoCrs8a+Ajn/3S8g==
// 解密流程
String tele_decrypt = threeDES.decryptThreeDESECB(telePhone_encrypt, key);
System.out.println("模拟代码解密:" + tele_decrypt);
}
}
测试结果
Bu7KzIWrplmh4nVj0d2Htg==
模拟代码解密:15629551180
Base64类
package com.me.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Base64 {
private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
public static String encode(byte[] data) {
int start = 0;
int len = data.length;
StringBuffer buf = new StringBuffer(data.length * 3 / 2);
int end = len - 3;
int i = start;
int n = 0;
while (i <= end) {
int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8) | (((int) data[i + 2]) & 0x0ff);
buf.append(legalChars[(d >> 18) & 63]);
buf.append(legalChars[(d >> 12) & 63]);
buf.append(legalChars[(d >> 6) & 63]);
buf.append(legalChars[d & 63]);
i += 3;
if (n++ >= 14) {
n = 0;
buf.append(" ");
}
}
if (i == start + len - 2) {
int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8);
buf.append(legalChars[(d >> 18) & 63]);
buf.append(legalChars[(d >> 12) & 63]);
buf.append(legalChars[(d >> 6) & 63]);
buf.append("=");
} else if (i == start + len - 1) {
int d = (((int) data[i]) & 0x0ff) << 16;
buf.append(legalChars[(d >> 18) & 63]);
buf.append(legalChars[(d >> 12) & 63]);
buf.append("==");
}
return buf.toString();
}
private static int decode(char c) {
if (c >= 'A' && c <= 'Z')
return ((int) c) - 65;
else if (c >= 'a' && c <= 'z')
return ((int) c) - 97 + 26;
else if (c >= '0' && c <= '9')
return ((int) c) - 48 + 26 + 26;
else
switch (c) {
case '+':
return 62;
case '/':
return 63;
case '=':
return 0;
default:
throw new RuntimeException("unexpected code: " + c);
}
}
/**
* Decodes the given Base64 encoded String to a new byte array. The byte array holding the decoded data is returned.
*/
public static byte[] decode(String s) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
decode(s, bos);
} catch (IOException e) {
throw new RuntimeException();
}
byte[] decodedBytes = bos.toByteArray();
try {
bos.close();
bos = null;
} catch (IOException ex) {
System.err.println("Error while decoding BASE64: " + ex.toString());
}
return decodedBytes;
}
private static void decode(String s, OutputStream os) throws IOException {
int i = 0;
int len = s.length();
while (true) {
while (i < len && s.charAt(i) <= ' ')
i++;
if (i == len)
break;
int tri = (decode(s.charAt(i)) << 18) + (decode(s.charAt(i + 1)) << 12) + (decode(s.charAt(i + 2)) << 6) + (decode(s.charAt(i + 3)));
os.write((tri >> 16) & 255);
if (s.charAt(i + 2) == '=')
break;
os.write((tri >> 8) & 255);
if (s.charAt(i + 3) == '=')
break;
os.write(tri & 255);
i += 4;
}
}
}
注意:
3DES密钥的长度必须是8的倍数,可取24位或32位;
加密结果的byte数组转换为字符串,一般采用两种方式:Base64处理或十六进制处理。