Java 加解密技術(shù)系列之 DES

Base64加密---加密學(xué)習(xí)筆記(一)

代碼實現(xiàn)

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";
    /**
     * 系統(tǒng)默認(rèn)字符集編碼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);
        }
    }

    /**
     * 對明文進(jìn)行加密
     * @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);
            // 設(shè)置加密模式為DES的CBC模式
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, KEY, IV);

            // 加密 使用BASE64對加密后的字符串進(jìn)行編碼
            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);
    }

    /**
     * 對密文進(jìn)行解密.
     * @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對密文進(jìn)行解碼
            byteArray = cipher.doFinal(Base64.decode(text));
            // 解密
            result = new String(byteArray, DEFAULT_CHARSET);
        } catch (Exception e) {
            LOGGER.error("decrypt error.", e);
        }
        return result;
    }

    /**
     * 參數(shù)DM5加密并Base64轉(zhuǎn)碼加密
     * @param str
     * @return
     */
    public static String md5AndBase64(String str) throws UnsupportedEncodingException {
        return Base64.encode(md5Encrypt(str));
    }

    /**
     * 參數(shù)DM5簽名字節(jié)碼
     * @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();
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哎媚,一起剝皮案震驚了整個濱河市证薇,隨后出現(xiàn)的幾起案子臀稚,更是在濱河造成了極大的恐慌图筹,老刑警劉巖裸扶,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疾嗅,死亡現(xiàn)場離奇詭異优床,居然都是意外死亡蛤售,警方通過查閱死者的電腦和手機(jī)疼邀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門喂江,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旁振,你說我怎么就攤上這事获询。” “怎么了拐袜?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵吉嚣,是天一觀的道長。 經(jīng)常有香客問我蹬铺,道長尝哆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任甜攀,我火速辦了婚禮秋泄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘规阀。我一直安慰自己恒序,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布谁撼。 她就那樣靜靜地躺著歧胁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上与帆,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天了赌,我揣著相機(jī)與錄音,去河邊找鬼玄糟。 笑死勿她,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阵翎。 我是一名探鬼主播逢并,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼郭卫!你這毒婦竟也來了砍聊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贰军,失蹤者是張志新(化名)和其女友劉穎玻蝌,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體词疼,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡俯树,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贰盗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片许饿。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖舵盈,靈堂內(nèi)的尸體忽然破棺而出陋率,到底是詐尸還是另有隱情,我是刑警寧澤秽晚,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布瓦糟,位于F島的核電站,受9級特大地震影響爆惧,放射性物質(zhì)發(fā)生泄漏狸页。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一扯再、第九天 我趴在偏房一處隱蔽的房頂上張望芍耘。 院中可真熱鬧,春花似錦熄阻、人聲如沸斋竞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坝初。三九已至浸剩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鳄袍,已是汗流浹背绢要。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留拗小,地道東北人重罪。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像哀九,于是被迫代替她去往敵國和親剿配。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,190評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理阅束,服務(wù)發(fā)現(xiàn)呼胚,斷路器,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • 一息裸、什么是HTML蝇更?HTML 是用來描述網(wǎng)頁的一種語言。1界牡、HTML指的是超文本編輯語言簿寂;2、HTML本身并不是一...
    忘惘的小風(fēng)扇閱讀 286評論 0 1
  • 喜歡陳末的敢愛宿亡,敢作,敢付出纳令,為了自己曾愛過的人頹廢過挽荠,孤獨過,后來才發(fā)現(xiàn)所愛之人其實就在自己身邊平绩,影片中最后兜兜...
    當(dāng)郭芙蓉想起佟湘玉閱讀 450評論 0 3
  • 大家早上好捏雌,歡迎來到咕咕姐早讀群跃赚,每天進(jìn)步一點點,堅持帶來大改變性湿,今天是2017年5月17日纬傲,星期三,我們已經(jīng)正式...
    咕咕姐閱讀 399評論 0 3