AES对称加解密, 相同key加密结果不一致,因为Linux的强随机数而导致,需要在 jvm 加如下启动参数
-Djava.security.egd=file:/dev/./urandom
如下测试类,在Linux javac Test.java 编译 ,运行 Java Test 每次加密结果不一致。
运行 java -Djava.security.egd=file:/dev/./urandom Test 则一致
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
//import org.apache.commons.lang3.StringUtils;
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException, RuntimeException {
// TODO Auto-generated method stub
String xx = "62222222222222222222";
System.out.println("xx:["+ xx +"]");
String en1 = AESUtil.encrypt(xx);
System.out.println("en1:["+ en1 +"]");
String en2 = AESUtil.encrypt(xx);
System.out.println("en2:["+ en2 +"]");
String en3 = AESUtil.encrypt(xx);
System.out.println("en3:["+ en3 +"]");
System.out.println(">>>");
String de1 = AESUtil.decrypt("CmrCvf3jdzPihcN75poIK+dereT2XxsbUe0LWvd7p3Q*");
System.out.println("de1:["+ de1 +"]");
/* String de2 = AESUtil.decrypt(en2);
System.out.println("de2:["+ de2 +"]");
String de3 = AESUtil.decrypt(en3);
System.out.println("de2:["+ de3 +"]");*/
}
static class AESUtil extends AESEncrypter {
public AESUtil(String aesKey) throws RuntimeException {
super(aesKey);
}
// 因为美国对软件出口的控制,默认只支持128位;要使用256则需另下bcprov-jdk的jar包替换jre\lib\security下的jar
private static final int KEY_SIZE = 128;
private static final String aesKey = "8979d58a2a51e140a2088fb505218ce1";
/**
* @title encrypt
* @description 加密
* @author yy
* @date 2017年5月2日 上午11:17:35
* @param text
* @return
* @throws RuntimeException
* @return String
*/
public static String encrypt(String text) throws RuntimeException {
if (StringUtils.isBlank(text))
return null;
return getInstance(aesKey).encode(text.getBytes());
}
/**
* @title decrypt
* @description 解密
* @author yy
* @date 2017年5月2日 上午11:17:38
* @param encryptText
* @return
* @throws RuntimeException
* @return String
*/
public static String decrypt(String encryptText) throws RuntimeException {
if (StringUtils.isBlank(encryptText))
return null;
return new String(getInstance(aesKey).decode(encryptText));
}
@Override
public Key generateKey() throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(aesKey.getBytes());
kgen.init(KEY_SIZE,sr );
return kgen.generateKey();
}
public static void main(String[] args) {
System.out.println();
}
}
static class StringUtils {
public static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
return false;
}
}
return true;
}
public static String getLMTString(Object src, int limit, String supplement) {
return getLMTString(src, limit, true, true, supplement);
}
public static String getLMTString(Object src, int limit, boolean frontBegin, boolean isBack,
String supplement) {
if (src == null)
return null;
String target = src.toString();
int diffValue = target.length() - limit;
if (diffValue == 0)
return target;
else if (diffValue > 0)
return frontBegin ? target.substring(0, limit) : target.substring(diffValue, target.length());
supplement = supplement == null ? "" : supplement;
if (supplement.equals(""))
return target;
if (isBack) {
do {
target += supplement;
} while (target.length() < limit);
} else {
do {
target = supplement + target;
} while (target.length() < limit);
}
return target.length() == limit ? target : target.substring(0, limit);
}
}
public enum Charset {
/**
* ASCII(American Standard Code for Information
* Interchange,美国信息互换标准代码)<br/>
* 是基于罗马字母表的一套电脑编码系统,它主要用于显示现代英语和其他西欧语言<br/>
* 它是现今最通用的单字节编码系统,并等同于国际标准ISO 646
*/
ASCII("ascii"),
/**
* 通常叫做Latin-1,和ASCII编码相似<br/>
* 属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列
*/
ISO8859_1("iso8859-1"),
/**
* GB2312又称为GB2312-80字符集,全称为<信息交换用汉字编码字符集·基本集>,由原中国国家标准总局发布,1981年5月1日实施,
* 是中国国家标准的简体中文字符集。它所收录的汉字已经覆盖99.75%的使用频率,基本满足了汉字的计算机处理需要。在中国大陆和新加坡获广泛使用
* <br/>
* GB2312收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共 7445
* 个图形字符。其中包括6763个汉字,其中一级汉字3755个,二级汉字3008个;包括拉丁字母、希腊字母、日文平假名及片假名字母、
* 俄语西里尔字母在内的682个全角字符。
*/
GB2312("gb2312"),
/**
* GBK字符集是GB2312的扩展(K)<br/>
* GBK1.0收录了21886个符号,它分为汉字区和图形符号区,汉字区包括21003个字符。GBK字符集主要扩展了繁体中文字的支持
*/
GBK("gbk"),
/**
* GB18030的全称是GB18030-2000<信息交换用汉字编码字符集基本集的扩充>,是我国政府于2000年3月17日发布的新的汉字编码国家标准
* ,2001年8月31日后在中国市场上发布的软件必须符合本标准<br/>
* GB 18030字符集标准的出台经过广泛参与和论证,来自国内外知名信息技术行业的公司,信息产业部和原国家质量技术监督局联合实施<br/>
* GB
* 18030字符集标准解决汉字、日文假名、朝鲜语和中国少数民族文字组成的大字符集计算机编码问题。该标准的字符总编码空间超过150万个编码位,
* 收录了27484个汉字,覆盖中文、日文、朝鲜语和中国少数民族文字。
* 满足中国大陆、香港、台湾、日本和韩国等东亚地区信息交换多文种、大字量、多用途、统一编码格式的要求
* 并且与UNICODE3.0版本兼容,填补UNICODE扩展字符字汇“统一汉字扩展A”的内容。并且与以前的国家字符编码标准(GB2312,
* GB13000.1)兼容
*/
GB18030("gb18030"),
/**
* BIG5又称大五码或五大码<br/>
* 1984年由台湾财团法人信息工业策进会和五间软件公司宏碁 (Acer)、神通 (MiTAC)、佳佳、零壹 (Zero
* One)、大众(FIC)创立,故称大五码<br/>
* Big5码的产生,是因为当时台湾不同厂商各自推出不同的编码,如倚天码、IBM
* PS55、王安码等,彼此不能兼容;另一方面,台湾政府当时尚未推出官方的汉字编码,而中国大陆的GB2312编码亦未有收录繁体中文字<br/>
* Big5字符集共收录13,053个中文字,该字符集在中国台湾使用
*/
BIG5("big5"),
/**
* 这是最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也有四字节的)编码,包括英文字母在内。所以可以说它是不兼容iso8859-1编码的
* ,也不兼容任何编码<br/>
* 不过,相对于iso8859-1编码来说,UNICODE编码只是在前面增加了一个0字节,比如字母a为"00 61"<br/>
* 需要说明的是,定长编码便于计算机处理(注意GB2312/GBK不是定长编码),而UNICODE又可以用来表示所有字符,
* 所以在很多软件内部是使用UNICODE编码来处理的,比如java
*/
UNICODE("unicode"),
/**
* UTF-8是UNICODE的其中一个使用方式<br/>
* UTF-8便于不同的计算机之间使用网络传输不同语言和编码的文字,使得双字节的UNICODE能够在现存的处理单字节的系统上正确传输<br/>
* UTF-8使用可变长度字节来储存UNICODE字符,例如ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,
* 而常用的汉字就要使用3字节。辅助平面字符则使用4字节
*/
UTF8("utf-8"),
/** UTF-16 使用一个或两个未分配的 16 位代码单元的序列对 UNICODE 代码点进行编码 */
UTF16("utf-16"),
/** UTF-32 即将每一个 UNICODE 代码点表示为相同值的 32 位整数 */
UTF32("utf-32");
public final String VALUE;
private Charset(String VALUE) {
this.VALUE = VALUE;
}
}
/**
* AES对称加解密
*
* @author fuli
* @version 1.0
* @date 2016-12-09 18:03
* @description 加密数据默认转换为Base64编码
*/
static class AESEncrypter {
// 因为美国对软件出口的控制,默认只支持128位;要使用256则需另下bcprov-jdk的jar包替换jre\lib\security下的jar
private static final int KEY_SIZE = 128;
protected static final String KEY_ALGORITHM = "AES";
private static Map<String, AESEncrypter> encryptMap = new HashMap<String, AESEncrypter>();
private int keySize = KEY_SIZE;
private String workPattern = "ECB";
private String paddingPattern = "PKCS5Padding";
private Cipher enCipher = null;
private Cipher deCipher = null;
private B64Encrypter b64Encrypter = null;
protected String aesKey;
public AESEncrypter(String aesKey) throws RuntimeException {
init(aesKey, B64Encrypter.DEFAULT_ALPHABET, workPattern, paddingPattern, aesKey);
}
public AESEncrypter(String aesKey, boolean useHex) throws RuntimeException {
init(aesKey, useHex ? null : B64Encrypter.DEFAULT_ALPHABET, workPattern, paddingPattern, aesKey);
}
public AESEncrypter(String aesKey, String b64Key) throws RuntimeException {
init(aesKey, b64Key, workPattern, paddingPattern, aesKey);
}
public AESEncrypter(String aesKey, String workPattern, String paddingPattern) throws RuntimeException {
init(aesKey, null, workPattern, paddingPattern, aesKey);
}
public AESEncrypter(String aesKey, String b64Key, String workPattern, String paddingPattern, String ivParameter)
throws RuntimeException {
init(aesKey, b64Key, workPattern, paddingPattern, ivParameter);
}
private void init(String aesKey, String b64Key, String workPattern, String paddingPattern, String ivParameter) {
this.aesKey = aesKey;
try {
Key key = generateKey();
StringBuilder pattern = new StringBuilder(KEY_ALGORITHM);
pattern.append("/").append(workPattern);
pattern.append("/").append(paddingPattern);
enCipher = Cipher.getInstance(pattern.toString());
deCipher = Cipher.getInstance(pattern.toString());
// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
if (workPattern.equals("CBC")) {
ivParameter = StringUtils.getLMTString(ivParameter, 16, "x");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes("UTF-8"));
enCipher.init(Cipher.ENCRYPT_MODE, key, iv);
deCipher.init(Cipher.DECRYPT_MODE, key, iv);
} else {
enCipher.init(Cipher.ENCRYPT_MODE, key);
deCipher.init(Cipher.DECRYPT_MODE, key);
}
if (!StringUtils.isBlank(b64Key))
b64Encrypter = B64Encrypter.getInstance(b64Key);
} catch (Exception e) {
throw new RuntimeException("Error initializing AESEncrypter class. Cause: " + e);
}
}
// 覆盖此方法以改变Key的生成方式
public Key generateKey() throws Exception {
if (keySize != 128 && keySize != 192 && keySize != 256) {
throw new RuntimeException(
"Error initializing AESEncrypter class. Cause: Unsupported keySize " + keySize);
}
KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
kgen.init(keySize, new SecureRandom(aesKey.getBytes()));
return kgen.generateKey();
// OR SecretKeySpec key = new SecretKeySpec(aesKey.getBytes(),
// KEY_ALGORITHM);
}
public String encode(byte[] data) throws RuntimeException {
try {
byte[] b = enCipher.doFinal(data);
return b64Encrypter == null ? Hex.bytes2Hex(b) : b64Encrypter.encode(b);
} catch (Exception e) {
throw new RuntimeException("AESEncrypter encode error. Cause: " + e);
}
}
public byte[] decode(String encryptText) throws RuntimeException {
try {
return deCipher
.doFinal(b64Encrypter == null ? Hex.hexToBytes(encryptText) : b64Encrypter.decode(encryptText));
} catch (Exception e) {
throw new RuntimeException("AESEncrypter decode error. Cause: " + e);
}
}
public void encodeFile(String file, String destFile) throws RuntimeException {
InputStream is = null;
OutputStream out = null;
CipherInputStream cis = null;
try {
is = new FileInputStream(file);
out = new FileOutputStream(destFile);
cis = new CipherInputStream(is, enCipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
} catch (Exception e) {
throw new RuntimeException("AESEncrypt encodeFile error. Cause: " + e);
} finally {
StreamUtils.close(out, is, cis);
}
}
//
// public void encodeFileAsyn(String file, String destFile) throws
// RuntimeException, FileNotFoundException {
// InputStream is = new FileInputStream(file);
// CipherInputStream cis = new CipherInputStream(is, enCipher);
// OutputStream out = new FileOutputStream(destFile);
// Observable<byte[]> writer = Observable.create((subscriber) -> {
// byte[] buffer = new byte[1024];
// int r;
// try {
// while ((r = cis.read(buffer)) > 0) {
// subscriber.onNext(Arrays.copyOfRange(buffer, 0, r));
// }
// } catch (IOException ioe) {
// throw new RuntimeException("AESEncrypt encodeFileAsyn error. Cause: "
// + ioe);
// }
// subscriber.onComplete();
// });
// writer.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe((data)
// -> {
// try {
// out.write(data);
// } catch (IOException ioe) {
// throw new RuntimeException("AESEncrypt encodeFileAsyn error. Cause: "
// + ioe);
// }
// }, (e) -> {
// StreamUtils.close(out, is, cis);
// throw new RuntimeException("AESEncrypt encodeFileAsyn error. Cause: "
// + e);
// }, () -> {
// StreamUtils.close(out, is, cis);
// });
// }
public void decodeFile(String file, String destFile) throws RuntimeException {
InputStream is = null;
OutputStream out = null;
CipherOutputStream cos = null;
try {
is = new FileInputStream(file);
out = new FileOutputStream(destFile);
cos = new CipherOutputStream(out, deCipher);
byte[] buffer = new byte[1024];
int r;
while ((r = is.read(buffer)) >= 0) {
cos.write(buffer, 0, r);
}
} catch (Exception e) {
throw new RuntimeException("AESEncrypt decodeFile error. Cause: " + e);
} finally {
StreamUtils.close(is, out, cos);
}
}
//
// public void decodeFileAsyn(String file, String destFile) throws
// RuntimeException, FileNotFoundException {
// InputStream is = new FileInputStream(file);
// OutputStream out = new FileOutputStream(destFile);
// CipherOutputStream cos = new CipherOutputStream(out, deCipher);
// Observable<byte[]> writer = Observable.create((subscriber) -> {
// byte[] buffer = new byte[1024];
// int r;
// try {
// while ((r = is.read(buffer)) > 0) {
// subscriber.onNext(Arrays.copyOfRange(buffer, 0, r));
// }
// } catch (IOException ioe) {
// throw new RuntimeException("AESEncrypt decodeFileAsyn error. Cause: "
// + ioe);
// }
// subscriber.onComplete();
// });
// writer.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).subscribe((data)
// -> {
// try {
// out.write(data);
// } catch (IOException ioe) {
// throw new RuntimeException("AESEncrypt decodeFileAsyn error. Cause: "
// + ioe);
// }
// }, (e) -> {
// StreamUtils.close(is, out, cos);
// throw new RuntimeException("AESEncrypt decodeFileAsyn error. Cause: "
// + e);
// }, () -> {
// StreamUtils.close(is, out, cos);
// });
// }
/********************* static method ************************/
public static AESEncrypter getInstance(String aesKey) {
return getInstance(aesKey, B64Encrypter.DEFAULT_ALPHABET);
}
public static AESEncrypter getInstance(String aesKey, boolean useHex) {
if (StringUtils.isBlank(aesKey)) {
return null;
}
String key = aesKey;
AESEncrypter aesEncrypt = encryptMap.get(key);
if (aesEncrypt == null) {
aesEncrypt = new AESEncrypter(aesKey, useHex);
encryptMap.put(key, aesEncrypt);
}
return aesEncrypt;
}
public static AESEncrypter getInstance(String aesKey, String b64Key) {
if (StringUtils.isBlank(aesKey) || !B64Encrypter.checkAlphabet(b64Key)) {
return null;
}
String key = aesKey + b64Key;
System.out.println("key:"+key);
AESEncrypter aesEncrypt = encryptMap.get(key);
if (aesEncrypt == null) {
aesEncrypt = new AESEncrypter(aesKey, b64Key);
encryptMap.put(key, aesEncrypt);
}
return aesEncrypt;
}
public static AESEncrypter newInstance(String aesKey) {
return newInstance(aesKey, B64Encrypter.DEFAULT_ALPHABET);
}
public static AESEncrypter newInstance(String aesKey, boolean useHex) {
if (StringUtils.isBlank(aesKey)) {
return null;
}
return new AESEncrypter(aesKey, useHex);
}
public static AESEncrypter newInstance(String aesKey, String b64Key) {
if (StringUtils.isBlank(aesKey) || !B64Encrypter.checkAlphabet(b64Key)) {
return null;
}
return new AESEncrypter(aesKey, b64Key);
}
public static String encrypt(String aesKey, byte[] data) throws RuntimeException {
if (StringUtils.isBlank(aesKey) || data == null)
return null;
return getInstance(aesKey).encode(data);
}
public static String encrypt(String aesKey, String b64Key, byte[] data) throws RuntimeException {
if (StringUtils.isBlank(aesKey) || !B64Encrypter.checkAlphabet(b64Key) || data == null)
return null;
return getInstance(aesKey, b64Key).encode(data);
}
public static byte[] decrypt(String aesKey, String encryptText) throws RuntimeException {
if (StringUtils.isBlank(aesKey) || StringUtils.isBlank(encryptText))
return null;
return getInstance(aesKey).decode(encryptText);
}
public static byte[] decrypt(String aesKey, String b64Key, String encryptText) throws RuntimeException {
if (StringUtils.isBlank(aesKey) || StringUtils.isBlank(encryptText) || !B64Encrypter.checkAlphabet(b64Key))
return null;
return getInstance(aesKey, b64Key).decode(encryptText);
}
/*************** File encode **************/
public static void encryptFile(String aesKey, String file, String destFile) throws RuntimeException {
if (!StringUtils.isBlank(aesKey)) {
getInstance(aesKey).encodeFile(file, destFile);
}
}
public static void encryptFile(String aesKey, String b64Key, String file, String destFile)
throws RuntimeException {
if (!StringUtils.isBlank(aesKey) && B64Encrypter.checkAlphabet(b64Key)) {
getInstance(aesKey, b64Key).encodeFile(file, destFile);
}
}
// public static void encryptFileAsyn(String aesKey, String file, String
// destFile)
// throws RuntimeException, FileNotFoundException {
// if (!StringUtils.isBlank(aesKey)) {
// getInstance(aesKey).encodeFileAsyn(file, destFile);
// }
// }
// public static void encryptFileAsyn(String aesKey, String b64Key,
// String file, String destFile)
// throws RuntimeException, FileNotFoundException {
// if (!StringUtils.isBlank(aesKey) &&
// B64Encrypter.checkAlphabet(b64Key)) {
// getInstance(aesKey, b64Key).encodeFileAsyn(file, destFile);
// }
// }
/*************** File decode **************/
public static void decryptFile(String aesKey, String file, String destFile) throws RuntimeException {
if (!StringUtils.isBlank(aesKey)) {
getInstance(aesKey).decodeFile(file, destFile);
}
}
public static void decryptFile(String aesKey, String b64Key, String file, String destFile)
throws RuntimeException {
if (!StringUtils.isBlank(aesKey) && B64Encrypter.checkAlphabet(b64Key)) {
getInstance(aesKey, b64Key).decodeFile(file, destFile);
}
}
// public static void decryptFileAsyn(String aesKey, String file, String
// destFile)
// throws RuntimeException, FileNotFoundException {
// if (!StringUtils.isBlank(aesKey)) {
// getInstance(aesKey).decodeFileAsyn(file, destFile);
// }
// }
//
// public static void decryptFileAsyn(String aesKey, String b64Key,
// String file, String destFile)
// throws RuntimeException, FileNotFoundException {
// if (!StringUtils.isBlank(aesKey) &&
// B64Encrypter.checkAlphabet(b64Key)) {
// getInstance(aesKey, b64Key).decodeFileAsyn(file, destFile);
// }
// }
}
static class Hex {
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
'd', 'e', 'f' };
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
'D', 'E', 'F' };
/**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data) {
return encodeHex(data, true);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @param toLowerCase
* <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data
* byte[]
* @param toDigits
* 用于控制输出的char[]
* @return 十六进制char[]
*/
protected static char[] encodeHex(byte[] data, char[] toDigits) {
int l = data.length;
char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data) {
return encodeHexStr(data, true);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @param toLowerCase
* <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public static String encodeHexStr(byte[] data, boolean toLowerCase) {
return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data
* byte[]
* @param toDigits
* 用于控制输出的char[]
* @return 十六进制String
*/
protected static String encodeHexStr(byte[] data, char[] toDigits) {
return new String(encodeHex(data, toDigits));
}
/**
* 将十六进制字符数组转换为字节数组
*
* @param data
* 十六进制char[]
* @return byte[]
* @throws RuntimeException
* 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
*/
public static byte[] decodeHex(char[] data) {
int len = data.length;
if ((len & 0x01) != 0) {
throw new RuntimeException("Odd number of characters.");
}
byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
/**
* 将十六进制字符转换成一个整数
*
* @param ch
* 十六进制char
* @param index
* 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException
* 当ch不是一个合法的十六进制字符时,抛出运行时异常
*/
private static int toDigit(char ch, int index) {
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index);
}
return digit;
}
public static String bytes2Hex(byte[] inbuf) {
int i;
String byteStr;
StringBuffer strBuf = new StringBuffer();
for (i = 0; i < inbuf.length; i++) {
byteStr = Integer.toHexString(inbuf[i] & 0x00ff);
if (byteStr.length() != 2) {
strBuf.append('0').append(byteStr);
} else {
strBuf.append(byteStr);
}
}
return new String(strBuf);
}
public static byte[] hexToBytes(String inbuf) {
int i;
int len = inbuf.length() / 2;
byte outbuf[] = new byte[len];
for (i = 0; i < len; i++) {
String tmpbuf = inbuf.substring(i * 2, i * 2 + 2);
outbuf[i] = (byte) Integer.parseInt(tmpbuf, 16);
}
return outbuf;
}
}
static class StreamUtils {
public static void close(InputStream inputStream) {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public static void close(InputStream... inputStreams) {
if (inputStreams != null && inputStreams.length > 0) {
for (InputStream is : inputStreams) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
}
public static void close(InputStream inputStream, OutputStream... outputStreams) {
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
}
if (outputStreams != null && outputStreams.length > 0) {
for (OutputStream os : outputStreams) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
}
}
public static void close(OutputStream outputStream) {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
}
}
}
public static void close(OutputStream... outputStreams) {
if (outputStreams != null && outputStreams.length > 0) {
for (OutputStream os : outputStreams) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
}
}
public static void close(OutputStream outputStream, InputStream... inputStreams) {
if (inputStreams != null && inputStreams.length > 0) {
for (InputStream is : inputStreams) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
try {
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
}
}
public static void close(InputStream inputStream, OutputStream outputStream) {
try {
if (inputStream != null)
inputStream.close();
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
}
}
public static void close(AutoCloseable... closeables) {
if (closeables != null && closeables.length > 0) {
for (AutoCloseable ac : closeables) {
if (ac != null) {
try {
ac.close();
} catch (Exception e) {
}
}
}
}
}
}
static class B64Encrypter {
static final String DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
private static Map<String, B64Encrypter> coderMap = new HashMap<String, B64Encrypter>();
private static char[] defaultEncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
private static byte[] defaultDecodeChars = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0,
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, -1, -1, -1,
-1, -1, -1, 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, -1, -1, -1, -1, -1 };
static {
coderMap.put(DEFAULT_ALPHABET, new B64Encrypter(defaultEncodeChars, defaultDecodeChars));
}
private char[] base64EncodeChars;
private byte[] base64DecodeChars;
private B64Encrypter(char[] base64EncodeChars, byte[] base64DecodeChars) {
this.base64EncodeChars = base64EncodeChars;
this.base64DecodeChars = base64DecodeChars;
}
public String encode(byte[] data) {
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len) {
b1 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("**");
break;
}
b2 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("*");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
public byte[] decode(String str) throws UnsupportedEncodingException {
StringBuffer sb = new StringBuffer();
byte[] data = str.getBytes(Charset.ASCII.VALUE);
int len = data.length;
int i = 0;
int b1, b2, b3, b4;
while (i < len) {
/* b1 */
do {
b1 = base64DecodeChars[data[i++]];
} while (i < len && b1 == -1);
if (b1 == -1)
break;
/* b2 */
do {
b2 = base64DecodeChars[data[i++]];
} while (i < len && b2 == -1);
if (b2 == -1)
break;
sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
/* b3 */
do {
b3 = data[i++];
if (b3 == 61)
return sb.toString().getBytes(Charset.ISO8859_1.VALUE);
b3 = base64DecodeChars[b3];
} while (i < len && b3 == -1);
if (b3 == -1)
break;
sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
/* b4 */
do {
b4 = data[i++];
if (b4 == 61)
return sb.toString().getBytes(Charset.ISO8859_1.VALUE);
b4 = base64DecodeChars[b4];
} while (i < len && b4 == -1);
if (b4 == -1)
break;
sb.append((char) (((b3 & 0x03) << 6) | b4));
}
return sb.toString().getBytes(Charset.ISO8859_1.VALUE);
}
public static boolean checkAlphabet(String alphabet) {
if (StringUtils.isBlank(alphabet) || alphabet.length() != 64)
return false;
byte[] temp = new byte[128];
for (int i = 0; i < 64; i++) {
if (temp[alphabet.charAt(i)] > 0) {
return false;
}
temp[alphabet.charAt(i)] = 1;
}
return true;
}
public static B64Encrypter getInstance() {
return getInstance(DEFAULT_ALPHABET);
}
public static B64Encrypter getInstance(String alphabet) {
if (!checkAlphabet(alphabet))
return null;
B64Encrypter coder = coderMap.get(alphabet);
if (coder == null) {
char[] encodeChar = new char[64];
byte[] decodeChar = new byte[128];
for (int i = 0; i < 64; i++) {
encodeChar[i] = alphabet.charAt(i);
decodeChar[encodeChar[i]] = Integer.valueOf(i).byteValue();
}
coder = new B64Encrypter(encodeChar, decodeChar);
coderMap.put(alphabet, coder);
}
return coder;
}
public static String encrypt(byte[] plainText) {
return plainText == null ? null : getInstance().encode(plainText);
}
public static byte[] decrypt(String ciphertext) throws UnsupportedEncodingException {
return StringUtils.isBlank(ciphertext) ? null : getInstance().decode(ciphertext);
}
}
}