DES算法和Mac算法

关于DES和3DES算法,网上有很多实现和代码,也有在线的DES转换工具,也有下载下来的DES计算小工具,但是理解还不深,这里是工作需要使用,百度以后整理了一下:

关于DES和3DES

  1 package com.hm.com.util;
  2 
  3 import java.security.spec.KeySpec;
  4 
  5 import javax.crypto.Cipher;
  6 import javax.crypto.SecretKey;
  7 import javax.crypto.SecretKeyFactory;
  8 import javax.crypto.spec.DESKeySpec;
  9 import javax.crypto.spec.DESedeKeySpec;
 10 
 11 /**
 12  * simple introduction
 13  * 
 14  * <p>
 15  * detailed comment
 16  * @author zjj 2016-4-12
 17  * @see
 18  * @since 1.0
 19  */
 20 public class DesUtils
 21 {
 22     
 23     static String DES = "DES/ECB/NoPadding";
 24     static String TriDes = "DESede/ECB/NoPadding";
 25 
 26     /**
 27      * 把16进制字符串转换成字节数组
 28      * @param hex
 29      * @return
 30      */
 31     public static byte[] hexStringToBytes(String hex)
 32     {
 33         int len = (hex.length() / 2);
 34         byte[] result = new byte[len];
 35         char[] achar = hex.toCharArray();
 36         for (int i = 0; i < len; i++)
 37         {
 38             int pos = i * 2;
 39             result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
 40         }
 41         return result;
 42     }
 43 
 44     /**
 45      * 把字节数组转化为16进制字符串
 46      * @param bytes byte[]
 47      * @return String
 48      */
 49     public static String bytesToHexString(byte[] bytes)
 50     {
 51         String ret = "";
 52         for (int i = 0; i < bytes.length; i++)
 53         {
 54             String hex = Integer.toHexString(bytes[i] & 0xFF);
 55             if (hex.length() == 1)
 56             {
 57                 hex = '0' + hex;
 58             }
 59             ret += hex.toUpperCase();
 60         }
 61         return ret;
 62     }
 63     
 64     /**
 65      * 将字符转化为字节
 66      * @param c
 67      * @return
 68      * @author zjj 2016-4-12
 69      * @since 1.0
 70      */
 71     private static byte toByte(char c)
 72     {
 73         byte b = (byte) "0123456789ABCDEF".indexOf(c);
 74         return b;
 75     }
 76     
 77     /**单DES加密算法
 78      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
 79      * @param key 密钥,字节数组,长度为8
 80      * @param data 待加密的源数据,字节数组
 81      * @return
 82      * @author zjj 2016-4-12
 83      * @since 1.0
 84      */
 85     public static byte[] des_encrypt(byte key[], byte data[]) {
 86         try {
 87             KeySpec ks = new DESKeySpec(key);
 88             SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
 89             SecretKey ky = kf.generateSecret(ks);
 90             Cipher c = Cipher.getInstance(DES);
 91             c.init(Cipher.ENCRYPT_MODE, ky);
 92             return c.doFinal(data);
 93         } catch (Exception e) {
 94             e.printStackTrace();
 95             return null;
 96         }
 97     }
 98     
 99     /**单DES解密算法
100      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
101      * @param key 密钥,字节数组,长度为8
102      * @param data 待加密的源数据,字节数组
103      * @return
104      * @author zjj 2016-4-12
105      * @since 1.0
106      */
107     public static byte[] des_decrypt(byte key[], byte data[]) {
108         try {
109             KeySpec ks = new DESKeySpec(key);
110             SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
111             SecretKey ky = kf.generateSecret(ks);
112 
113             Cipher c = Cipher.getInstance(DES);
114             c.init(Cipher.DECRYPT_MODE, ky);
115             return c.doFinal(data);
116         } catch (Exception e) {
117             e.printStackTrace();
118             return null;
119         }
120     }
121     
122     /**
123      * 3DES加密算法
124      * @param keyStr String类型的密钥,在方法中会自动转化为字节数组 
125      * @param data byte[]待加密的源数据 
126      * @return byte[] 加密后的字节数组
127      * @author zjj 2016-4-12
128      * @since 1.0
129      */
130     public static byte[] trides_encrypt(String keyStr, byte data[]) {
131         
132         return trides_encrypt(hexStringToBytes(keyStr),data);
133         
134     }
135     /**
136      * 3DES加密算法
137      * @param keyStr String类型的密钥,在方法中会自动转化为字节数组 
138      * @param dataStr String类型的密钥,在方法中会自动转化为字节数组 
139      * @return byte[] 加密后的字节数组
140      * @author zjj 2016-4-12
141      * @since 1.0
142      */
143     public static byte[] trides_encrypt(String keyStr, String dataStr) {
144         
145         return trides_encrypt(hexStringToBytes(keyStr),hexStringToBytes(dataStr));
146         
147     }
148     /**
149      * 3DES加密算法
150      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
151      * @param key byte[]密钥,字节数组,长度固定为24
152      * @param data byte[]待加密的源数据 
153      * @return byte[] 加密后的字节数组
154      * @author zjj 2016-4-12
155      * @since 1.0
156      */
157     public static byte[] trides_encrypt(byte key[], byte data[]) {
158         try {
159             byte[] k = new byte[24];
160 
161             int len = data.length;
162             if(data.length % 8 != 0){
163                 len = data.length - data.length % 8 + 8;
164             }
165             byte [] needData = null;
166             if(len != 0)
167                 needData = new byte[len];
168             
169             for(int i = 0 ; i< len ; i++){
170                 needData[i] = 0x00;
171             }
172             
173             System.arraycopy(data, 0, needData, 0, data.length);
174             
175             if (key.length == 16) {
176                 System.arraycopy(key, 0, k, 0, key.length);
177                 System.arraycopy(key, 0, k, 16, 8);
178             } else {
179                 System.arraycopy(key, 0, k, 0, 24);
180             }
181 
182             KeySpec ks = new DESedeKeySpec(k);
183             SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
184             SecretKey ky = kf.generateSecret(ks);
185 
186             Cipher c = Cipher.getInstance(TriDes);
187             c.init(Cipher.ENCRYPT_MODE, ky);
188             return c.doFinal(needData);
189         } catch (Exception e) {
190             e.printStackTrace();
191             return null;
192         }
193     }
194     
195     /**
196      * 3DES解密算法
197      * @param keyStr String类型的密钥,在方法中会自动转化为字节数组 
198      * @param data byte[]待加密的源数据 
199      * @return byte[] 加密后的字节数组
200      * @author zjj 2016-4-12
201      * @since 1.0
202      */
203     public static byte[] trides_decrypt(String keyStr, byte data[]) {
204         
205         return trides_encrypt(hexStringToBytes(keyStr),data);
206         
207     }
208     /**
209      * 3DES解密算法
210      * @param keyStr String类型的密钥,在方法中会自动转化为字节数组 
211      * @param dataStr String类型的密钥,在方法中会自动转化为字节数组 
212      * @return byte[] 加密后的字节数组
213      * @author zjj 2016-4-12
214      * @since 1.0
215      */
216     public static byte[] trides_decrypt(String keyStr, String dataStr) {
217         
218         return trides_encrypt(hexStringToBytes(keyStr),hexStringToBytes(dataStr));
219         
220     }
221     /**
222      * 3DES解密算法
223      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
224      * @param key byte[]密钥,字节数组,长度固定为24
225      * @param data byte[]待加密的源数据 
226      * @return byte[] 加密后的字节数组
227      * @author zjj 2016-4-12
228      * @since 1.0
229      */
230     public static byte[] trides_decrypt(byte key[], byte data[]) {
231         try {
232             byte[] k = new byte[24];
233 
234             int len = data.length;
235             if(data.length % 8 != 0){
236                 len = data.length - data.length % 8 + 8;
237             }
238             byte [] needData = null;
239             if(len != 0)
240                 needData = new byte[len];
241             
242             for(int i = 0 ; i< len ; i++){
243                 needData[i] = 0x00;
244             }
245             
246             System.arraycopy(data, 0, needData, 0, data.length);
247             
248             if (key.length == 16) {
249                 System.arraycopy(key, 0, k, 0, key.length);
250                 System.arraycopy(key, 0, k, 16, 8);
251             } else {
252                 System.arraycopy(key, 0, k, 0, 24);
253             }
254             KeySpec ks = new DESedeKeySpec(k);
255             SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
256             SecretKey ky = kf.generateSecret(ks);
257             Cipher c = Cipher.getInstance(TriDes);
258             c.init(Cipher.DECRYPT_MODE, ky);
259             return c.doFinal(needData);
260         } catch (Exception e) {
261             e.printStackTrace();
262             return null;
263         }
264     }
265 
266 }

关于MAc算法

  1 package com.hm.com.util;
  2 
  3 import java.util.Arrays;
  4 
  5 /**
  6  * Mac工具类,采用ECB算法
  7  * @author zjj
  8  */
  9 public class MacEcbUtils
 10 {
 11     public static byte[] IV = new byte[8];
 12 
 13     /**
 14      * 两个字节异或
 15      * @param src
 16      * @param src1
 17      * @return
 18      * @author Administrator 2016-4-12
 19      * @since 1.0
 20      */
 21     public static byte byteXOR(byte src, byte src1)
 22     {
 23         return (byte) ((src & 0xFF) ^ (src1 & 0xFF));
 24     }
 25 
 26     /**
 27      * 分别将两个数组中下标相同的字节进行异或
 28      * <p>要求数组长度一致
 29      * @param src
 30      * @param src1
 31      * @return
 32      * @author Administrator 2016-4-12
 33      * @since 1.0
 34      */
 35     public static byte[] bytesXOR(byte[] src, byte[] src1)
 36     {
 37         int length = src.length;
 38         if (length != src1.length)
 39         {
 40             return null;
 41         }
 42         byte[] result = new byte[length];
 43         for (int i = 0; i < length; i++)
 44         {
 45             result[i] = byteXOR(src[i], src1[i]);
 46         }
 47         return result;
 48     }
 49 
 50     /**
 51      * mac计算,数据不为8的倍数,需要补0(64bit的mac算法)
 52      * <p>具体的步骤如下:
 53      * <p>1.源字节数组的长度应为8的倍数,否则补零至8的倍数,按8个字节分段(d0,d1,d2...)
 54      * <p>2.密钥key字节数组长度固定是8
 55      * <p>3.将key与第一段d0进行des[加密]运算,得到e1
 56      * <p>4.e1与d2进行异或运算得到x1
 57      * <p>5.key再与x1进行des[加密]运算,得到e2
 58      * <p>6.e2在于d3进行异或运算得到x2
 59      * <p>7.key再与x2进行des[加密],依次进行,直到将源数组加密完毕,最后的到的字节数组即是mac值
 60      * 
 61      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
 62      * @param key 密钥,字节数组长度应为16,多于16将会截取前16位,少于16位则补0
 63      * @param srcData 源数据
 64      * @return
 65      * @throws Exception 
 66      */
 67     public static byte[] computeMac(byte[] key, byte[] srcData) throws Exception
 68     {
 69         int length = srcData.length;
 70         int x = length % 8;
 71         int addLen = 0;
 72         if (x != 0)
 73         {
 74             addLen = 8 - length % 8;
 75         }
 76         int pos = 0;
 77         //保证data是8的倍数
 78         byte[] data = new byte[length + addLen];
 79         //data的值就是源数组的值(包括补零的值)
 80         System.arraycopy(srcData, 0, data, 0, length);
 81         //源数组第一段8字节
 82         byte[] oper1 = new byte[8];
 83         System.arraycopy(data, pos, oper1, 0, 8);
 84         pos += 8;
 85         //用于存储每段字节与ka加密后的结果数组
 86         byte[] be = new byte[8];
 87         for (int i = 0; i < data.length / 8; i++)
 88         {
 89             //将第一段oper1与ka进行des加密,得到be
 90             be = DesUtils.des_encrypt(key,oper1);
 91             
 92             if((i+1)*8 < data.length){
 93                 //将加密结果e1与第二段oper2异或
 94                 byte[] oper2 = new byte[8];
 95                 System.arraycopy(data, pos, oper2, 0, 8);
 96                 //得到异或结果bx
 97                 byte[] bx = bytesXOR(be, oper2);
 98                 oper1 = bx;
 99                 pos += 8;
100             }
101         }
102         return be;
103     }
104     
105     /**
106      * mac计算,数据不为8的倍数,需要补0(128bit的mac算法)
107      * <p>具体的步骤如下:
108      * <p>1.源字节数组的长度应为8的倍数,否则补零至8的倍数,按8个字节分段(d0,d1,d2...)
109      * <p>2.密钥key字节数组长度固定是16,分为左右两部分(ka,kb)
110      * <p>3.左半部分ka与第一段d0进行des[加密]运算,得到e1
111      * <p>4.e1与d2进行异或运算得到x1
112      * <p>5.ka再与x1进行des[加密]运算,得到e2
113      * <p>6.e2在于d3进行异或运算得到x2
114      * <p>7.ka再与x2进行des[加密],依次进行,直到将源数组加密完毕,假设最后得到字节数组dn
115      * <p>8.用密钥的后半部分kb与dn进行des[解密]运算,得到p1
116      * <p>9.最后使用ka与p1进行des[加密]得到最后的mac值
117      * 
118      * <p>如果参数是字符串,请先用{@link DesUtils.hexStringToByte}转换为字节数组
119      * @param key 密钥,字节数组长度应为16,多于16将会截取前16位,少于16位则补0
120      * @param srcData 源数据
121      * @return
122      * @throws Exception 
123      */
124     public static byte[] computeMac_128(byte[] key, byte[] srcData) throws Exception
125     {
126         int klen = key.length;
127         byte[] ka = new byte[8];
128         byte[] kb = new byte[8];
129         byte[] temp = new byte[16];
130         //判断key的长度,主要是确定key的左右两部分
131         if(klen < 16){
132             System.arraycopy(key, 0, temp, 0, key.length);
133             System.arraycopy(temp, 0, ka, 0, 8);
134             System.arraycopy(temp, 8, kb, 0, 8);
135         } else {
136             System.arraycopy(key, 0, ka, 0, 8);
137             System.arraycopy(key, 8, kb, 0, 8);
138         }
139         
140         int length = srcData.length;
141         int x = length % 8;
142         int addLen = 0;
143         if (x != 0)
144         {
145             addLen = 8 - length % 8;
146         }
147         int pos = 0;
148         //保证data是8的倍数
149         byte[] data = new byte[length + addLen];
150         //data的值就是源数组的值(包括补零的值)
151         System.arraycopy(srcData, 0, data, 0, length);
152         //源数组第一段8字节
153         byte[] oper1 = new byte[8];
154         System.arraycopy(data, pos, oper1, 0, 8);
155         pos += 8;
156         //用于存储每段字节与ka加密后的结果数组
157         byte[] be = new byte[8];
158         for (int i = 0; i < data.length / 8; i++)
159         {
160             //将第一段oper1与ka进行des加密,得到be
161             be = DesUtils.des_encrypt(ka,oper1);
162             
163             if((i+1)*8 < data.length){
164                 //将加密结果e1与第二段oper2异或
165                 byte[] oper2 = new byte[8];
166                 System.arraycopy(data, pos, oper2, 0, 8);
167                 //得到异或结果bx
168                 byte[] bx = bytesXOR(be, oper2);
169                 oper1 = bx;
170                 pos += 8;
171             }
172         }
173         
174         //将最后加密的be与kb进行解密,得到dd
175         byte[] bb = new byte[8];
176         bb = DesUtils.des_decrypt(kb, be);
177         
178         //最后将bb与ka进行加密,得到mac值
179         // 取8个长度字节
180         byte[] retBuf = new byte[8];
181         retBuf = DesUtils.des_encrypt(ka,bb);
182         return retBuf;
183     }
184 
185     public static void main(String[] args) throws Exception
186     {
187         byte[] buff = DesUtils.hexStringToBytes("0200603804003081100D196228481610460005310031000000049000393404070901376228481610460005310D4912120481237000000104996228481610460551810D156156000000000000000000000011414144912DD000000000000D000000000000D027255100000000313330323839363300074143435459504598A5D201AED5C3FD00733131313135353531313135353130303030303030303030323931353635303130303039373331353635303130303130303031353635303130303130303030303030303030303030303000474142434836343431343130303030303035303030303031303330303330333039393330333036303130323433333330");
188         byte[] keys = DesUtils.hexStringToBytes("0000000000000000");
189         
190         byte[] result = computeMac(keys, buff);
191         
192         System.out.println("加密结果:"+DesUtils.bytesToHexString(result));
193         System.out.println(Arrays.toString(result));
194     }
195 }

 

测试类:

 1 package com.hm.com.util;
 2 
 3 import java.util.Arrays;
 4 
 5 import com.hm.com.util.string.HexConvertUtil;
 6 
 7 /**
 8  * simple introduction
 9  *
10  * <p>detailed comment
11  * @author Administrator 2016-4-12
12  * @see
13  * @since 1.0
14  */
15 public class CheckMac
16 {
17     public static void main(String[] args) throws Exception
18     {
19         String sss = computeMac("s");
20         System.out.println(sss);
21     }
22 
23     public static String computeMac(String reqStr) throws Exception{
24         String mac = "";
25 //        reqStr = "0200603804003080100D196228480028219036671031000000030709210703300921376228480028219036671D2310220343103000000104996228480028219036671D156156000000000000000000000021414142310DD000000000000D000000000000D04591010000000030303030303030303B749E4512BCD90500733131303135353531314435353120202030303034313030303031353635303233343039373931353635303233343130303031353635303233343130303030303030303030313030303000474142434836343431313730303030303035303030303031303330303330333039393330333036303130323433333330";
26         System.out.println("待计算的报文数据:(长度:" + reqStr.length()+ ")"+reqStr);
27         
28         //将63域mac转化为字节数组(此算法默认字符串是16进制表示)
29         byte[] srcs = HexConvertUtil.hexStrToBytes("1234567890123456");
30         System.out.println("源字节数组长度:" + srcs.length);
31         
32         //获取加解密的key字符串
33         String keyStr = "000000000000000000000000000000000000000000000000";
34         //将源数据转化为字节数组(此算法默认字符串是16进制表示)
35         byte[] keys = HexConvertUtil.hexStrToBytes(keyStr);
36         System.out.println("密钥字符串长度为:" + keyStr.length() + "-->转化为字节数组后长度:" + keys.length);
37         
38         //执行解密
39         byte[] reqKey = DesUtils.trides_decrypt(keys, srcs);
40         System.out.println("解密结果:" + DesUtils.bytesToHexString(reqKey));
41         
42         byte[] srcData = HexConvertUtil.hexStrToBytes(reqStr);
43         byte[] result = MacEcbUtils.computeMac(reqKey, srcData);
44         
45         mac = DesUtils.bytesToHexString(result);
46         System.out.println("计算得到的mac结果:" + mac);
47         
48         return mac;
49     }
50 
51 }

 

后面有时间还要再整理一下~!

 

转载于:https://www.cnblogs.com/seguzhizi/p/5415971.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值