对国库数据加密解密

/**
 * 
 * 说明:对国库数据加密、解密
 */
 
package com.cfcc.tas.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Calendar;
import java.util.Random;


public class TreasuryEncrypt {
	
	//二维数组,61*8;
	private final static String ENCRYPT_KEY [][]=  
		{{"?1i%d3Kx"},{"s8@8$!*i"},{"d7J:SFw4"},{"l6piz3Gn"},
		 {"Rs5t|o&#"},{"4s*m-y4;"},{"3o34%x:W"},{"a2e+FDKQ"},
		 {"s{OCS$1?"},{"sAUI<>2a"},{"2_gf<3vQ"},{"b8&o<fH]"},
		 {"7ds?.asd"},{"sd6sft4V"},{"ds5QTP{q"},{"n4^/?Sys"},
		 {"sfdteib8"},{"b2s?>LK}"},{"1/dti[qr"},{"a!bfo[[e"},
		 {"U3v$@h89"},{"8n$Lfv?2"},{"b7bwetjw"},{"bc6ertlx"},
		 {"h4532:KE"},{"k46SFTTR"},{"3XdrFGty"},{"2nVI%#dM"},
		 {"1af;mes,"},{"cb$yu.sx"},{"G4s?2+-s"},{"v83+V#OU"},
		 {"b7|ET&Nd"},{"n6b(G$><"},{"n5fsre65"},{"4lQfaftk"},
		 {"SDF{}3rd"},{"fert2<db"},{"s246<M19"},{"%dfgd45d"},
		 {"d5gsb2x!"},{"s8f:oewZ"},{"7d~twpot"},{"y6dsf34s"},
		 {"k59{_JH:"},{"4hvet*&e"},{"3m;SFsft"},{"sd2JLYI^"},
		 {"bf*F&^Cn"},{"h^sft.e4"},{"b6[do94)"},{"8gq=0&Fk"},
		 {"b`ewU<X|"},{"zb6rtx#@"},{"5oj79h:h"},{"sf7lakv%"},
		 {"SFETE3xd"},{"bvler-2s"},{"1d)(*V>d"},{"&ftwetrr"},
		 {"00000000"}};
	

	/*
	 * 密钥的长度
	 */
	private final static int KEY_LENGTH = ENCRYPT_KEY[0][0].length();
	
	//文件标志(windows)
	private final static byte[] WIN_FILE_SIGNAL = {13,10};	
	private final static byte[] WIN_STR_SIGNAL = {35,35};
	private final static int MAX_HEAD_LEN = 4;
	
	//分节符类型
	public final static int SIGNAL_TYPE_NULL = -1;
	public final static int SIGNAL_TYPE_STR = 0;
	public final static int SIGNAL_TYPE_FILE = 1;
	
	//加密和解密字符串时使用,如果字符串中不包含解密用的key,解密字符串时传入改值.
	public final static int KEY_NULL = -1;
	
	
	
	/*
	 * 说明: 在TCBS中主要使用了对文件中的内容进行加解密.
	 * 在TBS中,对字符串加密使用了两种方式,一种是使用回车换行(换行)做为分割密钥和字符串的标志,
	 * 一种是使用两个'#', 就是WIN_FILE_SIGNAL 和 WIN_STR_SIGNAL.
	 * 文件内容的加密使用WIN_STR_SIGNAL.
	 * 修改解密方法,文件加密有两种:一种首行为密钥索引,一种不是
	 */
	
	
	/**
	 * 对字符串加密
	 * @param srcStr
	 * @param sinalType 分节符类型 0:字符串类型 其它:文件类型
	 * @return
	 * @throws Exception
	 */
	public static String Encrypt(String srcStr, int sinalType) throws Exception{		
		if(srcStr == null || srcStr.trim().length() == 0){
			throw new Exception("被加密的字符串不能为空!");
		}
		
		//
		if(sinalType == SIGNAL_TYPE_STR){
			return encryptStr(srcStr, WIN_STR_SIGNAL);
		}else{
			return encryptStr(srcStr, WIN_FILE_SIGNAL);
		}		
	}
	
	/**
	 * 对字符串解密 (gkfxjmzjstr)
	 * @param srcStr	: 被加密后的字符串,可以带密钥也可以不带密钥. 不带密钥时需要在参数nKeyIndex传入密文使用的密钥;
	 * @param nKeyIndex : 参数srcStr中没有有密钥时,使用 nKeyIndex <= 60 并且 nKeyIndex >= 0;
	 * @param sinalType : 字符串中没有密钥时,该值无效;文件中使用回车换行(\r\n或\n)做为分割符.
	 * @return
	 * @throws Exception
	 */
	public static String Decrypt(String srcStr, int nKeyIndex, int sinalType) throws Exception {
		//
		byte keyIndex = 0;
		byte decrypt[] = null;
		
		//不在key范围内的字符串的key,认为字符串中包含key, 字符串中包含key
		if(nKeyIndex < 0 || nKeyIndex > 60){
			if(srcStr == null || srcStr.trim().length() == 0){
				throw new Exception("被解密的字符串不能为空!");
			}else if(srcStr.trim().length() <= MAX_HEAD_LEN){
				throw new Exception("被解密的字符串格式错误!");
			}
			
			//
			if(sinalType < SIGNAL_TYPE_STR){
				throw new Exception("被解密的字符串格式错误!");
			}
			
			//取key
			int idx = 0;
			if(sinalType == SIGNAL_TYPE_STR){
				idx = srcStr.indexOf(new String(WIN_STR_SIGNAL));
				keyIndex = (byte)Integer.parseInt(srcStr.substring(0, idx));
			}else{
				idx = srcStr.indexOf(new String(WIN_FILE_SIGNAL));
				keyIndex = (byte)readStrSignal(srcStr);				
			}
			
			//
			if(keyIndex > 60) {
				throw new Exception("字符串格式错误!");
			}		
			if(idx < 0) return null;
			
			decrypt = srcStr.substring(idx + 2, srcStr.length()).getBytes();
		}else{			
			keyIndex = (byte)nKeyIndex;
			decrypt = srcStr.getBytes();
		}
		
		return new String(decrypt(decrypt, decrypt.length, keyIndex));
	}
	
	
	/**
	 * 对文件加密(gkjmzj)
	 * @param srcFile
	 * @param dstFile
	 * @throws Exception
	 */
	public static void Encrypt(String srcFile, String dstFile) throws Exception{
		
		File inFile = new File(srcFile);
		if(!inFile.exists()){
			throw new Exception("被加密的文件不存在!");
		}		
		//空文件;
		if(inFile.length() == 0){
			throw new Exception("被加密的文件为空!");
		}
		
		File outFile = new File(dstFile);
		//
		if(!outFile.exists()){
			outFile.createNewFile();
		}
		
		//使用缓存的方式输入
		DataInputStream fin = new DataInputStream(
							  new BufferedInputStream(
							  new FileInputStream(inFile)));
		
		
		//使用缓存的方式输出
		DataOutputStream fout = new DataOutputStream(
								new BufferedOutputStream(
								new FileOutputStream(outFile)));
		
		
		//		
		byte nKeyIndex = genKeyIndex();
		
		//文件开始标志
		fout.write(String.valueOf(nKeyIndex).getBytes());
		fout.write(WIN_FILE_SIGNAL);		

		byte[] srcBuff = new byte[1024];
		int readLen = -1;
		//加密文件
		try {
			while(true){
				
				readLen = fin.read(srcBuff);
				if(readLen < 0){
					break;
				}
				
				fout.write(encrypt(srcBuff, readLen, nKeyIndex));
			}
		}catch(EOFException e){
			throw new Exception(e.getMessage());
		}finally{
			fout.flush();
			fin.close();
			fout.close();
		}
	}
	
	/**
	 * 解密文件(gkfxjmzj)
	 * @param srcFile
	 * @param dstFile
	 * @bFisrtLineEncrypt 文件内容的首行是密钥吗?
	 * @throws Exception
	 */
	public static void Decrypt(String srcFile, String dstFile, boolean bKeyIsFirstLine) throws Exception{
		
		File inFile = new File(srcFile);
		if(!inFile.exists()){
			throw new Exception("被解密的文件不存在!");
		}
		
		//空文件;
		if(inFile.length() == 0){
			throw new Exception("被解密的文件为空!");
		}
		
		File outFile = new File(dstFile);
		//判断文件能否打开
		if(!outFile.exists()){
			outFile.createNewFile();
		}

		//
		outFile.createNewFile();		
		//使用缓存的方式输入
		DataInputStream fin = new DataInputStream(
							  new BufferedInputStream(
							  new FileInputStream(inFile)));
		
		
		//使用缓存的方式输出
		DataOutputStream fout = new DataOutputStream(
								new BufferedOutputStream(
								new FileOutputStream(outFile)));
		
		
		byte keyIndex = 0;
		//读文件的首行
		if(!bKeyIsFirstLine){
			//读文件的首行,直接写入文件;
			String line = readLine(fin);
			if(line == null || line.trim().length() == 0){
				throw new Exception("文件格式错误!");
			}
			//
			line += "\r\n";
			fout.write(line.getBytes());
		}
		
		//读密钥
		keyIndex = (byte)readFileSignal(fin);
		if(keyIndex > ENCRYPT_KEY.length || keyIndex < 0){
			throw new Exception("文件格式错误!");
		}
		
		byte[] srcBuff = new byte[1024];
		int readLen = -1;
		//解密文件
		try{
			while(true){				
				readLen = fin.read(srcBuff);
				if(readLen < 0){
					break;
				}
				
				fout.write(decrypt(srcBuff, readLen, keyIndex));				
			}
		}catch(EOFException e){
			throw new Exception(e.getMessage());
		}finally{
			fin.close();
			fout.flush();
			fout.close();
		}
	}
	

	/**
	 * @deprecated
	 * gkjmzjfl
	 * @param inFileName
	 * @param outFileName
	 * @param key
	 * @return
	 */
	public static void EncryptUnix(String srcFile, String dstFile) throws Exception{
		//判断文件能否打开		
		File inFile = new File(srcFile);
		if(!inFile.exists()){
			throw new Exception("被加密的文件不存在!");
		}
		//空文件;
		if(inFile.length() == 0){
			throw new Exception("被加密的文件为空!");
		}
		
		File outFile = new File(dstFile);
		//
		if(!outFile.exists()){
			outFile.createNewFile();
		}
		
		//使用缓存的方式输入
		DataInputStream fin = new DataInputStream(
							  new BufferedInputStream(
							  new FileInputStream(inFile)));
		
		
		//使用缓存的方式输出
		DataOutputStream fout = new DataOutputStream(
								new BufferedOutputStream(
								new FileOutputStream(outFile)));
		
		//
		byte keyIndex = genKeyIndex();

		byte firstLine = 0;
		byte srcByte;
		byte dstByte;
		//
		byte keyBytes[] = ENCRYPT_KEY[keyIndex][0].getBytes(); 
		int keyBytesIdx = 0;
		
		try{
			while(true){
				//
				srcByte = fin.readByte();
				
				if(firstLine == 2){
					dstByte = xor(srcByte, keyBytes[keyBytesIdx++ % KEY_LENGTH]);	
					//
					if(keyBytesIdx == KEY_LENGTH){
						keyBytesIdx = 0;
					}
				}else{
					dstByte = srcByte;
				}
				
				fout.write(dstByte);
				
				//
				if(dstByte == 13 && firstLine == 0){
					firstLine = 1;
				}
				
				if(dstByte == 10 && firstLine == 1){
					fout.write(keyIndex);
					firstLine = 2;
				}
			}
		}catch(EOFException e){
			
		}
		
		fin.close();
		fout.close();
	}
	
	/**
	 * @deprecated
	 * 原名:DLL_Encrypt
	 * @param inKey : 密钥
	 * @param inData: 被加密或解密的数据
	 * @param bFlag : true 使用 inKey 对 inData 加密
	 * 				  false 使用 inKey 对 inData 解密;
	 * @return
	 */
	
	public static String Encrypt(String inKey, String inData, boolean bFlag) throws Exception {
		
		if(inKey == null || inKey.trim().length() == 0 || 
			inData == null || inData.trim().length() == 0){			
			throw new Exception("密钥和数据不能为空!");
		}
		//
		byte[] keyBytes = inKey.getBytes();
		byte[] dataBytes = inData.getBytes();
		
		int keyLen = keyBytes.length;
		int dataLen = dataBytes.length;
		
		ByteBuffer buff = null;
		
		//计算key的和
		int keySum = 0;
		for(int i = 0; i < keyLen; i++){
			keySum += keyBytes[i];
		}
		
		//
		int keyValue = 0;
		//加密
		if(bFlag){
			//
			buff = ByteBuffer.allocate(dataLen * 5);
			//
			for(int i = 0; i < dataLen; i++){
				keyValue = keySum;
				//
				keyValue += dataBytes[i];		
				//
				keyValue ^= keyBytes[0];
				//
				buff.put(String.format("%05d", keyValue).getBytes());
			}
		} else {
			
			//解密
			String subData = "";
			//被加密后的数据是5的整数倍
			if(dataLen % 5!=0){
				throw new Exception("数据格式错误!");
			}
			//实际数据的长度
			dataLen = dataLen / 5;
			buff = ByteBuffer.allocate(dataLen);
			
			//
			for(int i = 0; i < dataLen; i++)
			{
				subData = inData.substring(i * 5, (i + 1) * 5);
				//
				keyValue = Integer.valueOf(subData).intValue();
				//
				keyValue ^= keyBytes[0];
				//
				keyValue -= keySum;
				//				
				buff.put((byte)keyValue);
			}
		}
		
		return new String(buff.array());
	}
	
	
	/**
	 * 对字符串加密(gkjmzjstr)
	 * @param srcStr
	 * @param sinal : 分节符类型 字符类型和文件类型
	 * @return
	 * @throws Exception
	 */
	private static String encryptStr(String srcStr, byte sinal[]) throws Exception{		
		if(srcStr == null || srcStr.trim().length() == 0){
			throw new Exception("被加密的字符串不能为空!");
		}
		
		//取密钥
		byte keyIndex = genKeyIndex();
		
		//取字节流
		byte srcBytes[] = srcStr.getBytes();
		ByteBuffer buff = ByteBuffer.allocate(srcBytes.length + 2);
		
		//写密钥标志
		buff.put(sinal);
		
		//
		buff.put(encrypt(srcBytes, srcBytes.length, keyIndex));
		
		return Integer.toString(keyIndex)+ new String(buff.array());
	}
	
	/**
	 * 对字节数组加密
	 * @param srcBytes
	 * @param nSrcBytes
	 * @param keyIndex
	 * @return
	 * @throws Exception
	 */
	private static byte[] encrypt(byte[] srcBytes, int nSrcBytes, byte keyIndex) throws Exception{
		ByteBuffer buff = ByteBuffer.allocate(nSrcBytes);		
		//加密
		byte keyBytes[] = ENCRYPT_KEY[keyIndex][0].getBytes();
		int  keyByteIdx = 0;
		for(int i = 0; i< nSrcBytes; i++) {
			buff.put(xor(srcBytes[i], keyBytes[keyByteIdx++]));
			//
			if(keyByteIdx == KEY_LENGTH){
				keyByteIdx  = 0;
			}
		}
		
		return buff.array();
	}
	
	/**
	 * 对字节数据解密
	 * @param srcBytes
	 * @param nSrcBytes
	 * @param keyIndex
	 * @return
	 * @throws Exception
	 */
	private static byte[] decrypt(byte[] srcBytes, int nSrcBytes, byte keyIndex) throws Exception {
		//校验密钥索引
		if(keyIndex > 60) {
			throw new Exception("字符串格式错误!");
		}

		//解密
		ByteBuffer outBuff = ByteBuffer.allocate(nSrcBytes);
		byte keyItems[] = ENCRYPT_KEY[keyIndex][0].getBytes();
		int keyItemIdx = 0;		
		for(int i = 0; i < nSrcBytes; i++)
		{
			outBuff.put(xor(srcBytes[i], keyItems[keyItemIdx++]));
			
			if(keyItemIdx == KEY_LENGTH){
				keyItemIdx  = 0;
			}
		}

		return outBuff.array();
	}
	
	
	/**
	 * 使用 格林威治标准时间作为随机数的种子,生成密钥索引
	 * @return
	 */
	private static byte genKeyIndex(){
		//生成随机数
		Random rand = new Random(Calendar.getInstance().getTimeInMillis());
		long randValue = rand.nextInt();
		
		//取无符号数据;
		if(randValue < 0){
			randValue = (0xFFFFFFFFL + randValue) + 1;
		}
		
		//取模
		Long result = randValue % 60;
		
		//
		return result.byteValue();
	}
	
	/**
	 * 异或操作(不能对字节进行异或操作,所以添加该方法)
	 * @param src1
	 * @param src2
	 * @return
	 */
	private static byte xor(byte src1, byte src2){
		int result = Byte.valueOf(src1).intValue() ^ Byte.valueOf(src2).intValue();		
		return Integer.valueOf(result).byteValue(); 
	}
	
	/**
	 * 取文件头部的标志
	 * @param fin
	 * @return
	 * @throws IOException
	 * Windows中使用'\r\n'(0xD 0xA)回车换行, Linux 或 Unix 中使用'\n'(0xA)表示回车换行;
	 */
	private static int readFileSignal(DataInputStream fin) throws IOException{

		String sIndex = readKeyIndex(fin);
		if(sIndex != null){
			return Integer.parseInt(sIndex);
		}else{
			return -1;
		}
	}
	
	/**
	 * 取文件头部的标志
	 * @param fin
	 * @return
	 * @throws IOException
	 */
	private static int readStrSignal(String fin) throws IOException{

		String sIndex = readKeyIndex(fin);
		if(sIndex != null){
			return Integer.parseInt(sIndex);
		}else{
			return -1;
		}
	}
	
	/**
	 * 取文件中密钥的索引
	 * @param fin
	 * @return
	 * @throws IOException
	 */
	private static String readKeyIndex(DataInputStream fin) throws IOException {
		char c = 0;
		String sIndex = "";
		int len = 0;

		//索引 + 标记不超过 6 个字节
		while(len < 6){				
			c = (char)fin.readByte();
			len++;
			
			if(c == '\n' || c == '\r'){
				if(c == '\r'){
					c = (char)fin.readByte();
					len++;
					if(c == '\n'){
						return sIndex;
					}else{
						sIndex += c;
					}
				}else{
					return sIndex;
				}
			}else{
				sIndex += c;
			}				
		}
		
		return null;
	}
	
	/**
	 * 取文件中密钥的索引
	 * @param lines
	 * @return
	 * @throws IOException
	 */
	private static String readKeyIndex(String lines) throws IOException {
		char c = 0;
		String sIndex = "";
		int len = 0;

		//索引 + 标记不超过 6 个字节, 由密钥数组大小决定
		while(len < 6){				
			c = lines.charAt(len++);
			
			if(c == '\n' || c == '\r'){
				if(c == '\r'){
					c = lines.charAt(len++);
					if(c == '\n'){
						return sIndex;
					}else{
						sIndex += c;
					}
				}else{
					return sIndex;
				}
			}else{
				sIndex += c;
			}				
		}
		
		return null;
	}
	
	
	/**
	 * 取文件中密钥的索引
	 * @param fin
	 * @return
	 * @throws IOException
	 */
	private static String readLine(DataInputStream fin) throws IOException {
		char c = 0;
		String sLine = "";
		int len = 0;

		try{		
			//索引 + 标记不超过 6 个字节
			while(true){
				c = (char)fin.readByte();
				len++;
				
				if(c == '\n' || c == '\r'){
					if(c == '\r'){
						c = (char)fin.readByte();
						len++;
						if(c == '\n'){
							return sLine;
						}else{
							sLine += c;
						}
					}else{
						return sLine;
					}
				}else{
					sLine += c;
				}				
			}
		}catch(EOFException e){
			return sLine;
		}
	}
}

你可能感兴趣的:(C++,c,linux,windows,C#)