• 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 }

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

  • 相关阅读:
    composer 中国全量镜像 laravel-china.org
    Increase PHP script execution time with Nginx
    How to make a USB stick use ISO image file in debian
    Getting svn to ignore files and directories
    Carbon document
    Use Laravel/homestead 环境维护基于 brophp 开发的老项目
    Vagrant WinNFSd
    How to use jQuery countdown plugin
    消息系统的设计与实现
    VMvare 复制的数据库,需要改变的配置
  • 原文地址:https://www.cnblogs.com/seguzhizi/p/5415971.html
Copyright © 2020-2023  润新知