天天看點

(原創)android使用AES加密和解密檔案

前言

最近公司需要對本公司的一些下載下傳檔案進行加密解密需求,也就嘗試去實作下,其實需要借助第三方的jar包:bcprov-jdk15on-155.jar,下載下傳這個可以到網上搜或者下載下傳本人的demo即可,注意:需要加密和解密的key是一緻的才可以解密,不然就會解密失敗。不多說,直接上代碼。

效果圖

(原創)android使用AES加密和解密檔案
(原創)android使用AES加密和解密檔案

(原創)android使用AES加密和解密檔案
(原創)android使用AES加密和解密檔案
(原創)android使用AES加密和解密檔案
(原創)android使用AES加密和解密檔案

代碼:

實作加密解密邏輯代碼

package com.vsoontech.p2p.sample;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;

/**
 * @author zhou
 * @since 2016/9/26
 */

public enum AES {
    INSTANCE;
    private Key key;

    /**
     * 生成AES對稱秘鑰
     */
    public String generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keygen = KeyGenerator.getInstance("AES");
        SecureRandom random = new SecureRandom();
        keygen.init(random);
        this.key = keygen.generateKey();
        return "Algorithm Format Encoded:" + key.getAlgorithm() + " - " + key.getFormat() + " - " + new String(key.getEncoded());
    }

    /**
     * 加密
     */
    public void encrypt(InputStream in) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
        this.crypt(in, null, Cipher.ENCRYPT_MODE);
    }

    /**
     * 解密
     */
    public String decrypt(InputStream in) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
        return this.crypt(in, Cipher.DECRYPT_MODE);
    }

    /**
     * 加密
     */
    public void encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
        this.crypt(in, out, Cipher.ENCRYPT_MODE);
    }

    /**
     * 解密
     */
    public void decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
        this.crypt(in, out, Cipher.DECRYPT_MODE);
    }

    /**
     * 實際的加密解密過程
     */
    public void crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(mode, this.key);

        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        byte[] inBytes = new byte[blockSize];
        byte[] outBytes = new byte[outputSize];

        int inLength = 0;
        boolean more = true;
        while (more) {
            inLength = in.read(inBytes);
            if (inLength == blockSize) {   //隻要輸入資料塊具有全長度(長度可被8整除),調用update方法
                int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
                if (out != null) out.write(outBytes, 0, outLength);
            } else {
                more = false;
            }
        }
        if (inLength > 0)   //不具有全長度,調用doFinal方法
            outBytes = cipher.doFinal(inBytes, 0, inLength);
        else
            outBytes = cipher.doFinal();
        if (out != null) {
            out.write(outBytes);
            out.flush();
        }
    }

    /**
     * 實際的加密解密過程
     */
    public String crypt(InputStream in, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(mode, this.key);

        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        byte[] inBytes = new byte[blockSize];
        byte[] outBytes = new byte[outputSize];

        int inLength = 0;
        boolean more = true;
        StringBuilder sb = new StringBuilder();
        while (more) {
            inLength = in.read(inBytes);
            if (inLength == blockSize) {   //隻要輸入資料塊具有全長度(長度可被8整除),調用update方法
                int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
            } else {
                more = false;
            }
        }
        if (inLength > 0)   //不具有全長度,調用doFinal方法
            outBytes = cipher.doFinal(inBytes, 0, inLength);
        else
            outBytes = cipher.doFinal();
        sb.append(new String(outBytes));
        return sb.toString();
    }


    public void setKey(Key key) {
        this.key = key;
    }

    public Key getKey() {
        return key;
    }
}
           

生成秘鑰代碼

package com.vsoontech.p2p.sample;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * @author zhou
 * @since 2016/9/26
 */

public class AESKeyModel {
    public static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    private String srcFile = "", destionFile = "";

    /**
     * 初始化密鑰
     *
     * @return byte[] 密鑰
     * @throws Exception
     */
    public byte[] initSecretKey() {
        //傳回生成指定算法的秘密密鑰的 KeyGenerator 對象
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return new byte[0];
        }
        //初始化此密鑰生成器,使其具有确定的密鑰大小
        //AES 要求密鑰長度為 128
        kg.init(128);
        //生成一個密鑰
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    public void setDestionFile(String destionFile) {
        this.destionFile = destionFile;
    }

    public void setSrcFile(String srcFile) {
        this.srcFile = srcFile;
    }

    /**
     * 轉換密鑰
     *
     * @param key 二進制密鑰
     * @return 密鑰
     */
    private static Key toKey(byte[] key) {
        //生成密鑰
        return new SecretKeySpec(key, KEY_ALGORITHM);
    }

    /**
     * 加密
     *
     * @param data 待加密資料
     * @param key  密鑰
     * @return byte[]   加密資料
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, Key key) throws Exception {
        return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
    }

    /**
     * 加密
     *
     * @param data 待加密資料
     * @param key  二進制密鑰
     * @return byte[]   加密資料
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
    }


    /**
     * 加密
     *
     * @param data            待加密資料
     * @param key             二進制密鑰
     * @param cipherAlgorithm 加密算法/工作模式/填充方式
     * @return byte[]   加密資料
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception {
        //還原密鑰
        Key k = toKey(key);
        return encrypt(data, k, cipherAlgorithm);
    }

    /**
     * 加密
     *
     * @param data            待加密資料
     * @param key             密鑰
     * @param cipherAlgorithm 加密算法/工作模式/填充方式
     * @return byte[]   加密資料
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
        //執行個體化
        Cipher cipher = Cipher.getInstance(cipherAlgorithm);
        //使用密鑰初始化,設定為加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key);
        //執行操作
        return cipher.doFinal(data);
    }

    /**
     * 解密
     *
     * @param data 待解密資料
     * @param key  二進制密鑰
     * @return byte[]   解密資料
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
        return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
    }

    /**
     * 解密
     *
     * @param data 待解密資料
     * @param key  密鑰
     * @return byte[]   解密資料
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, Key key) throws Exception {
        return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
    }

    /**
     * 解密
     *
     * @param data            待解密資料
     * @param key             二進制密鑰
     * @param cipherAlgorithm 加密算法/工作模式/填充方式
     * @return byte[]   解密資料
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception {
        //還原密鑰
        Key k = toKey(key);
        return decrypt(data, k, cipherAlgorithm);
    }

    /**
     * 解密
     *
     * @param data            待解密資料
     * @param key             密鑰
     * @param cipherAlgorithm 加密算法/工作模式/填充方式
     * @return byte[]   解密資料
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
        //執行個體化
        Cipher cipher = Cipher.getInstance(cipherAlgorithm);
        //使用密鑰初始化,設定為解密模式
        cipher.init(Cipher.DECRYPT_MODE, key);
        //執行操作
        return cipher.doFinal(data);
    }

    public void encryptionFile(Key sessionKey) throws Exception {
        int len = 0;
        byte[] buffer = new byte[1024];
        byte[] cipherbuffer = null;

        // 使用會話密鑰對檔案加密。
        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM, new BouncyCastleProvider());
        IvParameterSpec iv = new IvParameterSpec("0000000000123456".getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, sessionKey, iv);

        FileInputStream fis = new FileInputStream(new File(srcFile));
        FileOutputStream fos = new FileOutputStream(new File(destionFile));

        // 讀取原文,加密并寫密文到輸出檔案。
        while ((len = fis.read(buffer)) != -1) {
            cipherbuffer = cipher.update(buffer, 0, len);
            fos.write(cipherbuffer);
            fos.flush();
        }
        cipherbuffer = cipher.doFinal();
        fos.write(cipherbuffer);
        fos.flush();

        if (fis != null)
            fis.close();
        if (fos != null)
            fos.close();
    }

    public void descryptionFile(Key sessionKey) throws Exception {
        int len = 0;
        byte[] buffer = new byte[5 * 1024];
        byte[] plainbuffer = null;

        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM, new BouncyCastleProvider());
        IvParameterSpec iv = new IvParameterSpec("0000000000123456".getBytes());
        cipher.init(Cipher.DECRYPT_MODE, sessionKey, iv);

        FileInputStream fis = new FileInputStream(new File(srcFile));
        FileOutputStream fos = new FileOutputStream(new File(destionFile));

        while ((len = fis.read(buffer)) != -1) {
            plainbuffer = cipher.update(buffer, 0, len);
            fos.write(plainbuffer);
            fos.flush();
        }

        plainbuffer = cipher.doFinal();
        fos.write(plainbuffer);
        fos.flush();

        if (fis != null)
            fis.close();
        if (fos != null)
            fos.close();
    }
}
           

加密邏輯示例代碼

/**
     * 加密
     *
     * @param path
     * @param destionFile
     */
    private void aes(String path, String destionFile) {
        try {
            Log.d(TAG, "aes Key: " + AES.INSTANCE.generateKey());
            FileInputStream fis = new FileInputStream(new File(path));
            FileOutputStream fos = new FileOutputStream(new File(destionFile));
            AES.INSTANCE.encrypt(fis, fos);
        } catch (Exception e) {
            Log.d(TAG, "Exception: " + e.toString());
            e.printStackTrace();
        }

    }
           

解密邏輯示例代碼:

/**
     * AES解密檔案
     *
     * @param path 需要解密的檔案目錄
     */
    private void aesJieMi(String path) {
        File f = new File(path);
        if (!f.exists() || f.isDirectory())
            Toast.makeText(getApplicationContext(), "該檔案不合法!", Toast.LENGTH_SHORT).show();
        else {
            String prefix = f.getName().substring(0, f.getName().indexOf('.'));
            String suffix = f.getName().substring(f.getName().indexOf('.'));
            String outjiemiFile = Environment.getExternalStorageDirectory() + File.separator + prefix + "AES_jieMi" + suffix;

            AESKeyModel model_aes = new AESKeyModel();
            model_aes.setSrcFile(path);
            model_aes.setDestionFile(outjiemiFile);

            try {
//                model_aes.descryptionFile(key_AES);
                model_aes.descryptionFile(key_aes);
                // TODO: 加密後的檔案
                RandomAccessFile raf = new RandomAccessFile(path, "rw");
                Log.d(TAG, "解密後 file length: " + raf.length());
                Log.d(TAG, "解密後 file content: " + raf.readLine());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
           

總結:

注意秘鑰需要一緻。

代碼連結位址: 點選打開連結

繼續閱讀