最近接到任务(文件的安全性)需要在文件上传到服务器上时将文件加密保存, 用户下载时将文件解密后返回给用户。翻了下方法最后决定用java中的Cipher类来完成(里面的实现方式挺全的)。
上手实现。pom.xml文件引入依赖包
org.bouncycastlebcprov-jdk15on1.56commons-codeccommons-codec1.10
生成秘钥(static代码块必须否则会报错)
static {Security.addProvider(new BouncyCastleProvider());}public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException {KeyGenerator kg = KeyGenerator.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);kg.init(128, new SecureRandom());byte[] result = kg.generateKey().getEncoded();System.out.println(new String(Hex.encodeHex(result, false)));}
初始化Cipher加解密的公用方法
/** * * @param mode_type 加解密类型 * @param keyData key的字节数组 * @param cipher_algorith 算法/工作模式/填充模式 * @param algorith_name 算法 * @return * @throws InvalidKeyException * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException */ public static Cipher generateCipher(int mode_type, byte[] keyData,String cipher_algorith,String algorith_name) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException { Cipher cipher = Cipher.getInstance(cipher_algorith, BouncyCastleProvider.PROVIDER_NAME); SecretKeySpec key = new SecretKeySpec(keyData, algorith_name); cipher.init(mode_type, key); return cipher; }
加密方法调用
/** * * @param key 秘钥 * @param inStream 源文件流 * @param targetPath 加密后文件 * @param cipher_algorith 算法/工作模式/填充模式 * @param algorith_name 算法 * @throws InvalidKeyException * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws IOException */ public static void encryptStream(String key, InputStream inStream, String targetPath,String cipher_algorith,String algorith_name) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, IOException { CipherInputStream cipherInputStream = null; try { byte[] keyData = ByteUtils.fromHexString(key); Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, keyData, cipher_algorith, algorith_name); cipherInputStream = new CipherInputStream(inStream, cipher); Util.copy(cipherInputStream, targetPath); } finally { Util.close(cipherInputStream,inStream); } }
解密方法调用
/** * * @param key 秘钥 * @param sourcePath 加密文件 * @param out 输入的文件流 * @param cipher_algorith 算法/工作模式/填充模式 * @param algorith_name 算法 * @throws InvalidKeyException * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws IOException */ public static void decryptFile(String key,String sourcePath, OutputStream out,String cipher_algorith,String algorith_name) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, IOException { CipherOutputStream cipherOutputStream = null; try { byte[] keyData = ByteUtils.fromHexString(key); Cipher cipher = generateCipher(Cipher.DECRYPT_MODE, keyData, cipher_algorith, algorith_name); cipherOutputStream = new CipherOutputStream(out, cipher); Files.copy(Paths.get(sourcePath), cipherOutputStream); } finally { Util.close(cipherOutputStream, out); } }
写个工具类用于文件转移和关流
public class Util {/** * 文件转移 当上级目录不存在时创建 * * @param in * @param targetPath * @throws IOException */public static void copy(InputStream in, String targetPath) throws IOException {Path target = Paths.get(targetPath);Files.createDirectories(target.getParent());Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);}/** * 关流 * @param cb */public static void close(Closeable... cb) {for (Closeable cbd : cb) {if (cbd != null) {try {cbd.close();} catch (IOException e) {e.printStackTrace();}}}}}
找到Cipher中支持的加解密算法,从bcprov-jdk15on1.56.jar包中翻出目前支持的算法有
找几个常用的加解密方式来验收下成果
package com.more.fw.core.common.method;import java.io.FileInputStream;import java.io.FileOutputStream;import java.security.SecureRandom;import java.security.Security;import javax.crypto.KeyGenerator;import org.apache.commons.codec.binary.Hex;import org.bouncycastle.jce.provider.BouncyCastleProvider;public class Test { public static final String ALGORITHM_NAME_3DES = "DESede";//Blowfish算法 public static final String CIPHER_ALGORITHM_3DES_ECB = "DESede/ECB/PKCS5Padding";//格式是"算法/工作模式/填充模式" public static final String ALGORITHM_NAME_BLOWFISH = "Blowfish";//Blowfish算法 public static final String CIPHER_ALGORITHM_BLOWFISH = "Blowfish/ECB/PKCS5Padding";//格式是"算法/工作模式/填充模式" public static final String ALGORITHM_NAME_SM4 = "SM4";//SM4算法 public static final String CIPHER_ALGORITHM_SM4 = "SM4/ECB/PKCS5Padding";//格式是"算法/工作模式/填充模式" public static final String ALGORITHM_NAME_AES = "AES";//AES算法 public static final String CIPHER_ALGORITHM_AES = "AES/ECB/PKCS5Padding";//格式是"算法/工作模式/填充模式" public static final String ALGORITHM_NAME_RC2 = "RC2";//RC2算法 public static final String CIPHER_ALGORITHM_RC2 = "RC2/ECB/PKCS5Padding";//格式是"算法/工作模式/填充模式"static {Security.addProvider(new BouncyCastleProvider());}public static final int DEFAULT_KEY_SIZE = 128;public static void main(String[] args) throws Exception {String key = generateKey(ALGORITHM_NAME_AES);FileInputStream in = new FileInputStream("F:logsmc_info.log.14");//源文件String targer = "D:logsmc_info.log.15";//加密后文件long star = System.currentTimeMillis();encryptStream(key,in,targer,CIPHER_ALGORITHM_AES,ALGORITHM_NAME_AES);System.out.println("AES加密時間:"+(System.currentTimeMillis()-star));FileOutputStream out = new FileOutputStream("D:logsmc_info.log.16");star = System.currentTimeMillis();decryptFile(key, targer, out, CIPHER_ALGORITHM_AES,ALGORITHM_NAME_AES);System.out.println("AES解密時間:"+(System.currentTimeMillis()-star));in = new FileInputStream("F:logsmc_info.log.14");//源文件targer = "D:logsmc_info.log.17";//加密后文件star = System.currentTimeMillis();encryptStream(key,in,targer,CIPHER_ALGORITHM_SM4,ALGORITHM_NAME_SM4);System.out.println("SM4加密時間:"+(System.currentTimeMillis()-star));out = new FileOutputStream("D:logsmc_info.log.18");star = System.currentTimeMillis();decryptFile(key, targer, out, CIPHER_ALGORITHM_SM4,ALGORITHM_NAME_SM4);System.out.println("SM4解密時間:"+(System.currentTimeMillis()-star));in = new FileInputStream("F:logsmc_info.log.14");//源文件targer = "D:logsmc_info.log.19";//加密后文件star = System.currentTimeMillis();encryptStream(key,in,targer,CIPHER_ALGORITHM_BLOWFISH,ALGORITHM_NAME_BLOWFISH);System.out.println("BLOWFISH加密時間:"+(System.currentTimeMillis()-star));out = new FileOutputStream("D:logsmc_info.log.20");star = System.currentTimeMillis();decryptFile(key, targer, out, CIPHER_ALGORITHM_BLOWFISH,ALGORITHM_NAME_BLOWFISH);System.out.println("BLOWFISH解密時間:"+(System.currentTimeMillis()-star));in = new FileInputStream("F:logsmc_info.log.14");//源文件targer = "D:logsmc_info.log.21";//加密后文件star = System.currentTimeMillis();encryptStream(key,in,targer,CIPHER_ALGORITHM_3DES_ECB,ALGORITHM_NAME_3DES);System.out.println("3DES加密時間:"+(System.currentTimeMillis()-star));out = new FileOutputStream("D:logsmc_info.log.22");star = System.currentTimeMillis();decryptFile(key, targer, out, CIPHER_ALGORITHM_3DES_ECB,ALGORITHM_NAME_3DES);System.out.println("3DES解密時間:"+(System.currentTimeMillis()-star));in = new FileInputStream("F:logsmc_info.log.14");//源文件targer = "D:logsmc_info.log.22";//加密后文件star = System.currentTimeMillis();encryptStream(key,in,targer,CIPHER_ALGORITHM_RC2,ALGORITHM_NAME_RC2);System.out.println("RC2加密時間:"+(System.currentTimeMillis()-star));out = new FileOutputStream("D:logsmc_info.log.23");star = System.currentTimeMillis();decryptFile(key, targer, out, CIPHER_ALGORITHM_RC2,ALGORITHM_NAME_RC2);System.out.println("RC2解密時間:"+(System.currentTimeMillis()-star));}public static String generateKey(String algorithmName) throws Exception {KeyGenerator kg = KeyGenerator.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);kg.init(DEFAULT_KEY_SIZE, new SecureRandom());byte[] result = kg.generateKey().getEncoded();return new String(Hex.encodeHex(result, false));}}
跑出的结果如下
AES加密時間:6845AES解密時間:2880SM4加密時間:8328SM4解密時間:4255BLOWFISH加密時間:7648BLOWFISH解密時間:39353DES加密時間:183513DES解密時間:14710RC2加密時間:12116RC2解密時間:4151