自定义协议-加密与解析

网上经常要用到数据加密的功能,自定义协议加密解析往往才是安全的。

最近上班也在弄这个东东,闲话不多说。


一、基础自定义协议

协议组成结构

协议组成结构为:起始符 标题 账号 密码 时间 校验码 结束符。


起始结束符

所有的协议开始和结束符都采用BE开始BE结束。

(这里可以由自己设计,如果涉及到同时发送多条协议的时候或者有出现协议不完整等情况。可以采用代替:如中间BE用BD02表示,BD用BD01表示


标题

标题规则属性:协议类型+协议长度+账号长度+密码长度

协议类型:01 = 用户聊天工具登录类型

协议长度:整条协议的总字符长度。

账号长度:账号字符长度。

密码长度:密码字符长度。

 

标题采用字符长度8存储各信息。每两个字符采用十六进制以字符的方式表达。

例如:011C0A0B

01:协议聊天工具登录类型。

1C:十六进制转十进制等于28,代表该协议总字符长度为28

0A:同上,账号长度为10

0B:同上,密码长度为11


账号密码

账号密码采用DES加密后字符串。


时间

时间格式yyyyMMddHHmmss进行DES加密后的字符串。


校验码

校验码为协议体(不包含校验码,起始结束符)按照字符两位向后异或最后所得的十六进制字符。



二、协议生成

第一步:

账号、密码、时间进行DES加密。然后存储各个加密后的字符长度。


第二步:

组装协议标题,把各个长度转换成十六进制,填充标题。

注:总长度为=账号密码时间总长度 起始结束长度4 + 校验码长度2 + 标题长度8


第三步:

从标题到时间的进行异或得出校验码。


第四步:

加上起始结束符,并组装整个协议字符串。


 

三、协议解析

第一步:

判断协议起始结束字符是否有效。


第二步:

获取协议校验码(倒数3,4位),获取协议体(第3位开始到倒数第5位)进行异或和比较,判断协议是否有效。


第三步:

获取协议标题(第310位),得出协议体属性。


第四步:

根据协议体属性,获取账号密码时间,进行DES解密。



这只是个基础的协议,需要复杂的可以在这个基础上根据自己的需求更改添加更多的复杂属性。




四、代码


DES加密工具类(ps:该代码网上的,已经不知道是谁写的了)


package com.util;


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


import javax.crypto.Cipher;


/**
 * 
 * 数据加密解密
 * 
 * @author Administrator
 *
 */
public class DesUtils {
/** 字符串默认键值 */
private static String strDefaultKey = "national";


/** 加密工具 */
private Cipher encryptCipher = null;


/** 解密工具 */
private Cipher decryptCipher = null;


/**
* 将byte数组转换为表示16进制值的字符串, 如:byte[]{8,18}转换为:0813

* , 和public static byte[] hexStr2ByteArr(String strIn) 互为可逆的转换过程

* @param arrB
*            需要转换的byte数组
* @return 转换后的字符串
* @throws Exception
*             本方法不处理任何异常,所有异常全部抛出
*/
public static String byteArr2HexStr(byte[] arrB) throws Exception {
int iLen = arrB.length;
// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
// 把负数转换为正数
while (intTmp < 0) {
intTmp = intTmp + 256;
}
// 小于0F的数需要在前面补0
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}


/**
* 将表示16进制值的字符串转换为byte数组, 和public static String

* byteArr2HexStr(byte[] arrB) 互为可逆的转换过程

* @param strIn
*            需要转换的字符串
* @return 转换后的byte数组
* @throws Exception
*             本方法不处理任何异常,所有异常全部抛出
* @author <a href="mailto:leo841001@163.com">LiGuoQing</a>
*/
public static byte[] hexStr2ByteArr(String strIn) throws Exception {
byte[] arrB = strIn.getBytes();
int iLen = arrB.length;


// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
byte[] arrOut = new byte[iLen / 2];
for (int i = 0; i < iLen; i = i + 2) {
String strTmp = new String(arrB, i, 2);
arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
}
return arrOut;
}


/**
* 默认构造方法,使用默认密钥

* @throws Exception
*/
public DesUtils() throws Exception {
this(strDefaultKey);
}


/**
* 指定密钥构造方法

* @param strKey
*            指定的密钥
* @throws Exception
*/
public DesUtils(String strKey) throws Exception {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
Key key = getKey(strKey.getBytes());


encryptCipher = Cipher.getInstance("DES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);


decryptCipher = Cipher.getInstance("DES");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
}


/**
* 加密字节数组

* @param arrB
*            需加密的字节数组
* @return 加密后的字节数组
* @throws Exception
*/
public byte[] encrypt(byte[] arrB) throws Exception {
return encryptCipher.doFinal(arrB);
}


/**
* 加密字符串

* @param strIn
*            需加密的字符串
* @return 加密后的字符串
* @throws Exception
*/
public String encrypt(String strIn) throws Exception {
return byteArr2HexStr(encrypt(strIn.getBytes()));
}


/**
* 解密字节数组

* @param arrB
*            需解密的字节数组
* @return 解密后的字节数组
* @throws Exception
*/
public byte[] decrypt(byte[] arrB) throws Exception {
return decryptCipher.doFinal(arrB);
}


/**
* 解密字符串

* @param strIn
*            需解密的字符串
* @return 解密后的字符串
* @throws Exception
*/
public String decrypt(String strIn) throws Exception {
return new String(decrypt(hexStr2ByteArr(strIn)));
}


/**
* 从指定字符串生成密钥,密钥所需的字节数组长度为8位 不足8位时后面补0,

* 超出8位只取前8位

* @param arrBTmp
*            构成该字符串的字节数组
* @return 生成的密钥
* @throws java.lang.Exception
*/
private Key getKey(byte[] arrBTmp) throws Exception {
// 创建一个空的8位字节数组(默认值为0)
byte[] arrB = new byte[8];


// 将原始字节数组转换为8位
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}


// 生成密钥
Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");


return key;
}




public static void main(String[] args) {
try {
String test = "2015043095115";
DesUtils des = new DesUtils("S2");// 自定义密钥
System.out.println("加密前的字符:" + test);
System.out.println("加密后的字符:" + des.encrypt(test));
System.out.println("解密后的字符:" + des.decrypt(des.encrypt(test)));
} catch (Exception e) {
e.printStackTrace();
}
}
}


字符串、字节、异或工具类:


package com.util;


public class StringByteUtil {


/**
* 字符串转化为十六进制字节数组
* @param str
* @return
*/
public static byte[] getByteByString(String hexString){
hexString = hexString.toLowerCase();
final byte[] byteArray = new byte[hexString.length() / 2];
int k = 0;
for (int i = 0; i < byteArray.length; i++) {
// 因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
byteArray[i] = (byte) (high << 4 | low);
k += 2;
}
return byteArray;
}

/**
* 十六进制字节数组异或
* @param bytes
* @return
*/
public static Byte getXorByBytes(byte[] val){
byte b = val[0];
for (int i = 1, length = val.length; i < length; i++) {
b ^= val[i];
}
return b;
}


/**
* 十六进制字节数组异或 最后一个字节不进行异或
* @param bytes
* @return
*/
public static Byte getXorByBytes2(byte[] val){
byte b = val[0];
for (int i = 1, length = val.length-1; i < length; i++) {
b ^= val[i];
}
return b;
}

/**
* 十六进制字节数组转换为字符串
* @param bytes
* @return
*/
public static String getStringByBytes(byte[] b){
String hexString = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = "0" + hex;
}
hexString += hex;
}
return hexString.toUpperCase();
}

/**
* 单个16进制字节转字符串
* @param b
* @return
*/
public static String getStringByByte(byte b){
String hexString = "";
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
hex = "0" + hex;
}
hexString += hex;
return hexString.toUpperCase();
}


public static void main(String[] a){
String aa = "C8600084AB3506";
byte[] b = getByteByString(aa);
byte[] bs = new byte[b.length+1];
for(int i = 0,j=b.length;i<j;i++){
bs[i] = b[i];
}
bs[bs.length-1] = getXorByBytes(b);
 
System.out.println(bs[bs.length-1]);
 
aa = getStringByBytes(bs);
 
 
System.out.println(aa);
 
aa = "C8600084AB3506B4";
 
 
// byte[] b = getByteByString(aa);
// byte[] bs = {getXorByBytes(b)};
// System.out.println( getStringByBytes(bs) );
}
}



解密协议:


package com.util;


import javax.crypto.BadPaddingException;


/**
 * 协议解析
 * @author Administrator
 *
 */
public class AgreementAnalysisUtil {



private static int length = 0;
private static DesUtils du = null;

/**
* 解析协议
* @param agreement
* @param desKey
* @return  String[] null:无效协议 、 string[0] 0:协议校验失败   1:成功   、 string[1]:账号  、 string[2]:密码  、string[3]:时间
*/
public static String[] analysis(String agreement,String desKey){
try {
length = agreement.length();
String startstr = agreement.substring(0,2);
String endstr = agreement.substring(length - 2, length);

//检测协议起始结束符
if("AE".equals(startstr) && "AE".equals(endstr)){
String str[] = new String[4];
//检测校验码
if(checkCode(agreement)){
du = new DesUtils(desKey);

//根据标题内容获取属性
String title = agreement.substring(2, 10);

int unamellength = Integer.valueOf(title.substring(4, 6), 16);
int upassllength = Integer.valueOf(title.substring(6, 8), 16);

String uname = agreement.substring(10, unamellength + 10);
String upass = agreement.substring(unamellength + 10, upassllength + unamellength + 10);
String time = agreement.substring(upassllength + unamellength + 10,length - 4);

str[0] = "1";
str[1] = du.decrypt(uname);
str[2] = du.decrypt(upass);
str[3] = du.decrypt(time);
}else{
str[0] = "0";
}
return str;
}
}catch(BadPaddingException bpe){
//根据desKey解密失败   desKey错误
}catch (Exception e) {
e.printStackTrace();
}
return null;
}


/**
* 对比校验码,判断协议是否有效
* @return
*/
private static boolean checkCode(String agreement){
String code = agreement.substring(length - 4, length -2);
String content = agreement.substring(2, length -4);

byte[] b = StringByteUtil.getByteByString(content);
byte bs = StringByteUtil.getXorByBytes(b);
String code2 = StringByteUtil.getStringByByte(bs);

if(code.equals(code2)){
return true;
}
return false;
}

public static void main(String[] args) {
String str = "AE016e2020007ef1053ed1e4b530aafdfd31ec063a800be463969b1b2ec994e944419f7934a7c5fdd53ce2448feb6201d8b5342079A0AE";
String[] s = analysis(str, "passport");
for (int i = 0; i < s.length; i++) {
System.out.println(s[i]);
}
}
}



加密协议:


package com.tbynet.sooeso.passport.util;


/**
 * 协议加密
 * @author Administrator
 *
 */
public class AgreementEncryptionUtil {



private static DesUtils du = null;


/**
* 生成协议
* @param desKey DES加密KEY
* @param uname账号
* @param upass密码
* @param time 时间   格式(yyyyMMddHHmmss)
* @return
*/
public static String getAgreement(String desKey,String uname,String upass,String time){
try {
du = new DesUtils(desKey);
//加密
uname = desEncryption(uname);
upass = desEncryption(upass);
time = desEncryption(time);
//组装标题
String title = createTitle(uname.length(), upass.length(), time.length());
//生成效验码
String content = title+uname+upass+time;
String code = createCheckCode(content);

//完整协议
String agreement = "AE" + content + code +"AE";

du = null;
return agreement;
} catch (Exception e) {
du = null;
e.printStackTrace();
}
return null;
}


/**
* 根据协议体 异或得出效验码
* @param content
* @return
*/
private static String createCheckCode(String content){
byte[] b = StringByteUtil.getByteByString(content);
byte bs = StringByteUtil.getXorByBytes(b);
return StringByteUtil.getStringByByte(bs);
}


/**
* 创建标题
* @param unameLength
* @param upassLength
* @param timeLength
* @return
*/
private static String createTitle(int unameLength,int upassLength,int timeLength){
String type ="01";
String allLength = Integer.toHexString(unameLength+upassLength+timeLength+8+2+4);
String unamelstr = Integer.toHexString(unameLength);
String upasslstr = Integer.toHexString(upassLength);
return type+allLength+unamelstr+upasslstr;
}

/**
* des加密数据
* @param str
* @return
* @throws Exception
*/
private static String desEncryption(String str) throws Exception{
return du.encrypt(str);
}


public static void main(String[] args) {
System.out.println(getAgreement("spark", "zhoulieqing@qq.com", "12345678", "20150424084610"));
}
}



最后:转载请说明出处,小弟第一次写东西不容易。


已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页