AES LINUX加密结果不一致


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);
        }


    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值