IDEA加密文件Base64转换String传输以及报文摘要MD5防止恶意篡改

来源:互联网 发布:智能健康数据分析图 编辑:程序博客网 时间:2024/05/29 18:46
一、需求:将数据加密之后存放到excel表中,到另一个地方之后,解密读出明文,但要采取一定的方法鉴别密文是否被修改过。
二、思路:先用MD5报文摘要算法算出明文的摘要信息,并把摘要信息和明文一起用IDEA进行加密,保存密文到excel表中。当要读取得时候,先解密,再分离明文和报文摘要,同时再用md5算出明文的报文摘要,用这个报文摘要和原来的摘要对比,如果一样,则密文没有被改动。
三、遇到的问题:在进行加密和解密的过程中需要这样的转换:string-byte-string-byte,如果直接用jdk的普通类进行转换,是不可行的,需要借用Base64这个类。
四、代码部分
1、CipherService类,用来IDEA的密钥生成、加密以及解密(可以自己定义密钥)
用的的工具包是:bcprov-ext-jdk16-146.jar


import java.security.Key;
import java.security.Security;

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

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class CipherService {


/**
* 密钥算法
* */
public static final String KEY_ALGORITHM="IDEA";

/**
* 这是加密和解密的钥匙,暂时为这个,最长为128位
*/
public static final String KEY = "HELLOIAMFINLEYHA";

/**
* 加密/解密算法/工作模式/填充方式
* */
public static final String CIPHER_ALGORITHM="IDEA/ECB/ISO10126Padding";


/**
*
* 生成密钥,只有bouncycastle支持
* @return byte[] 二进制密钥
* */
public byte[] initkey() throws Exception{
//加入bouncyCastle支持
Security.addProvider(new BouncyCastleProvider());

//实例化密钥生成器
KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥生成器,IDEA要求密钥长度为128位
kg.init(128);
//生成密钥
SecretKey secretKey=kg.generateKey();
//获取二进制密钥编码形式
return secretKey.getEncoded();
}
/**
* 转换密钥
* @param key 二进制密钥
* @return Key 密钥
* */
public Key toKey(byte[] key) throws Exception{
//实例化iDES密钥
//生成密钥
SecretKey secretKey=new SecretKeySpec(key,KEY_ALGORITHM);
return secretKey;
}

/**
* 加密数据
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密后的数据
* */
public byte[] encrypt(byte[] data,byte[] key) throws Exception{
//加入bouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
//还原密钥
Key k=this.toKey(key);
//实例化
Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
//初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, k);
//执行操作
return cipher.doFinal(data);
}

/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密后的数据
* */
public byte[] decrypt(byte[] data,byte[] key) throws Exception{
//加入bouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
//还原密钥
Key k =this.toKey(key);
Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
//初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, k);
//执行操作
return cipher.doFinal(data);
}
}


2、excel表的导入导出,同时实现在这个过程中进行加密和解密:
用到的包有:
bcprov-ext-jdk16-146.jar、
下面是个包是对poi对excel表的操作是用到的
poi-3.12-20150511.jarpoi-ooxml-3.12-20150511.jarpoi-ooxml-schemas-3.12-20150511.jarlib/xmlbeans-2.6.0.jar
本来想上传到云盘里面然后分享给大家下载的链接、、、、、、不过下载这些包也不难,建议到官网逛逛

/**
* 把二维数组导出成excel表
* @param list 装载导出数据的二维数组
* @param filePath 导出的文件名,不包含路径
* @author LiangYiHuai
*/
public boolean exportForm(List<ArrayList<String>> list, String fileName) {
try {
//Windows风格
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e1) {
e1.printStackTrace();
}
JFileChooser saveFileFrame = new JFileChooser();


saveFileFrame.setSelectedFile(new File(fileName));
int values = saveFileFrame.showSaveDialog(null);
saveFileFrame.setDialogTitle("另存为...");
saveFileFrame.setVisible(true);

if(values == 1){
return false;
}
String absolutePath = saveFileFrame.getSelectedFile().getAbsolutePath();
System.out.println(absolutePath);

File file = new File(absolutePath);

if(!file.exists()){
try {
if(!file.createNewFile()){
JOptionPane.showMessageDialog(null, "文件保存失败!", "提示", 2);
return false;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}else{
if(JOptionPane.showConfirmDialog(null, "存在同名文件,确定覆盖?", "提示", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION){
return false;
}
}
int index = absolutePath.lastIndexOf(".");
String suffix = absolutePath.substring(index + 1);

boolean flag = false;

Workbook wb = null;
if ("xls".equals(suffix)) {
wb = new HSSFWorkbook();
} else if ("xlsx".equals(suffix)) {
wb = new XSSFWorkbook();
} else {
return false;
}
Sheet sheet = wb.createSheet();

// 生成除标题行外的数据
int size = list.size();
byte[] encryptByte = null;
String encryptString = "";
for (int k = 0; k < size; k++) {

Row row = sheet.createRow(k);

int size_2 = list.get(k).size();
for (int i = 0; i < size_2; i++) {
String tempString = list.get(k).get(i);
if(tempString == null){
tempString = "";
}
try {
*//**
* 对导出的数据进行加密
*//*
encryptByte = cipherService.encrypt(tempString.getBytes(), CipherService.KEY.getBytes());
//将字节转换成特定的字符串(目的是后面通过转换这些字符串成字节,进行解密)
encryptString = Base64.getEncoder().encodeToString(encryptByte);
} catch (Exception e) {
try {
throw new Exception("导出文件加密异常");
} catch (Exception e1) {
e1.printStackTrace();
}

}
//设置excel表中的值
row.createCell(i).setCellValue(encryptString);

}
}

try {
FileOutputStream out = new FileOutputStream(absolutePath);
wb.write(out);
out.close();
wb.close();
flag = true;
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "文件打开中,不能被覆盖或保存文件!", "提示", JOptionPane.YES_OPTION);
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return flag;
}

*//**
* 导入excel表中的数据,并将这些数据存放到一个二位数组中
*
* @param filePath
* 包含文件名
* @param sheetIndex
* excel 表中sheet的位置 默认从0开始
* @return 带有excel表中的数据的二维数组
* @author LiangYiHuai
*//*
public List<ArrayList<String>> importForm(String filePath, int sheetIndex) throws Exception{
List<ArrayList<String>> list = new ArrayList<ArrayList<String>>();

Workbook wb = null;
try {
InputStream inp = new FileInputStream(filePath);
wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheetAt(sheetIndex);

int firstRowNum = sheet.getFirstRowNum();// 表格中开始有数据的行的索引
Row biginRow = sheet.getRow(firstRowNum);// 表哥中开始有数据的行
int lastRowNum = sheet.getLastRowNum();// 表格中最后一行的索引
int firstColNum = biginRow.getFirstCellNum();// 表格中开始有数据的第一列的索引
int colNum = biginRow.getLastCellNum() - firstColNum;// 表格中数据的最后一列减去第一列

if (colNum > 1) {


for (int i = sheet.getFirstRowNum(); i < lastRowNum+1; i++) {
ArrayList<String> tempList = new ArrayList<String>();
Row tempRow = sheet.getRow(i);

for (int k = firstColNum; k < colNum; k++) {
Cell tempCell = tempRow.getCell(k,Row.CREATE_NULL_AS_BLANK);

*//**
* switch,用来判断excel单元格中的数据是什么格式的 然后采用相应的方法来读取,否则会抛出异常
*//*
switch (tempCell.getCellType()) {
case Cell.CELL_TYPE_STRING:
String string = tempCell.getRichStringCellValue().getString();
*//**
* 解密
*//*

try {
this.myDecrypt(string, tempList);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("解密异常,数据很可能被篡改");
}

break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(tempCell)) {
// 这里为日期格式化成字符串
Date date = tempCell.getDateCellValue();
String dateString = MyDateFormat.changeDateToString(date);

*//**
* 解密
*//*


try {
this.myDecrypt(dateString, tempList);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("解密异常,数据很可能被篡改");
}
} else {
tempCell.setCellType(Cell.CELL_TYPE_STRING);
String tempString = tempCell.getStringCellValue();
if (tempString.indexOf(".") > -1) {
String doubleString = String.valueOf(new Double(tempString));
*//**
* 解密
*//*


try {
this.myDecrypt(doubleString, tempList);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("解密异常,数据很可能被篡改");
}

} else {
//tempList.add(tempString);

*//**
* 解密
*//*


try {
this.myDecrypt(tempString, tempList);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("解密异常,数据很可能被篡改");
}
}
}
break;
case Cell.CELL_TYPE_BOOLEAN:

String booleanString = String.valueOf(tempCell.getBooleanCellValue());

*//**
* 解密
*//*


try {
this.myDecrypt(booleanString, tempList);
} catch (Exception e) {
e.printStackTrace();

throw new Exception("解密异常,数据很可能被篡改");

}

break;
case Cell.CELL_TYPE_FORMULA:
tempCell.setCellType(Cell.CELL_TYPE_STRING);
String tempString = tempCell.getStringCellValue();
if (tempString != null) {
tempString.replaceAll("#N/A", "");

*//**
* 解密
*//*


try {
this.myDecrypt(tempString, tempList);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("解密异常,数据很可能被篡改");
}
}
break;
case Cell.CELL_TYPE_ERROR:
System.out.println("error");
tempList.add("");
break;
case Cell.CELL_TYPE_BLANK:
System.out.println("error excel cell");
throw new Exception("原始excel表本不应该出现空的单元格,所以数据很可能被人为删除");
default:
System.out.println("default");
tempList.add("");
}

}
list.add(tempList);
}
}

} catch (EncryptedDocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} finally {
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}

return list;
}

3、报文摘要算法:


import java.security.MessageDigest;
public class MD5Util {
public final static String MD5(String s) {
char hexDigits[]={'梁','不','惊','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
byte[] btInput = s.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(MD5Util.MD5("Hello My name is 梁不惊"));
System.out.println(MD5Util.MD5("加密"));
}
}


0 0
原创粉丝点击