AES加密文件


上一篇讲了《AES加密算法入门》,这篇继续讲一下AES加密文件。就以AES/CBC/PKCS5Padding为例。

1. 对字节流加密

1. 代码

 修改一下上一篇的AES类

package com.tricycle.aes;

import java.security.NoSuchAlgorithmException;

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

public class AES {
	static Cipher cipher;
	static final String AES_ALGORITHMS = "AES";
	public static final String ALGORITHMS_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
	public static final String ALGORITHMS_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
	public static final String ALGORITHMS_CBC_NoPadding = "AES/CBC/NoPadding";
	public static final String ALGORITHMS_ECB_NoPadding = "AES/ECB/NoPadding";

	/*
	 * CBC need an initial vector; IV length must be 16 bytes long
	 */
	public static byte[] getIV() {
		String iv = "1234567812345678";
		return iv.getBytes();
	}
	
	public static SecretKey generateKey() {
		SecretKey secretKey = null;
		try {
			secretKey = KeyGenerator.getInstance(AES_ALGORITHMS).generateKey();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return secretKey;
	}
	
	public static byte[] encryptCbcPKCS5Padding(byte[] source, SecretKey secretKey) {
		byte[] encrypt = null;
		try{
			Cipher cipher = Cipher.getInstance(ALGORITHMS_CBC_PKCS5Padding);
			cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(getIV()));
			encrypt = cipher.doFinal(source);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return encrypt;
	}
	
	public static byte[] decryptCbcPKCS5Padding(byte[] source, SecretKey secretKey) {
		byte[] decrypt = null;
		try{
			Cipher cipher = Cipher.getInstance(ALGORITHMS_CBC_PKCS5Padding);
			cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(getIV()));
			decrypt = cipher.doFinal(source);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return decrypt;
	}
}

FileEncryptor类:

package com.tricycle.aes;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import org.apache.log4j.Logger;

public class FileEncryptor {
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	private SecretKey mSecretKey = null;

	public FileEncryptor(SecretKey secretKey) {
		mSecretKey  = secretKey;
	}
	
	public void encrypt(String input, String output) {
		if(input == null || output == null) {
			logger.error("input == null || output == null");
			return;
		}
		File inputFile = new File(input);
		if(!inputFile.exists()) {
			logger.error("file not exist: " + input);
			return;
		}
		byte[] buffer = new byte[1024];
		byte[] readBuffer = null;
		byte[] encryptedBuffer = null;
		int lenEncrypted = 0;
		int lenRead = 0;
		BufferedInputStream is = null;
		BufferedOutputStream os = null;
		try {
			is = new BufferedInputStream(new FileInputStream(inputFile));
			os = new BufferedOutputStream(new FileOutputStream(output));

			while((lenRead = is.read(buffer)) != -1) {
				readBuffer = Arrays.copyOfRange(buffer, 0, lenRead);
				encryptedBuffer = AES.encryptCbcPKCS5Padding(readBuffer, mSecretKey);
				lenEncrypted = encryptedBuffer.length;
				os.write(encryptedBuffer, 0, lenEncrypted);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				is.close();
				os.flush();
				os.close();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void decrypt(String input, String output) {
		if(input == null || output == null) {
			logger.error("input == null || output == null");
			return;
		}
		File inputFile = new File(input);
		if(!inputFile.exists()) {
			logger.error("file not exist: " + input);
			return;
		}
		byte[] buffer = new byte[1024];
		byte[] readBuffer = null;
		byte[] encryptedBuffer = null;
		int lenDecrypted = 0;
		int lenRead = 0;
		BufferedInputStream is = null;
		BufferedOutputStream os = null;
		try {
			is = new BufferedInputStream(new FileInputStream(inputFile));
			os = new BufferedOutputStream(new FileOutputStream(output));

			while((lenRead = is.read(buffer)) != -1) {
				readBuffer = Arrays.copyOfRange(buffer, 0, lenRead);
				encryptedBuffer = AES.decryptCbcPKCS5Padding(readBuffer, mSecretKey);
				lenDecrypted = encryptedBuffer.length;
				os.write(encryptedBuffer, 0, lenDecrypted);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				is.close();
				os.flush();
				os.close();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}	
}


2. 分析

要注意,一下这种写法是错误的,buffer的长度永远是1024,当buffer都会来的长度不足1024时就会出错。


while((len = is.read(buffer)) != -1) {
    os.write(AES.encryptCbcPKCS5Padding(buffer, mSecretKey), 0, len);
}


2.使用CipherOutputStreamCipherInputStream

CipherOutputStreamCipherInputStream是继承OutputStreamInputStream,和BufferedOutputStreamBufferedInputStream类似,都是OutputStreamInputStream的装饰者,后面设想会在讲装饰者模式的时候用这个来举例。

 

	
	public void encryptByCipherStream(String input, String output) {
		if(input == null || output == null) {
			logger.error("input == null || output == null");
			return;
		}
		File inputFile = new File(input);
		File outputFile = new File(output);
		if(!inputFile.exists()) {
			logger.error("file not exist: " + input);
			return;
		}
		Cipher cipher;
		OutputStream os = null;
		InputStream is = null;
		try {
			cipher = Cipher.getInstance(AES.ALGORITHMS_CBC_PKCS5Padding);
			cipher.init(Cipher.ENCRYPT_MODE, mSecretKey, new IvParameterSpec(AES.getIV()));
			
			is = new BufferedInputStream(new FileInputStream(inputFile));
			os = new CipherOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)), cipher);
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			try {
				is.close();
				os.flush();
				os.close();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void decryptByCipherStream(String input, String output) {
		if(input == null || output == null) {
			logger.error("input == null || output == null");
			return;
		}
		File inputFile = new File(input);
		File outputFile = new File(output);
		if(!inputFile.exists()) {
			logger.error("file not exist: " + input);
			return;
		}
		Cipher cipher;
		OutputStream os = null;
		InputStream is = null;
		try {
			cipher = Cipher.getInstance(AES.ALGORITHMS_CBC_PKCS5Padding);
			cipher.init(Cipher.DECRYPT_MODE, mSecretKey, new IvParameterSpec(AES.getIV()));
			
			is = new CipherInputStream(new BufferedInputStream(new FileInputStream(inputFile)), cipher);
			os = new BufferedOutputStream(new FileOutputStream(outputFile));
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			try {
				is.close();
				os.flush();
				os.close();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}

3.测试

测试类

package com.tricycle.utils;

import com.tricycle.aes.AES;
import com.tricycle.aes.FileEncryptor;

public class Test {
	
	private static final String AES_SOURCE_FILE = "G:\\javaTest\\AES\\sourceFile.txt";
	private static final String AES_ENCRYPT_FILE = "G:\\javaTest\\AES\\encryptFile.txt";
	private static final String AES_DECRYPT_FILE = "G:\\javaTest\\AES\\decryptFile.txt";
	private static final String AES_ENCRYPT_FILE1 = "G:\\javaTest\\AES\\encryptFile1.txt";
	private static final String AES_DECRYPT_FILE1 = "G:\\javaTest\\AES\\decryptFile1.txt";

	public static void main(String[] args) {
		FileEncryptor fileEncryptor = new FileEncryptor(AES.generateKey());
		fileEncryptor.encrypt(AES_SOURCE_FILE, AES_ENCRYPT_FILE);
		fileEncryptor.decrypt(AES_ENCRYPT_FILE, AES_DECRYPT_FILE);
		fileEncryptor.encryptByCipherStream(AES_SOURCE_FILE, AES_ENCRYPT_FILE1);
		fileEncryptor.decryptByCipherStream(AES_ENCRYPT_FILE, AES_DECRYPT_FILE1);
	}
}

结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值