DES算法简单介绍及用法
程序员文章站
2022-03-12 19:36:20
...
大家好,今天给大家分享一下DES加密
一、DES介绍
加密一般分为可逆加密和不可逆加密,其中可逆加密一般又分为对称加密和非对称加密,前者是我们使用公用**加密之后可以使用公用**再解密出来,而后者则是使用公用**加密之后必须使用私用**来解密。除此之外还有不可逆的加密,使用不可逆加密之后是无法解密的,如果我们想验证数据是否正确只能使用同样方法再次加密然后比较两次加密完生成的key是否相同。所以一般可以使用不可逆加密的地方都可以使用可逆加密,区别就是是否需要再解密出来。
为了保证数据传输过程中不被人拦截从而解密盗取关键信息,需要在双向加密过程中设置**。**不同的情况下,相同算法相同数据也会得到不同的结果。而结果字符集越长就越能避免密码碰撞,也就是不同密码产生相同的结果。所以,对称算法的**设置需要尽量复杂,结果集也需要尽量长,才能保证结果更安全。
二、DES在cookie中的用处
可以使用DES来将用户的id和登录时间加密为uid和lid,存在cookie中,然后在拦截器中解密出来验证uid和lid的正确性,从而实现用户通行许可的验证。
三、代码演示
1.首先是DES的工具类
package com.task.utils;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
/**
* DES双向加密工具类
*/
public class DESUtil {
//安全**
private String keyData = "ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstwxyz0123456789-_.";
//无参构造
public DESUtil() {
}
//有参构造
public DESUtil(String key) {
this.keyData = key;
}
/**
* 将Long类型加密
* @param source
* @return
* @throws UnsupportedEncodingException
*/
public String encryptFromLong(long source)throws UnsupportedEncodingException{
String source1=String.valueOf(source);//先将long类型转化为String类型
return encrypt(source1, "UTF-8");
}
/**
* 将解密好的转化为long类型
* @param encryptedData
* @return
* @throws UnsupportedEncodingException
*/
public long decryptToLong(String encryptedData) throws UnsupportedEncodingException {
long decryptLong=Long.valueOf(decrypt(encryptedData, "UTF-8"));
return decryptLong;
}
/**
*加密UTF-8,调用底下的方法
* @param source 待加密数据
* @return 加密完成的数据
* @throws UnsupportedEncodingException
* 异常
*/
public String encrypt(String source)throws UnsupportedEncodingException{
return encrypt(source, "UTF-8");
}
/**
*解密UTF-8,调用底下的方法
* @param encryptedData 待解密数据
* @return 解密完成数据
* @throws UnsupportedEncodingException
* 异常
*/
public String decrypt(String encryptedData)
throws UnsupportedEncodingException {
return decrypt(encryptedData, "UTF-8");
}
/**
*功能:加密
* @param source 待加密数据
* @param charSet 字符编码
* @return 加密完成数据
* @throws UnsupportedEncodingException
* 异常
*/
public String encrypt(String source, String charSet)
throws UnsupportedEncodingException {
String encrypt = null;
byte[] ret = encrypt(source.getBytes(charSet));
encrypt = new String(Base64.encode(ret));
return encrypt;
}
/**
*功能:解密
* @param encryptedData 待解密数据
* @param charSet 字符编码
* @return 解密完成数据
* @throws UnsupportedEncodingException
* 异常
*/
public String decrypt(String encryptedData, String charSet)
throws UnsupportedEncodingException {
String decryptedData = null;
byte[] ret = decrypt(Base64.decode(encryptedData.toCharArray()));
decryptedData = new String(ret, charSet);
return decryptedData;
}
/**
*加密
* @param primaryData
* @return
*/
private byte[] encrypt(byte[] primaryData) {
//取得安全**
byte rawKeyData[] = getKey();
//DES算法要求有一个可信任的随机数源
SecureRandom sr = new SecureRandom();
//使用原始**数据创建DESKeySpec对象
DESKeySpec dks = null;
try {
dks = new DESKeySpec(keyData.getBytes());
} catch (InvalidKeyException e) {
e.printStackTrace();
}
//创建一个**工厂
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//用**工厂把DESKeySpec转换成一个SecretKey对象
SecretKey key = null;
try {
key = keyFactory.generateSecret(dks);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
// Cipher对象实际完成加密操作
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
e.printStackTrace();
}
// 用**初始化Cipher对象
try {
cipher.init(Cipher.ENCRYPT_MODE, key, sr);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
// 正式执行加密操作
byte encryptedData[] = null;
try {
encryptedData = cipher.doFinal(primaryData);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException|BadPaddingException e) {
e.printStackTrace();
}
//返回加密数据
return encryptedData;
}
/**
*加密
* @param encryptedData
* @return
*/
private byte[] decrypt(byte[] encryptedData) {
/** DES算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 取得安全** */
byte rawKeyData[] = getKey();
/** 使用原始**数据创建DESKeySpec对象 */
DESKeySpec dks = null;
try {
dks = new DESKeySpec(keyData.getBytes());
} catch (InvalidKeyException e) {
e.printStackTrace();
}
/** 创建一个**工厂 */
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
/** 用**工厂把DESKeySpec转换成一个SecretKey对象 */
SecretKey key = null;
try {
key = keyFactory.generateSecret(dks);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
/** Cipher对象实际完成加密操作 */
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
/** 用**初始化Cipher对象 */
try {
cipher.init(Cipher.DECRYPT_MODE, key, sr);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
/** 正式执行解密操作 */
byte decryptedData[] = null;
try {
decryptedData = cipher.doFinal(encryptedData);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedData;
}
/**
*获得**
* @return
*/
private byte[] getKey() {
/** DES算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为我们选择的DES算法生成一个**生成器对象 */
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
kg.init(sr);
/** 生成**工具类 */
SecretKey key = kg.generateKey();
/** 生成**byte数组 */
byte rawKeyData[] = key.getEncoded();
return rawKeyData;
}
}
这里越下面的的方法越底层,上面的都是一层一层往下面调用的,所以可以根据需要调整传入参数的时候在上面修改,然后调用下面的方法。
2.下面是上面需要调用Base64编码的工具类,Base64也是可反向解码的编码格式。
package com.task.utils;
import java.io.*;
/**
* Base64编码和解码
*/
public class Base64 {
public Base64() {
}
/**
* 编码字符串
* @param data 需要编码的字符串
* @return 编码完成的字符串
*/
public static String encode(String data) {
return new String(encode(data.getBytes()));
}
/**
* 解码字符串
* @param data 需要解码的字符串
* @return 解码完成的字符串
*/
public static String decode(String data) {
return new String(decode(data.toCharArray()));
}
/**
* 编码byte[]
* @param data 输入需要编码的字节组
* @return 编码完成的char类型数组
*/
public static char[] encode(byte[] data) {
char[] out = new char[((data.length + 2) / 3) * 4];
for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
boolean quad = false;
boolean trip = false;
int val = (0xFF & (int) data[i]);
val <<= 8;
if ((i + 1) < data.length) {
val |= (0xFF & (int) data[i + 1]);
trip = true;
}
val <<= 8;
if ((i + 2) < data.length) {
val |= (0xFF & (int) data[i + 2]);
quad = true;
}
out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 1] = alphabet[val & 0x3F];
val >>= 6;
out[index + 0] = alphabet[val & 0x3F];
}
return out;
}
/**
* 解码
* @param data
* @return
*/
public static byte[] decode(char[] data) {
int tempLen = data.length;
for (int ix = 0; ix < data.length; ix++) {
if ((data[ix] > 255) || codes[data[ix]] < 0) {
--tempLen; // ignore non-valid chars and padding
}
}
// calculate required length:
// -- 3 bytes for every 4 valid base64 chars
// -- plus 2 bytes if there are 3 extra base64 chars,
// or plus 1 byte if there are 2 extra.
int len = (tempLen / 4) * 3;
if ((tempLen % 4) == 3) {
len += 2;
}
if ((tempLen % 4) == 2) {
len += 1;
}
byte[] out = new byte[len];
int shift = 0; // # of excess bits stored in accum
int accum = 0; // excess bits
int index = 0;
// we now go through the entire array (NOT using the 'tempLen' value)
for(int ix = 0; ix < data.length; ix++) {
int value = (data[ix] > 255) ? -1 : codes[data[ix]];
if (value >= 0) { // skip over non-code
accum <<= 6; // bits shift up by 6 each time thru
shift += 6; // loop, with new bits being put in
accum |= value; // at the bottom.
if (shift >= 8) { // whenever there are 8 or more shifted in,
shift -= 8; // write them out (from the top, leaving any
out[index++] = // excess at the bottom for next iteration.
(byte) ((accum >> shift) & 0xff);
}
}
}
// if there is STILL something wrong we just have to throw up now!
if (index != out.length) {
throw new Error("Miscalculated data length (wrote " + index
+ " instead of " + out.length + ")");
}
return out;
}
/**
* 编码文件
* @param file
* @throws IOException
*/
public static void encode(File file) throws IOException {
if (!file.exists()) {
System.exit(0);
}
else {
byte[] decoded = readBytes(file);
char[] encoded = encode(decoded);
writeChars(file, encoded);
}
file = null;
}
/**
* 解码文件
* @param file
* @throws IOException
*/
public static void decode(File file) throws IOException {
if (!file.exists()) {
System.exit(0);
} else {
char[] encoded = readChars(file);
byte[] decoded = decode(encoded);
writeBytes(file, decoded);
}
file = null;
}
private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
.toCharArray();
private static byte[] codes = new byte[256];
static {
for (int i = 0; i < 256; i++) {
codes[i] = -1;
// LoggerUtil.debug(i + "&" + codes[i] + " ");
}
for (int i = 'A'; i <= 'Z'; i++) {
codes[i] = (byte) (i - 'A');
// LoggerUtil.debug(i + "&" + codes[i] + " ");
}
for (int i = 'a'; i <= 'z'; i++) {
codes[i] = (byte) (26 + i - 'a');
// LoggerUtil.debug(i + "&" + codes[i] + " ");
}
for (int i = '0'; i <= '9'; i++) {
codes[i] = (byte) (52 + i - '0');
// LoggerUtil.debug(i + "&" + codes[i] + " ");
}
codes['+'] = 62;
codes['/'] = 63;
}
/**
* 读取文件中的字符,转化为byte[]
* @param file
* @return
* @throws IOException
*/
private static byte[] readBytes(File file) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = null;
InputStream fis = null;
InputStream is = null;
try {
fis = new FileInputStream(file);
is = new BufferedInputStream(fis);
int count = 0;
byte[] buf = new byte[16384];
while ((count = is.read(buf)) != -1) {
if (count > 0) {
baos.write(buf, 0, count);
}
}
b = baos.toByteArray();
} finally {
try {
if (fis != null)
fis.close();
if (is != null)
is.close();
// if (baos != null)
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return b;
}
/**
* 读取文件中的字符,转化为char[]
* @param file
* @return
* @throws IOException
*/
private static char[] readChars(File file) throws IOException {
CharArrayWriter caw = new CharArrayWriter();
Reader fr = null;
Reader in = null;
try {
fr = new FileReader(file);
in = new BufferedReader(fr);
int count = 0;
char[] buf = new char[16384];
while ((count = in.read(buf)) != -1) {
if (count > 0) {
caw.write(buf, 0, count);
}
}
} finally {
try {
// if (caw != null)
caw.close();
if (in != null)
in.close();
if (fr != null)
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return caw.toCharArray();
}
/**
* 将byte[]字符写入文件中
* @param file
* @param data
* @throws IOException
*/
private static void writeBytes(File file, byte[] data) throws IOException {
OutputStream fos = null;
OutputStream os = null;
try {
fos = new FileOutputStream(file);
os = new BufferedOutputStream(fos);
os.write(data);
} finally {
try {
if (os != null)
os.close();
if (fos != null)
fos.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
/**
* 将char[]字符写入文件中
* @param file
* @param data
* @throws IOException
*/
private static void writeChars(File file, char[] data) throws IOException {
Writer fos = null;
Writer os = null;
try {
fos = new FileWriter(file);
os = new BufferedWriter(fos);
os.write(data);
} finally {
try {
if (os != null)
os.close();
if (fos != null)
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3.上测试类,注意需要先创建工具类的对象才能调用
@Test
public void listByName() throws Exception{
DESUtil desUtil=new DESUtil();
long loginTime=System.currentTimeMillis();
String str1=desUtil.encryptFromLong(loginTime);
System.out.println(str1);
long str2=desUtil.decryptToLong(str1);
System.out.println("l"+str2);
System.out.println(desUtil.encrypt("wangqichao"));
}
结果如下,可以看到加密和解密都成功了,证明DES的功能实现了
今天的分享就到这了,希望大家多多指正,互相学习~