Android-AES加解密

Android-RSA 分段加密解密
Android-Openssl創(chuàng)建RSA公鑰和私鑰
Android-AES加解密
Android-DH 秘鑰交換

1. AES(Advanced Encryption Standard) 介紹

AES 是比利時密碼學(xué)家Joan Daemen和Vincent Rijmen所設(shè)計的一種加密算法,又稱為 Rijndael 加密法垦写。由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)經(jīng)過許多算法的篩選吕世,高級加密標(biāo)準(zhǔn)(Advanced Encryption Standard)在2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標(biāo)準(zhǔn)梯投,在全世界被廣泛使用命辖。

AES 是一種對稱加密算法,即使用秘鑰加密數(shù)據(jù)以后分蓖,要使用相同的秘鑰才能解密尔艇。AES 加密方式比 DES 加密更安全,但是速度比不上 DES么鹤,但在不同運行環(huán)境下能保持良好的性能终娃。
AES 共有 5 種加密模式:

  1. ECB(Electronic Code Book) 電子密碼本模式
  2. CBC(Cipher Block Chaining) 加密塊鏈模式
  3. CFB(Cipher FeedBack Mode) 加密反饋模式
  4. OFB(Output FeedBack) 輸出反饋模式
  5. CTR(Counter) 計數(shù)器模式(不常見)

其中 ECB、CBC蒸甜、CTR 為塊加密模式棠耕,CFB余佛、OFB 為流加密模式。
AES 五種加密模式: https://www.cnblogs.com/starwolf/p/3365834.html

2. AES 加解密

import android.util.Log;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
 * AES 對稱加密算法窍荧,加解密工具類
 */
public class AESEncrypt {

    private static final String TAG = AESEncrypt.class.getSimpleName() + " --> ";

    /**
     * 加密算法
     */
    private static final String KEY_ALGORITHM = "AES";
   
    /**
     * AES 的 密鑰長度辉巡,32 字節(jié),范圍:16 - 32 字節(jié)
     */
    public static final int SECRET_KEY_LENGTH = 32;

    /**
     * 字符編碼
     */
    private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;

    /**
     * 秘鑰長度不足 16 個字節(jié)時蕊退,默認(rèn)填充位數(shù)
     */
    private static final String DEFAULT_VALUE = "0";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
    
   /**
     * AES 加密
     *
     * @param data      待加密內(nèi)容
     * @param secretKey 加密密碼郊楣,長度:16 或 32 個字符
     * @return 返回Base64轉(zhuǎn)碼后的加密數(shù)據(jù)
     */
    public static String encrypt(String data, String secretKey) {
        try {
            //創(chuàng)建密碼器
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //初始化為加密密碼器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(secretKey));
            byte[] encryptByte = cipher.doFinal(data.getBytes(CHARSET_UTF8));
            // 將加密以后的數(shù)據(jù)進(jìn)行 Base64 編碼
            return base64Encode(encryptByte);
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * AES 解密
     *
     * @param base64Data 加密的密文 Base64 字符串
     * @param secretKey  解密的密鑰,長度:16 或 32 個字符
     */
    public static String decrypt(String base64Data, String secretKey) {
        try {
            byte[] data = base64Decode(base64Data);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //設(shè)置為解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(secretKey));
            //執(zhí)行解密操作
            byte[] result = cipher.doFinal(data);
            return new String(result, CHARSET_UTF8);
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * 使用密碼獲取 AES 秘鑰
     */
    public static SecretKeySpec getSecretKey(String secretKey) {
        secretKey = toMakeKey(secretKey, SECRET_KEY_LENGTH, DEFAULT_VALUE);
        return new SecretKeySpec(secretKey.getBytes(CHARSET_UTF8), KEY_ALGORITHM);
    }

    /**
     * 如果 AES 的密鑰小于 {@code length} 的長度瓤荔,就對秘鑰進(jìn)行補位净蚤,保證秘鑰安全。
     *
     * @param secretKey 密鑰 key
     * @param length    密鑰應(yīng)有的長度
     * @param text      默認(rèn)補的文本
     * @return 密鑰
     */
    private static String toMakeKey(String secretKey, int length, String text) {
        // 獲取密鑰長度
        int strLen = secretKey.length();
        // 判斷長度是否小于應(yīng)有的長度
        if (strLen < length) {
            // 補全位數(shù)
            StringBuilder builder = new StringBuilder();
            // 將key添加至builder中
            builder.append(secretKey);
            // 遍歷添加默認(rèn)文本
            for (int i = 0; i < length - strLen; i++) {
                builder.append(text);
            }
            // 賦值
            secretKey = builder.toString();
        }
        return secretKey;
    }

   /**
     * 將 Base64 字符串 解碼成 字節(jié)數(shù)組
     */
    public static byte[] base64Decode(String data) {
        return Base64.decode(data, Base64.NO_WRAP);
    }

   /**
     * 將 字節(jié)數(shù)組 轉(zhuǎn)換成 Base64 編碼
     */
    public static String base64Encode(byte[] data) {
        return Base64.encodeToString(data, Base64.NO_WRAP);
    }

    /**
     * 處理異常
     */
    private static void handleException(Exception e) {
        e.printStackTrace();
        Log.e(TAG, TAG + e);
    }
}

3. AES 加解密文件

    /**
     * 對文件進(jìn)行AES加密
     *
     * @param sourceFile 待加密文件
     * @param dir        加密后的文件存儲路徑
     * @param toFileName 加密后的文件名稱
     * @param secretKey  密鑰
     * @return 加密后的文件
     */
    public static File encryptFile(File sourceFile, String dir, String toFileName, String secretKey) {
        try {
            // 創(chuàng)建加密后的文件
            File encryptFile = new File(dir, toFileName);
            // 根據(jù)文件創(chuàng)建輸出流
            FileOutputStream outputStream = new FileOutputStream(encryptFile);
            // 初始化 Cipher
            Cipher cipher = initFileAESCipher(secretKey, Cipher.ENCRYPT_MODE);
            // 以加密流寫入文件
            CipherInputStream cipherInputStream = new CipherInputStream(
                    new FileInputStream(sourceFile), cipher);
            // 創(chuàng)建緩存字節(jié)數(shù)組
            byte[] buffer = new byte[1024 * 2];
            // 讀取
            int len;
            // 讀取加密并寫入文件
            while ((len = cipherInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }
            // 關(guān)閉加密輸入流
            cipherInputStream.close();
            closeStream(outputStream);
            return encryptFile;
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * AES解密文件
     *
     * @param sourceFile 源加密文件
     * @param dir        解密后的文件存儲路徑
     * @param toFileName 解密后的文件名稱
     * @param secretKey  密鑰
     */
    public static File decryptFile(File sourceFile, String dir, String toFileName, String secretKey) {
        try {
            // 創(chuàng)建解密文件
            File decryptFile = new File(dir, toFileName);
            // 初始化Cipher
            Cipher cipher = initFileAESCipher(secretKey, Cipher.DECRYPT_MODE);
            // 根據(jù)源文件創(chuàng)建輸入流
            FileInputStream inputStream = new FileInputStream(sourceFile);
            // 獲取解密輸出流
            CipherOutputStream cipherOutputStream = new CipherOutputStream(
                    new FileOutputStream(decryptFile), cipher);
            // 創(chuàng)建緩沖字節(jié)數(shù)組
            byte[] buffer = new byte[1024 * 2];
            int len;
            // 讀取解密并寫入
            while ((len = inputStream.read(buffer)) >= 0) {
                cipherOutputStream.write(buffer, 0, len);
                cipherOutputStream.flush();
            }
            // 關(guān)閉流
            cipherOutputStream.close();
            closeStream(inputStream);
            return decryptFile;
        } catch (IOException e) {
            handleException(e);
        }
        return null;
    }

    /**
     * 初始化 AES Cipher
     *
     * @param secretKey  密鑰
     * @param cipherMode 加密模式
     * @return 密鑰
     */
    private static Cipher initFileAESCipher(String secretKey, int cipherMode) {
        try {
            // 創(chuàng)建密鑰規(guī)格
            SecretKeySpec secretKeySpec = getSecretKey(secretKey);
            // 獲取密鑰
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            // 初始化
            cipher.init(cipherMode, secretKeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
            return cipher;
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    /**
     * 關(guān)閉流
     *
     * @param closeable 實現(xiàn)Closeable接口
     */
    private static void closeStream(Closeable closeable) {
        try {
            if (closeable != null) closeable.close();
        } catch (Exception e) {
            handleException(e);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末输硝,一起剝皮案震驚了整個濱河市今瀑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腔丧,老刑警劉巖放椰,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愉粤,居然都是意外死亡砾医,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門衣厘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來如蚜,“玉大人,你說我怎么就攤上這事影暴〈戆睿” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵型宙,是天一觀的道長撬呢。 經(jīng)常有香客問我,道長妆兑,這世上最難降的妖魔是什么魂拦? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮搁嗓,結(jié)果婚禮上芯勘,老公的妹妹穿的比我還像新娘。我一直安慰自己腺逛,他們只是感情好荷愕,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般安疗。 火紅的嫁衣襯著肌膚如雪抛杨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天茂契,我揣著相機(jī)與錄音蝶桶,去河邊找鬼。 笑死掉冶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脐雪。 我是一名探鬼主播厌小,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼战秋!你這毒婦竟也來了璧亚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤脂信,失蹤者是張志新(化名)和其女友劉穎癣蟋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狰闪,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡疯搅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了埋泵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幔欧。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丽声,靈堂內(nèi)的尸體忽然破棺而出礁蔗,到底是詐尸還是另有隱情,我是刑警寧澤雁社,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布浴井,位于F島的核電站,受9級特大地震影響霉撵,放射性物質(zhì)發(fā)生泄漏磺浙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一喊巍、第九天 我趴在偏房一處隱蔽的房頂上張望屠缭。 院中可真熱鬧,春花似錦崭参、人聲如沸呵曹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奄喂。三九已至铐殃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間跨新,已是汗流浹背富腊。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留域帐,地道東北人赘被。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像肖揣,于是被迫代替她去往敵國和親民假。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353