关于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 }
后面有时间还要再整理一下~!