代码实现
package com.wanggs.utils;
import java.io.UnsupportedEncodingException;
/**
* Created by wanggs on 2017/9/6.
*/
public final class Base64 {
public static final String DEFAULT_ENCODING = "UTF-8";
/*
* The methods of this class are static. Do not instantiate this class. Use
* its static methods to get the encoded/decoded results
*/
public static String encode(byte[] byteData) throws UnsupportedEncodingException {
return encode(byteData, DEFAULT_ENCODING);
}
public static String encode(byte[] byteData, String encoding) throws UnsupportedEncodingException {
if(byteData == null) { throw new IllegalArgumentException("byteData cannot be null"); }
return new String(_encode(byteData),encoding);
}
public static byte[] encode(String string) throws UnsupportedEncodingException {
return encode(string, DEFAULT_ENCODING);
}
public static byte[] encode(String string, String encoding) throws UnsupportedEncodingException {
if(string == null) { throw new IllegalArgumentException("string cannot be null"); }
return _encode(string.getBytes(encoding));
}
public final static byte[] _encode(byte[] byteData) {
/* If we received a null argument, exit this method. */
if (byteData == null) { throw new IllegalArgumentException("byteData cannot be null"); }
/*
* Declare working variables including an array of bytes that will
* contain the encoded data to be returned to the caller. Note that the
* encoded array is about 1/3 larger than the input. This is because
* every group of 3 bytes is being encoded into 4 bytes.
*/
int iSrcIdx; // index into source (byteData)
int iDestIdx; // index into destination (byteDest)
// byte[] byteData = (byte[])byteData_in.clone();
// byte[] byteData = byteData_in;
byte[] byteDest = new byte[((byteData.length + 2) / 3) * 4];
/*
* Walk through the input array, 24 bits at a time, converting them from
* 3 groups of 8 to 4 groups of 6 with two unset bits between. as per
* Base64 spec see
* http://www.javaworld.com/javaworld/javatips/jw-javatip36-p2.html for
* example explanation
*/
for (iSrcIdx = 0, iDestIdx = 0; iSrcIdx < byteData.length - 2; iSrcIdx += 3) {
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx] >>> 2) & 077);
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx + 1] >>> 4) & 017 | (byteData[iSrcIdx] << 4) & 077);
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx + 2] >>> 6) & 003 | (byteData[iSrcIdx + 1] << 2) & 077);
byteDest[iDestIdx++] = (byte) (byteData[iSrcIdx + 2] & 077);
}
/*
* If the number of bytes we received in the input array was not an even
* multiple of 3, convert the remaining 1 or 2 bytes.
*/
if (iSrcIdx < byteData.length) {
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx] >>> 2) & 077);
if (iSrcIdx < byteData.length - 1) {
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx + 1] >>> 4) & 017 | (byteData[iSrcIdx] << 4) & 077);
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx + 1] << 2) & 077);
} else
byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx] << 4) & 077);
}
/*
* Use the encoded data as indexes into the Base64 alphabet. (The Base64
* alphabet is completely documented in RFC 1521.)
*/
for (iSrcIdx = 0; iSrcIdx < iDestIdx; iSrcIdx++) {
if (byteDest[iSrcIdx] < 26)
byteDest[iSrcIdx] = (byte) (byteDest[iSrcIdx] + 'A');
else if (byteDest[iSrcIdx] < 52)
byteDest[iSrcIdx] = (byte) (byteDest[iSrcIdx] + 'a' - 26);
else if (byteDest[iSrcIdx] < 62)
byteDest[iSrcIdx] = (byte) (byteDest[iSrcIdx] + '0' - 52);
else if (byteDest[iSrcIdx] < 63)
byteDest[iSrcIdx] = '+';
else
byteDest[iSrcIdx] = '/';
}
/* Pad any unused bytes in the destination string with '=' characters. */
for (; iSrcIdx < byteDest.length; iSrcIdx++)
byteDest[iSrcIdx] = '=';
return byteDest;
}
public static String decode(byte[] encoded) throws UnsupportedEncodingException {
return decode(encoded, DEFAULT_ENCODING);
}
public static String decode(byte[] encoded, String encoding) throws UnsupportedEncodingException {
if(encoded == null) { throw new IllegalArgumentException("encoded cannot be null"); }
return new String(_decode(encoded), encoding);
}
public final static byte[] decode(String encoded) throws UnsupportedEncodingException {
return decode(encoded,DEFAULT_ENCODING);
}
public final static byte[] decode(String encoded, String encoding) throws IllegalArgumentException, UnsupportedEncodingException {
if(null == encoded) { throw new IllegalArgumentException("encoded cannot be null"); }
return _decode(encoded.getBytes(encoding));
}
public final static byte[] _decode(byte[] byteData) throws IllegalArgumentException {
/* If we received a null argument, exit this method. */
if (byteData == null) { throw new IllegalArgumentException("byteData cannot be null"); }
/*
* Declare working variables including an array of bytes that will
* contain the decoded data to be returned to the caller. Note that the
* decoded array is about 3/4 smaller than the input. This is because
* every group of 4 bytes is being encoded into 3 bytes.
*/
int iSrcIdx; // index into source (byteData)
int reviSrcIdx; // index from end of the src array (byteData)
int iDestIdx; // index into destination (byteDest)
byte[] byteTemp = new byte[byteData.length];
/*
* remove any '=' chars from the end of the byteData they would have
* been padding to make it up to groups of 4 bytes note that I don't
* need to remove it just make sure that when progressing throug array
* we don't go past reviSrcIdx ;-)
*/
for (reviSrcIdx = byteData.length; reviSrcIdx -1 > 0 && byteData[reviSrcIdx -1] == '='; reviSrcIdx--) {
; // do nothing. I'm just interested in value of reviSrcIdx
}
/* sanity check */
if (reviSrcIdx -1 == 0) { return null; /* ie all padding */ }
/*
* Set byteDest, this is smaller than byteData due to 4 -> 3 byte munge.
* Note that this is an integer division! This fact is used in the logic
* l8r. to make sure we don't fall out of the array and create an
* OutOfBoundsException and also in handling the remainder
*/
byte byteDest[] = new byte[((reviSrcIdx * 3) / 4)];
/*
* Convert from Base64 alphabet to encoded data (The Base64 alphabet is
* completely documented in RFC 1521.) The order of the testing is
* important as I use the '<' operator which looks at the hex value of
* these ASCII chars. So convert from the smallest up
*
* do all of this in a new array so as not to edit the original input
*/
for (iSrcIdx = 0; iSrcIdx < reviSrcIdx; iSrcIdx++) {
if (byteData[iSrcIdx] == '+')
byteTemp[iSrcIdx] = 62;
else if (byteData[iSrcIdx] == '/')
byteTemp[iSrcIdx] = 63;
else if (byteData[iSrcIdx] < '0' + 10)
byteTemp[iSrcIdx] = (byte) (byteData[iSrcIdx] + 52 - '0');
else if (byteData[iSrcIdx] < ('A' + 26))
byteTemp[iSrcIdx] = (byte) (byteData[iSrcIdx] - 'A');
else if (byteData[iSrcIdx] < 'a' + 26)
byteTemp[iSrcIdx] = (byte) (byteData[iSrcIdx] + 26 - 'a');
}
/*
* 4bytes -> 3bytes munge Walk through the input array, 32 bits at a
* time, converting them from 4 groups of 6 to 3 groups of 8 removing
* the two unset most significant bits of each sorce byte as this was
* filler, as per Base64 spec. stop before potential buffer overun on
* byteDest, remember that byteDest is 3/4 (integer division) the size
* of input and won't necessary divide exactly (ie iDestIdx must be <
* (integer div byteDest.length / 3)*3 see
* http://www.javaworld.com/javaworld/javatips/jw-javatip36-p2.html for
* example
*/
for (iSrcIdx = 0, iDestIdx = 0; iSrcIdx < reviSrcIdx
&& iDestIdx < ((byteDest.length / 3) * 3); iSrcIdx += 4) {
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx] << 2) & 0xFC | (byteTemp[iSrcIdx + 1] >>> 4) & 0x03);
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx + 1] << 4) & 0xF0 | (byteTemp[iSrcIdx + 2] >>> 2) & 0x0F);
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx + 2] << 6) & 0xC0 | byteTemp[iSrcIdx + 3] & 0x3F);
}
/*
* tidy up any remainders if iDestIdx >= ((byteDest.length / 3)*3) but
* iSrcIdx < reviSrcIdx then we have at most 2 extra destination bytes
* to fill and posiblr 3 input bytes yet to process
*/
if (iSrcIdx < reviSrcIdx) {
if (iSrcIdx < reviSrcIdx - 2) {
// "3 input bytes left"
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx] << 2) & 0xFC | (byteTemp[iSrcIdx + 1] >>> 4) & 0x03);
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx + 1] << 4) & 0xF0 | (byteTemp[iSrcIdx + 2] >>> 2) & 0x0F);
} else if (iSrcIdx < reviSrcIdx - 1) {
// "2 input bytes left"
byteDest[iDestIdx++] = (byte) ((byteTemp[iSrcIdx] << 2) & 0xFC | (byteTemp[iSrcIdx + 1] >>> 4) & 0x03);
}
/*
* wont have just one input byte left (unless input wasn't base64
* encoded ) due to the for loop steps and array sizes, after "="
* pad removed, but for compleatness
*/
else {
throw new IllegalArgumentException("Warning: 1 input bytes left to process. This was not Base64 input");
}
}
return byteDest;
}
}
工具类
package com.wanggs.utils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.SortedMap;
/**
* CryptoUtils
* @author wangs
* @version 1.0
* @since 2017年8月18日下午3:04:26
*/
public class CryptoUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(CryptoUtils.class);
private static SecretKey KEY;
private static IvParameterSpec IV;
private static byte[] aesKey;
/**
* DES加密文本密钥配置
*/
public static final String DES_KEY_CONF = "encrypt.des.key";
/**
* 系统默认字符集编码utf-8
*/
public static final String DEFAULT_CHARSET = "utf-8";
/**
* DES加密初始化向量配置
*/
public static final String DES_IV_CONF = "encrypt.des.iv";
/**
* MD5加密文本密钥配置
*/
public static final String MD5_KEY_CONF = "encrypt.md5.key";
static{
try {
int keyLength = 8;
String desKey = DES_KEY_CONF;
if(desKey.length() > keyLength){
desKey = desKey.substring(0, keyLength);
}
byte[] rgbKey = desKey.getBytes(DEFAULT_CHARSET);
String desIv = DES_IV_CONF;
if(desIv.length() > keyLength){
desIv = desIv.substring(0, keyLength);
}
byte[] rgbIV = desIv.getBytes(DEFAULT_CHARSET);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
DESKeySpec desKeySpec = new DESKeySpec(rgbKey);
KEY = keyFactory.generateSecret(desKeySpec);
IV = new IvParameterSpec(rgbIV);
} catch (Exception e) {
LOGGER.error("encrypt key and iv init error.", e);
}
}
/**
* 对明文进行加密
* @param text 需要加密的明文
* @return加密后base64编码的字符串
* @throwsDEC加密失败
*/
public static String encrypt(String text) throws UnsupportedEncodingException {
if(StringUtils.isBlank(text))
return null;
if(KEY == null || IV == null)
return null;
byte[] byteArray = null;
try {
byte[] strByteArray = text.getBytes(DEFAULT_CHARSET);
// 设置加密模式为DES的CBC模式
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, KEY, IV);
// 加密 使用BASE64对加密后的字符串进行编码
byteArray = cipher.doFinal(strByteArray);
//SecretKeySpec keySpec = new SecretKeySpec(aesKey, "DES");
//IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
//cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
} catch (Exception e) {
LOGGER.error("encrypt error.", e);
}
return Base64.encode(byteArray);
}
/**
* 对密文进行解密.
* @paramtext需要解密的密文
* @return解密得到的明文
*/
public static String decrypt(String text) {
if(StringUtils.isBlank(text))
return null;
if(KEY == null || IV == null)
return null;
byte[] byteArray;
String result = null;
try {
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, KEY, IV);
//SecretKeySpec key_spec = new SecretKeySpec(aesKey, "DES");
//IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
//cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// 使用BASE64对密文进行解码
byteArray = cipher.doFinal(Base64.decode(text));
// 解密
result = new String(byteArray, DEFAULT_CHARSET);
} catch (Exception e) {
LOGGER.error("decrypt error.", e);
}
return result;
}
/**
* 参数DM5加密并Base64转码加密
* @param str
* @return
*/
public static String md5AndBase64(String str) throws UnsupportedEncodingException {
return Base64.encode(md5Encrypt(str));
}
/**
* 参数DM5签名字节码
* @param encryptStr
* @return
*/
private static byte[] md5Encrypt(String encryptStr) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(encryptStr.getBytes("utf8"));
return md5.digest();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getSignature(SortedMap<String, String> map) throws UnsupportedEncodingException {
if(map != null && map.size() > 0){
StringBuilder builder = new StringBuilder();
for(Entry<String, String> entry : map.entrySet()){
if(!entry.getKey().equals("sign")){
builder.append(entry.getKey()+"="+entry.getValue());
builder.append("&");
}
}
builder.append("key="+MD5_KEY_CONF);
String result = md5AndBase64(builder.toString());
LOGGER.debug("data md5AndBase64 result:{}", result);
return result;
}
return null;
}
}
测试
package com.wanggs.utils;
/**
* Created by wanggs on 2017/9/6.
*/
public class Test {
public static void main(String[] args) {
try {
System.out.println(CryptoUtils.encrypt("{ID:213456498,NAME:\"张三\"}"));
System.out.println(CryptoUtils.decrypt("ODVAmNv8f2rAcBTLv/nEDrE0hUp3U52cfVISaHy4VjI="));
/**
* 输出
* ODVAmNv8f2rAcBTLv/nEDrE0hUp3U52cfVISaHy4VjI=
{ID:213456498,NAME:"张三"}
*/
} catch (Exception e) {
e.printStackTrace();
}
}
}