(原創)android使用AES加密和解密文件

前言

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

效果圖



代碼:

實現加密解密邏輯代碼
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();
            }
        }
    }

總結:

注意祕鑰需要一致。

代碼鏈接地址:點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章