ase 加密

昨天遇到一個加密的東西项钮,解決問題的過程異常艱辛
要求是
AES256-CBC-PKCS7Padding加密 base64輸出
代碼老大之前有給過我一份棒厘,讓我參考一下檩互。
毫無疑問的粹胯,我拿來就跑demo蓖柔,當(dāng)時是在android studio上跑,毫無疑問失敗了风纠,jdk的版本用的是開源的况鸣,不是oracle的。demo也沒有好好看
當(dāng)時電腦有點卡竹观,鍵盤好像也有點問題镐捧,拷貝東西的時候不多按幾下c鍵,東西可能拷貝不下來臭增。

遇到的第一個問題是 java.security.InvalidKeyException:illegal Key Size
解決方案:我換了個jdk懂酱,然后下載了local_policy.jar和US_export_policy.jar覆蓋本地的包

遇到的第二個問題是生成的密文不對,解不出來速址。然后懷疑給的代碼有問題玩焰,網(wǎng)上找各種版本。Google芍锚,stackoverflow昔园。他們建議是把PKCS7Padding換成PKCS5Padding蔓榄。這個和需求有悖。那就只能找別人實現(xiàn)了的默刚,這個相當(dāng)耗時甥郑,時間久了,感覺不對就去老大那里看他那加解密是怎么做的荤西。他那邊的做法和我一樣只是不同的語言實現(xiàn)的澜搅。這時候我回到原來的代碼上,一陣狂改邪锌,感覺沒用的全都注釋勉躺。老大看過看我的代碼,發(fā)現(xiàn)上面的key觅丰,和iv是一樣的饵溅,我當(dāng)時就懵逼了

最后一個問題:不多說,自己犯傻

深深鄙視貼代碼貼一半的人

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
//這個類可以自己寫妇萄,base64網(wǎng)上一大堆 本文用的是apache的 commons-codec
import org.apache.commons.codec.binary.Base64;

/**

 * 說明:異常java.security.InvalidKeyException:illegal Key Size的解決方案
 * <ol>
 * <li>在官方網(wǎng)站下載JCE無限制權(quán)限策略文件(JDK7的下載地址:
 * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124
 * .html
 * jdk 8
 * http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
 * </li>
 * <li>下載后解壓蜕企,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
 * <li>如果安裝了JRE,將兩個jar文件放到%JRE_HOME%\lib\security目錄下覆蓋原來的文件</li>
 * <li>如果安裝了JDK冠句,將兩個jar文件放到%JDK_HOME%\jre\lib\security目錄下覆蓋原來文件</li>
 * </ol>
 */
public class ASE {
    static Charset CHARSET = Charset.forName("utf-8");
    Base64 base64 = new Base64();
    byte[] aesKey = "1q2w3e4rfdsaffdsa343234d".getBytes();
    byte[] iv = "0316030405060709".getBytes();
    static int BLOCK_SIZE = 32;

    // 生成4個字節(jié)的網(wǎng)絡(luò)字節(jié)序
    byte[] getNetworkBytesOrder(int sourceNumber) {
        byte[] orderBytes = new byte[4];
        orderBytes[3] = (byte) (sourceNumber & 0xFF);
        orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
        orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
        orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
        return orderBytes;
    }

    // 還原4個字節(jié)的網(wǎng)絡(luò)字節(jié)序
    int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

    // 隨機(jī)生成16位字符串
    String getRandomStr() {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 16; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 對明文進(jìn)行加密.
     * 
     * @param text
     *            需要加密的明文
     * @return 加密后base64編碼的字符串
     * @throws AesException
     *             aes加密失敗
     */
    String encrypt(String text) throws AesException {
        ByteGroup byteCollector = new ByteGroup();
        byte[] randomStrBytes = getRandomStr().getBytes(CHARSET);
        byte[] textBytes = text.getBytes(CHARSET);
        byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);

        // randomStr + networkBytesOrder + text
        byteCollector.addBytes(randomStrBytes);
        byteCollector.addBytes(networkBytesOrder);
        byteCollector.addBytes(textBytes);

        // ... + pad: 使用自定義的填充方式對明文進(jìn)行補(bǔ)位填充
        byte[] padBytes = encode(byteCollector.size());
        byteCollector.addBytes(padBytes);

        // 獲得最終的字節(jié)流, 未加密
        byte[] unencrypted = byteCollector.toBytes();

        try {
            // 設(shè)置加密模式為AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec ivs = new IvParameterSpec(iv, 0, 16);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivs);

            // 加密
            byte[] encrypted = cipher.doFinal(unencrypted);

            // 使用BASE64對加密后的字符串進(jìn)行編碼
            String base64Encrypted = base64.encodeToString(encrypted);

            return base64Encrypted;
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.EncryptAESError);
        }
    }

    /**
     * 對密文進(jìn)行解密.
     * 
     * @param text
     *            需要解密的密文
     * @return 解密得到的明文
     * @throws AesException
     *             aes解密失敗
     */
    String decrypt(String text) throws AesException {
        byte[] original;
        try {
            // 設(shè)置解密模式為AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec ivs = new IvParameterSpec(Arrays.copyOfRange(iv, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, ivs);

            // 使用BASE64對密文進(jìn)行解碼
            byte[] encrypted = Base64.decodeBase64(text);

            // 解密
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.DecryptAESError);
        }

        String xmlContent;
        try {
            // 去除補(bǔ)位字符
            byte[] bytes = decode(original);

            // 分離16位隨機(jī)字符串,網(wǎng)絡(luò)字節(jié)序和AppId
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

            int xmlLength = recoverNetworkBytesOrder(networkOrder);

            xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.IllegalBuffer);
        }

        return xmlContent;

    }

    /**
     * 獲得對明文進(jìn)行補(bǔ)位填充的字節(jié).
     * 
     * @param count
     *            需要進(jìn)行填充補(bǔ)位操作的明文字節(jié)個數(shù)
     * @return 補(bǔ)齊用的字節(jié)數(shù)組
     */
    static byte[] encode(int count) {
        // 計算需要填充的位數(shù)
        int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
        if (amountToPad == 0) {
            amountToPad = BLOCK_SIZE;
        }
        // 獲得補(bǔ)位所用的字符
        char padChr = chr(amountToPad);
        String tmp = new String();
        for (int index = 0; index < amountToPad; index++) {
            tmp += padChr;
        }
        return tmp.getBytes(CHARSET);
    }

    /**
     * 刪除解密后明文的補(bǔ)位字符
     * 
     * @param decrypted
     *            解密后的明文
     * @return 刪除補(bǔ)位字符后的明文
     */
    static byte[] decode(byte[] decrypted) {
        int pad = (int) decrypted[decrypted.length - 1];
        if (pad < 1 || pad > 32) {
            pad = 0;
        }
        return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
    }

    /**
     * 將數(shù)字轉(zhuǎn)化成ASCII碼對應(yīng)的字符轻掩,用于對明文進(jìn)行補(bǔ)碼
     * 
     * @param a
     *            需要轉(zhuǎn)化的數(shù)字
     * @return 轉(zhuǎn)化得到的字符
     */
    static char chr(int a) {
        byte target = (byte) (a & 0xFF);
        return (char) target;
    }

    class ByteGroup {
        ArrayList<Byte> byteContainer = new ArrayList<Byte>();

        public byte[] toBytes() {
            byte[] bytes = new byte[byteContainer.size()];
            for (int i = 0; i < byteContainer.size(); i++) {
                bytes[i] = byteContainer.get(i);
            }
            return bytes;
        }

        public ByteGroup addBytes(byte[] bytes) {
            for (byte b : bytes) {
                byteContainer.add(b);
            }
            return this;
        }

        public int size() {
            return byteContainer.size();
        }
    }
    
    /***
     * 抄代碼注意頂部的提示
     * key和iv別拷貝的時候仔細(xì)點,別搞錯了
     * 
     * @param args
     */
    public static void main(String[] args) {
        String str = "11111";
        ASE ase = new ASE();
        String aseword = null;
        try {
            aseword = ase.encrypt(str);
            System.out.println(aseword);
            
            String decryptString =  ase.decrypt(aseword);
            
            System.out.println(decryptString);
        } catch (AesException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
}

exception類


public class AesException extends Exception {

    private static final long serialVersionUID = 1L;
    public final static int OK = 0;
    
    public final static int EncryptAESError = -40006;
    public final static int DecryptAESError = -40007;
    public final static int IllegalBuffer = -40008;

    private int code;

    private static String getMessage(int code) {
        switch (code) {
        case EncryptAESError:
            return "aes加密失敗";
        case DecryptAESError:
            return "aes解密失敗";
        case IllegalBuffer:
            return "解密后得到的buffer非法";
        default:
            return null; // cannot be
        }
    }

    public int getCode() {
        return code;
    }

    AesException(int code) {
        super(getMessage(code));
        this.code = code;
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懦底,一起剝皮案震驚了整個濱河市唇牧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聚唐,老刑警劉巖奋构,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拱层,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宴咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門根灯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掺栅,你說我怎么就攤上這事烙肺。” “怎么了氧卧?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵桃笙,是天一觀的道長。 經(jīng)常有香客問我沙绝,道長搏明,這世上最難降的妖魔是什么鼠锈? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮星著,結(jié)果婚禮上购笆,老公的妹妹穿的比我還像新娘。我一直安慰自己虚循,他們只是感情好同欠,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著横缔,像睡著了一般铺遂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茎刚,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天襟锐,我揣著相機(jī)與錄音,去河邊找鬼斗蒋。 笑死捌斧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泉沾。 我是一名探鬼主播捞蚂,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跷究!你這毒婦竟也來了姓迅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤俊马,失蹤者是張志新(化名)和其女友劉穎丁存,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柴我,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡解寝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了艘儒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聋伦。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖界睁,靈堂內(nèi)的尸體忽然破棺而出觉增,到底是詐尸還是另有隱情,我是刑警寧澤翻斟,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布逾礁,位于F島的核電站,受9級特大地震影響访惜,放射性物質(zhì)發(fā)生泄漏嘹履。R本人自食惡果不足惜腻扇,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望植捎。 院中可真熱鬧衙解,春花似錦、人聲如沸焰枢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽济锄。三九已至暑椰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荐绝,已是汗流浹背一汽。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留低滩,地道東北人召夹。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像恕沫,于是被迫代替她去往敵國和親监憎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355