引入:
现在我们来研究密码学的加密解密过程,这个十分重要,因为它是明文到密文的桥梁,从类型上分,我们又分为加密解密字符串和加密解密文件,我们这文章就讲解这些细节,主要的核心类是Cipher类。
实践:
加密字符串的一般过程为:
(1)获取一个加密用的密钥
(2)实例化Cipher对象
(3)初始化Cipher对象,指定其现在处于加密模式(ENCRYPT_MODE),并指定加密使用的密钥
(4)调用doFinal方法,传入被加密的字符串对应的字节数组,返回加密后的字节数组
解密字符串的一般过程为:
(1)获取一个解密用的密钥
(2)实例化Cipher对象
(3)初始化Cipher对象,指定其现在处于解密模式(DECRYPT_MODE),并指定解密用的密钥
(4)调用doFinal方法,传入密文字节数组,返回解密后的字节数组
加密文件的一般过程为:
(1)获取一个加密用的密钥
(2)实例化Cipher对象
(3)初始化Cipher对象,指定其现在处于加密模式(ENCRYPT_MODE),并指定加密使用的密钥
(4)打开文件输入流,指向要被加密的文件
(5)打开文件输出流,指向加密后存放的文件
(6)打开加密输入流,包装指向被加密文件的输入流
(7)读取,并且加密,加密结果写入目标文件
解密文件的一般过程为:
(1)获取一个解密用的密钥
(2)实例化Cipher对象
(3)初始化Cipher对象,指定其现在处于解密模式(DECRYPT_MODE),并指定解密用的密钥
(4)打开文件输入流,指向要被解密的文件
(5)打开文件输出流,指向解密后存放的文件
(6)打开解密输出流,包装指向解密后文件的输出流
(7)读取,并且解密,解密结果写入目标文件
为了演示上面过程,我们写了一个工具类:
package com.charles.encryptstudy;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
/**
*
* Description: 这个类提供了加密解密的一般方法
*
* @author charles.wang
* @created Oct 29, 2013 9:17:48 AM
*
*/
public class EncryptUtil {
//加密解密字符串的操作方法
/**
* 用指定的密钥加密,吧字符串加密成字节数组
*
* @param data 被加密的字符串
* @param key 加密使用的密钥
* @return 加密后的字节流
* @throws InvalidKeyException
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*
*/
public static byte[] encryptString(String data, Key key)
throws InvalidKeyException,NoSuchPaddingException,NoSuchAlgorithmException,BadPaddingException,IllegalBlockSizeException {
// 实例化Cipher对象用于加密操作
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
// 初始化Cipher对象,表明这个Cipher现在处于加密模式,并且指定加密使用的密钥
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密过程,返回加密后的内容
return cipher.doFinal(data.getBytes());
}
/**
* 用指定的密钥解密,还原字符串
*
* @param data 要被解密的字节流
* @param key 解密使用的密钥
* @return 解密后还原的字符串
* @throws InvalidKeyException
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decryptString(byte[] data, Key key) throws InvalidKeyException,NoSuchPaddingException,NoSuchAlgorithmException,BadPaddingException,IllegalBlockSizeException {
// 实例化Cipher对象用于解密操作
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
// 初始化Cipher对象,表明这个Cipher现在处于解密模式,并且指定解密使用的密钥
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(data));
}
//加密解密文件的操作方法
/**
* 用指定的密钥加密文件(sourceFile),结果保存在destFile中
*
* @param sourceFile 要加密的文件
* @param destFile 加密后的文件
* @param key 加密使用的密钥
* @throws Exception
*/
public static void encryptFile(String sourceFile,String destFile,Key key) throws Exception{
//实例化Cipher对象用于加密操作
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
//初始化Cipher对象,表明这个Cipher现在处于加密模式,并且指定加密使用的密钥
cipher.init(Cipher.ENCRYPT_MODE, key);
//打开文件输入流,指向要被加密的文件
InputStream is = new FileInputStream(sourceFile);
//打开文件输出流,指向加密后存放的文件
OutputStream os = new FileOutputStream(destFile);
//打开加密输入流,包装指向被加密文件的输入流
CipherInputStream cis = new CipherInputStream(is,cipher);
//缓冲区
byte[] buffer = new byte[1024];
int result;
//读取,并且加密,加密结果写入目标文件
while ((result = cis.read(buffer)) > 0) {
os.write(buffer, 0, result);
}
cis.close();
is.close();
os.close();
}
/**
* 用指定的密钥解密文件(encryptedFile),结果保存在originalFile中
*
* @param encryptedFile 要解密的文件
* @param originalFile 解密后的文件
* @param key 解密使用的密钥
* @throws Exception
*/
public static void decryptFile(String encryptedFile,String originalFile,Key key) throws Exception{
//实例化Cipher对象用于解密操作
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
//初始化Cipher对象,表明这个Cipher现在处于解密模式,并且指定解密使用的密钥
cipher.init(Cipher.DECRYPT_MODE, key);
//打开文件输入流,指向要被解密的文件
InputStream is = new FileInputStream(encryptedFile);
//打开文件输出流,指向解密后存放的文件
OutputStream os = new FileOutputStream(originalFile);
//打开解密输出流,包装指向解密后文件的输出流
CipherOutputStream cos = new CipherOutputStream(os,cipher);
//缓冲区
byte[] buffer = new byte[1024];
int result;
//读取,并且解密,解密结果写入目标文件
while ((result = is.read(buffer)) > 0) {
cos.write(buffer, 0, result);
}
cos.close();
is.close();
os.close();
}
}
对于加密解密字符串,我们写了一个演示Demo类,来演示这2个操作结果,我们指定任意字符串,先用我们的加密方法对其加密,然后用我们的解密方法解密还原原始字符串.
package com.charles.encryptstudy;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import sun.misc.BASE64Encoder;
import com.charles.keystudy.SymmetricKeyUtil;
/**
*
* Description: 这个类用来演示如何加密和解密字符串
*
* @author charles.wang
* @created Oct 28, 2013 4:37:41 PM
*
*/
public class EncryptStringDemo {
public static void main(String[] args) throws Exception {
//我们演示加密解密字符串
System.out.println("加密解密字符串:");
String stringNeedEncrypt="加密这段文本";
System.out.println("被加密的文本为:"+stringNeedEncrypt);
//产生一个密钥
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
Key key=keyGen.generateKey();
System.out.println("\n加密使用的密钥为:"+(new BASE64Encoder()).encode(key.getEncoded()));
System.out.println("加密使用的算法为:"+key.getAlgorithm());
//加密字符串过程
System.out.println("\n开始加密字符串...");
byte[] encryptedValue = EncryptUtil.encryptString(stringNeedEncrypt, key);
System.out.println("加密后的密文为:"+(new BASE64Encoder()).encode(encryptedValue));
//解密字符串过程
System.out.println("\n开始解密字符串...");
String decryptedString = EncryptUtil.decryptString(encryptedValue, key);
System.out.println("解密后还原的字符串为:"+decryptedString);
}
}
运行这个类的main()方法,我们可以很清楚的看到,代码正确的被执行了:
对于加密解密文件,我们写了一个演示Demo类,来演示这2个操作结果,我们指定原始文件,先用我们的加密方法对其加密,产生密文文件,然后用我们的解密方法解密还原原始文件。
package com.charles.encryptstudy;
import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import javax.crypto.KeyGenerator;
import sun.misc.BASE64Encoder;
/**
*
* Description: 这个类是用来演示如何加密和解密文件的
*
* @author charles.wang
* @created Oct 29, 2013 10:06:01 AM
*
*/
public class EncryptFileDemo {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
//我们演示加密解密文件
System.out.println("加密解密文件:");
//给定被加密的文件,你可以吧相应任意文件放在任意目录并且更改这里路径
String filePathNeedEncrypt="travel.jpg";
//获取被加密的文件信息
File fileNeedEncrypt= new File(filePathNeedEncrypt);
System.out.println("被加密的文件为:"+fileNeedEncrypt.getName());
System.out.println("被加密文件的大小为:"+fileNeedEncrypt.length()+" bytes");
//产生一个密钥
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
Key key=keyGen.generateKey();
System.out.println("\n加密使用的密钥为:"+(new BASE64Encoder()).encode(key.getEncoded()));
System.out.println("加密使用的算法为:"+key.getAlgorithm());
//加密文件过程
System.out.println("\n开始加密文件...");
String filePathEncrypted="travel-encrypt.encrypt";
EncryptUtil.encryptFile(filePathNeedEncrypt,filePathEncrypted,key);
//获取加密后的密文文件信息
File fileEncrypted = new File(filePathEncrypted);
System.out.println("加密后的密文文件为:"+fileEncrypted.getName());
System.out.println("加密后的密文文件大小为:"+fileEncrypted.length()+" bytes");
//解密文件过程
System.out.println("\n开始解密文件...");
String filePathRestored="travel-restored.jpg";
EncryptUtil.decryptFile(filePathEncrypted,filePathRestored,key);
//获取解密后的明文文件信息
File fileRestored = new File(filePathRestored);
System.out.println("解密后的明文文件为:"+fileRestored.getName());
System.out.println("解密后的明文文件大小为:"+fileRestored.length()+" bytes");
}
}
运行这个类的main()方法,我们可以很清楚的看到,代码正确的被执行了,尤其比较下文件大小:
如果不放心的话,我们去文件系统看:
对于原始文件travel.jpg:
对于加密后的密文文件travel-encrypt.encrypt:
再比较解密后还原的文件travel-restored.jpg:
可以发现它和原始文件是完全一样的。
转载于:https://blog.51cto.com/supercharles888/1316630