Java 加解密技术系列之 DES

Base64加密---加密学习笔记(一)

代码实现

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,259评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,561评论 18 139
  • 一、什么是HTML?HTML 是用来描述网页的一种语言。1、HTML指的是超文本编辑语言;2、HTML本身并不是一...
    忘惘的小风扇阅读 282评论 0 1
  • 喜欢陈末的敢爱,敢作,敢付出,为了自己曾爱过的人颓废过,孤独过,后来才发现所爱之人其实就在自己身边,影片中最后兜兜...
    当郭芙蓉想起佟湘玉阅读 443评论 0 3
  • 大家早上好,欢迎来到咕咕姐早读群,每天进步一点点,坚持带来大改变,今天是2017年5月17日,星期三,我们已经正式...
    咕咕姐阅读 390评论 0 3