`
f543711700
  • 浏览: 322856 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Tools.java

 
阅读更多
[size=x-large][size=large]
package com.ghca.policeintf;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;

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

public class Tools {

	public static String constant_encoding = "gbk";
	
	private static ThreadLocal threadLocal = new ThreadLocal();
	public static ThreadLocal getThreadLocal() {
		return threadLocal;
	}

	public static int unsignedByte(byte b)
	{
		return 0x000000ff & (int)b;
	}
	
	
	
	public static byte[] int2byteArr(int i) {
		ByteBuffer bb = ByteBuffer.allocate(4);
		bb.putInt(i);
		return bb.array();
	}
	
	public static byte[] short2byteArr(short i) {
		ByteBuffer bb = ByteBuffer.allocate(2);
		bb.putShort(i);
		return bb.array();
	}
	
	
	public static int byteArr2unsignedInt(byte[] arr) throws Exception {
		if(arr == null) {
			throw new Exception("byteArr2unsignedInt() find arr is null");
		}
		if(arr.length > 4 || arr.length <=0 ) {
			throw new Exception("byteArr2unsignedInt() find arr.length invalid:" + arr.length);
		}
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(arr));
		int r = -2000;
		if(arr.length == 1) {
			r = dis.readUnsignedByte();
		} else if(arr.length == 2) {
			r = dis.readUnsignedShort();
		} else if(arr.length == 3) {
			byte[] newarr = new byte[] {0x00,arr[0],arr[1],arr[2]};
			dis.close();
			dis = null;
			dis = new DataInputStream(new ByteArrayInputStream(newarr));
			r = dis.readInt();
		} else {
			r = dis.readInt();
		}
		dis.close();
		dis = null;
		if(r < 0) {
			throw new Exception("byteArr2unsignedInt() find int result < 0 : " + r);
		}
		return r;
	}
	
	
	public static void log(String log,Exception e) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(sdf.format(new Date()) + " " + log);
		if(e != null) {
			e.printStackTrace(System.out);
		}
	}
	
	
	/**
	 * 检查ber编码是不定长、长定长还是短定长,并返回value的长度
	 * @param buf
	 * @param whatLen
	 * @throws Exception
	 */
	public static int checkBerLen(ByteBuffer buf,String whatLen) throws Exception {
		byte len = buf.get();
		
		//不定长方式这个字节固定是0x80
		//但是在java里面byte的0x80应该是-128,所以这里进行了一个无符号的转换,后续同理
		int  intLen = unsignedByte(len);
		if(intLen == 0x80) {
			throw new Exception(whatLen + " find len is 0x80:" + len);
		}
		
		if((intLen & 128) == 128) {//高位等于1->长定长
			Tools.log(whatLen + " find long fix len:" + len, null);
			//取出低7位查看后续有多少个字节的 len
			int nextLen = intLen & 127;
			if(nextLen > 2) {//后续的len超过2个字节,则认为错误
				throw new Exception(whatLen + " find next-len too long:" + len);
			} else {
				byte[] lenValueArr = new byte[nextLen];
				buf.get(lenValueArr, 0, nextLen);//执行这个之后,buf会向后移动nextLen个字节,指向value的开头
				int lenValue = byteArr2unsignedInt(lenValueArr);
				return lenValue;
			}
		} else if((intLen & 128) == 0) {//高位等于0 -> 短定长
			//取出低7位得到value的长度
			return intLen & 127;
		} else {
			throw new Exception(whatLen + " find neither long fix len nor short fix len:" + len);
		}
	}
	
	
	/**
	 * 检查该字节是否是context-specific,并返回context-specific的低5位的值, 从而对应文档
	 * @param buf
	 * @param what
	 * @return
	 * @throws Exception 
	 */
	public static int checkBerContextSpecific(ByteBuffer buf,String what) throws Exception {
		byte type = buf.get();
		int  intType = unsignedByte(type);
		
		if((intType & 192) != 128) {//取高两位看是不是 10 (context-specific)
			throw new Exception(what + " not context-specific:" + type);
		}
		
		//取低5位作为context-specific的值返回
		return (intType & 31);
	}
	
	
	public static byte[] md5(byte[] b) throws NoSuchAlgorithmException
	{
		byte[] val = null;
		MessageDigest md5 = MessageDigest.getInstance("md5");
		val = md5.digest(b);
		return val;
	}
	
	
	/**
	 * 比较两个byte数组是否相等
	 * @param a
	 * @param b
	 * @return
	 */
	public static boolean compareByteArr(byte[] a,byte[] b) {
		if(a.length != b.length) {
			return false;
		}
		for(int i = 0; i < a.length; i++) {
			if(a[i] != b[i]) {
				return false;
			}
		}
		return true;
	}
	
	
	
	public static byte[] encodeBer(byte tag,byte[] valueArr) throws Exception {
		if(valueArr.length <= 127) {//短定长
			ByteBuffer bb = ByteBuffer.allocate(1+1+valueArr.length);
			bb.order(ByteOrder.BIG_ENDIAN);
			bb.put(tag);
			bb.put((byte)valueArr.length);
			bb.put(valueArr);
			return bb.array();
		} else {//长定长
			if(valueArr.length <= 255) {//长定长--长度字段占两个字节
				ByteBuffer bb = ByteBuffer.allocate(1+2+valueArr.length);
				bb.order(ByteOrder.BIG_ENDIAN);
				bb.put(tag);
				bb.put((byte)0x81);//0x81:二进制高位为1(长定长),低7位值为1,代表后续有一个字节的len
				bb.put((byte)valueArr.length);//这个字节存放value的具体长度
				bb.put(valueArr);
				return bb.array();
			} else if(valueArr.length <= 65535) {//长定长--长度字段占三个字节
				ByteBuffer bb = ByteBuffer.allocate(1+3+valueArr.length);
				bb.order(ByteOrder.BIG_ENDIAN);
				bb.put(tag);
				bb.put((byte)0x82);//0x82:二进制高位为1(长定长),低7位值为2,代表后续有两个字节的len
				bb.putShort((short)valueArr.length);//这两个字节存放value的具体长度
				bb.put(valueArr);
				return bb.array();
			} else if(valueArr.length <= 16777215) {//长定长--长度字段占四个字节
				ByteBuffer bb = ByteBuffer.allocate(1+4+valueArr.length);
				bb.order(ByteOrder.BIG_ENDIAN);
				bb.put(tag);
				bb.put((byte)0x83);//0x83:二进制高位为1(长定长),低7位值为3,代表后续有三个字节的len
				//注意这里的实现
				//1.先将valueArr.length作为一个int值写入一个byte[]
				//2.然后获取到这个byte[]并将最高字节删除掉(其实最高字节就是0)放到另外一个byte[]中,则新的byte[]只剩下三个字节,就是长度值的三个字节
				//3.最后再将新的三个字节的byte[]填充到目标ByteBuffer里面去
				ByteBuffer tmpBuf = ByteBuffer.allocate(4);
				tmpBuf.putInt(valueArr.length);
				byte[] tmpByteArr = tmpBuf.array();
				byte[] inputLenArr = new byte[] {tmpByteArr[1],tmpByteArr[2],tmpByteArr[3]};
				bb.put(inputLenArr);
				bb.put(valueArr);
				return bb.array();
			} else {//长定长--长度字段超过4个字节,直接报错,因为此时的value值太大
				throw new Exception("encodeBer() find value.length too long:" + valueArr.length);
			}
		}
	}
	
	
	
	
	public static String toHex(byte[] v)
	{
		String vs = "";
		for(int i = 0; i < v.length - 1; i++)
		{
			vs += byteHEX(v[i]) + ",";
		}
		if(v.length >= 1)
			vs += byteHEX(v[v.length - 1]);
		return vs;
	}
	
	
	public static String byteHEX(byte ib) 
	{
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F' };
		char[] ob = new char[2];
		ob[0] = Digit[(ib >>> 4) & 0X0F];
		ob[1] = Digit[ib & 0X0F];
		String s = new String(ob);
		return "0x" + s;
	}
	
	
	
	/**
	 * 合并多个字节数组成为一个字节数组,多个字节数组存放在vector里面,按存入vector的顺序合并
	 * 即:先存入vector的合并之后在结果数组的前面
	 * @param v
	 * @return
	 * @throws Exception
	 */
	public static byte[] combineByteArr(Vector v) throws Exception {
		if(v == null || v.size() <= 0) {
			throw new Exception("combineByteArr() find vector is null or size() <= 0");
		}
		int totalLength = 0;
		for(int i = 0; i < v.size(); i++) {
			byte[] b = (byte[]) v.get(i);
			totalLength = totalLength + b.length;
		}
		byte[] resultArr = new byte[totalLength];
		int lastLen = 0;
		for(int i = 0; i < v.size(); i++) {
			byte[] tmpArr = (byte[]) v.get(i);
			System.arraycopy(tmpArr, 0, resultArr, lastLen, tmpArr.length);
			lastLen = lastLen + tmpArr.length;
		}
		return resultArr;
	}
	
	
	/**
	 * 3des加密算法
	 * @param keybyte
	 * @param src
	 * @return
	 * @throws Exception
	 */
	 public static byte[] encrypt3des(byte[] keybyte, byte[] src) throws Exception {
	    //生成密钥
		if(keybyte.length == 16) {//因为kc是16个字节,而java里面3des的key必须传入24个字节
			//根据3des算法,如果秘钥是16个字节,则后8个字节等于前8个字节,必须组成24个字节的秘钥
			byte[] b = new byte[24];
			System.arraycopy(keybyte, 0, b, 0, 16);
			System.arraycopy(keybyte, 0, b, 16, 8);
			keybyte = b;
		}
	    SecretKey deskey = new SecretKeySpec(keybyte,"DESede");
	    //加密
	    Cipher c1 = Cipher.getInstance("DESEDE/ECB/nopadding");
	    c1.init(Cipher.ENCRYPT_MODE, deskey);
	    
	    //因为采用nopadding加密填充算法,所以明文字节长度必须是8的倍数
	    //如果明文字节长度不是8的倍数,则在后面填补0xff(这是双方约定好的)
	    int mod = src.length % 8;
	    if(mod != 0) {//则需要填补(8-mod)个0xff
	    	int paddingLen = 8 - mod;
	    	byte[] paddingByte = new byte[paddingLen];
	    	for(int i = 0; i < paddingLen; i++) {
	    		paddingByte[i] = (byte) 0xff;
	    	}
	    	Vector v = new Vector();
	    	v.add(src);
	    	v.add(paddingByte);
	    	src = combineByteArr(v);
	    }
	    
	    return c1.doFinal(src);
	 }

	 
	 /**
	  * 3des解密算法
	  * @param keybyte
	  * @param src
	  * @return
	  * @throws Exception
	  */
     public static byte[] decrypt3des(byte[] keybyte, byte[] src) throws Exception {      
        //生成密钥
 		if(keybyte.length == 16) {//因为kc是16个字节,而java里面3des的key必须传入24个字节
 			//根据3des算法,如果秘钥是16个字节,则后8个字节等于前8个字节,必须组成24个字节的秘钥
 			byte[] b = new byte[24];
 			System.arraycopy(keybyte, 0, b, 0, 16);
 			System.arraycopy(keybyte, 0, b, 16, 8);
 			keybyte = b;
 		}
        SecretKey deskey = new SecretKeySpec(keybyte, "DESede");
        //解密
        Cipher c1 = Cipher.getInstance("DESEDE/ECB/nopadding");
        c1.init(Cipher.DECRYPT_MODE, deskey);
        return c1.doFinal(src);
     }
	
	
     /**
      * 接口的MD5算法,输入字节不够64个字节要用0xff补够64个字节
      * 传入的vector里面只需要存入有效的字节,该方法会自动补齐64个字节
      * @param v
      * @return
      * @throws Exception
      */
     @SuppressWarnings("unchecked")
	public static byte[] interfaceMd5(Vector v) throws Exception {
    	byte[] b = combineByteArr(v);
    	 
    	//协议上规定MD5输入如果不够64个字节则要用0xff补够64个字节
		int validLen = b.length;
		if(validLen < 64) {
			int paddingLen = 64 - validLen;
			byte[] paddingByte = new byte[paddingLen];
			for(int i = 0; i < paddingLen; i++) {
				paddingByte[i] = (byte) 0xff;
			}
			v.add(paddingByte);
		} else if(validLen == 64) {
			Tools.log("interfaceMd5() find validLen == 64,NoPadding", null);
		} else {
			throw new Exception("interfaceMd5() find validLen > 64");
		}
		
		b = combineByteArr(v);
		return md5(b);
		
     }
     
     
     private static Properties p = null;
     
     public static String getConfig(String configName) throws FileNotFoundException, IOException {
    	 if(p == null) {
    		 p = new Properties();
        	 p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
    	 }
    	 return p.getProperty(configName);
     }
     
     
     public static byte[] ipToByteArr(String ip) {
    	 String[] arr = ip.split("\\.");
    	 int a = Integer.parseInt(arr[0]);
    	 int b = Integer.parseInt(arr[1]);
    	 int c = Integer.parseInt(arr[2]);
    	 int d = Integer.parseInt(arr[3]);
    	 
    	 byte[] r = new byte[] {(byte) a,(byte) b,(byte) c,(byte) d};
    	 return r;
     }
     
     
	
}
[/size][/size]
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics