需要用到的工具类,代码如下:

  1. import java.io.UnsupportedEncodingException;
  2. import java.nio.ByteBuffer;
  3. import java.nio.ByteOrder;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Calendar;
  6. import java.util.Date;
  7.  
  8. /**
  9. * @ClassName: CommonUtils
  10. * @Description: 通用工具类
  11. * @since: 0.0.1
  12. * @author: dzy
  13. * @date: 2017年2月22日 上午11:46:44
  14. */
  15. public class CommonUtils {
  16.  
  17. /**
  18. * @param date 日期
  19. * @param pattern 模式 如:yyyyMMdd等
  20. * @return
  21. * @Title: formatDate
  22. * @Description: 格式化日期
  23. * @since: 0.0.1
  24. */
  25. public static String formatDate(Date date, String pattern) {
  26. SimpleDateFormat formatter = new SimpleDateFormat(pattern);
  27. return formatter.format(date);
  28. }
  29.  
  30. /**
  31. * @param strDate String类型日期
  32. * @param pattern 日期显示模式
  33. * @return
  34. * @Title: parseDate
  35. * @Description: 将String日期转换为Date类型日期
  36. * @since: 0.0.1
  37. */
  38. public static Date parseDate(String strDate, String pattern) {
  39. SimpleDateFormat formatter = null;
  40. if (StringUtils.isBlank(strDate)) {
  41. return null;
  42. }
  43. formatter = new SimpleDateFormat(pattern);
  44. try {
  45. return formatter.parse(strDate);
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. return null;
  49. }
  50. }
  51.  
  52. /**
  53. * @param date 操作前的日期
  54. * @param field 日期的部分如:年,月,日
  55. * @param amount 增加或减少的值(负数表示减少)
  56. * @return
  57. * @Title: dateAdd
  58. * @Description: 日期的加减操作
  59. * @since: 0.0.1
  60. */
  61. public static Date dateAdd(Date date, int field, int amount) {
  62. Calendar calendar = Calendar.getInstance();
  63. calendar.setTime(date);
  64. calendar.add(field, amount);
  65. return calendar.getTime();
  66. }
  67.  
  68. /**
  69. * @param source 源字符串
  70. * @param offset 填充开始的位置, 0-在左边, source.getBytes().length 在右边, 如果有中文时需小心位置
  71. * @param c 用于填充的字符
  72. * @param length 最后字符串的字节长度
  73. * @return
  74. * @Title: fill
  75. * @Description: 填充字符串, 长度是按字节计算, 不是字符
  76. * @since: 0.0.1
  77. */
  78. public static String fill(String source, int offset, char c, int length) throws UnsupportedEncodingException {
  79. if (null == source) {
  80. source = "";
  81. }
  82. if (source.getBytes(CustomConstants.CHARSET_UTF8).length == length) {
  83. return source;
  84. }
  85. byte[] buf = new byte[length];
  86. byte[] src = source.getBytes(CustomConstants.CHARSET_UTF8);
  87. if (src.length > length) {
  88. System.arraycopy(src, src.length - length, buf, 0, length);
  89. return new String(buf, CustomConstants.CHARSET_UTF8);
  90. }
  91. if (offset > src.length) {
  92. offset = src.length;
  93. } else if (offset < 0) {
  94. offset = 0;
  95. }
  96. int n = length - src.length;
  97.  
  98. System.arraycopy(src, 0, buf, 0, offset);
  99. for (int i = 0; i < n; i++) {
  100. buf[i + offset] = (byte) c;
  101. }
  102. System.arraycopy(src, offset, buf, offset + n, src.length - offset);
  103. return new String(buf, CustomConstants.CHARSET_UTF8);
  104. }
  105.  
  106. /**
  107. * @param original 原字符串
  108. * @param offset 填充开始的位置, 0-在左边, original.getBytes().length 在右边, 如果有中文时需小心位置
  109. * @param length 替换的字节数
  110. * @param c 用于替换的字符
  111. * @return
  112. * @Title: replace
  113. * @Description: 替换字符串, 长度是按字节计算, 不是字符
  114. * @since: 0.0.1
  115. */
  116. public static String replace(String original, int offset, int length, char c) throws UnsupportedEncodingException {
  117. if (original == null) {
  118. original = "";
  119. }
  120. if (original.getBytes(CustomConstants.CHARSET_UTF8).length <= offset) {
  121. return original;
  122. }
  123. if (original.getBytes(CustomConstants.CHARSET_UTF8).length < offset + length) {
  124. length = original.getBytes(CustomConstants.CHARSET_UTF8).length - offset;
  125. }
  126. byte[] buf = new byte[original.length()];
  127. byte[] src = original.getBytes(CustomConstants.CHARSET_UTF8);
  128. System.arraycopy(src, 0, buf, 0, offset);
  129.  
  130. for (int i = offset; i < offset + length; i++) {
  131. buf[i] = (byte) c;
  132. }
  133. System.arraycopy(src, offset + length, buf, offset + length, src.length - offset - length);
  134. return new String(buf, CustomConstants.CHARSET_UTF8);
  135. }
  136.  
  137. /**
  138. * @param s 16进制字符串
  139. * @return
  140. * @Title: hexToByte
  141. * @Description: 16进制字符串转字节数组
  142. * @since: 0.0.1
  143. */
  144. public static byte[] hexToByte(String s) {
  145. byte[] result = null;
  146. try {
  147. int i = s.length();
  148. // if (i % 2 == 1) {
  149. // throw new Exception("字符串长度不是偶数.");
  150. // }
  151. if (i % 2 != 0) {
  152. throw new Exception("字符串长度不是偶数.");
  153. }
  154. result = new byte[i / 2];
  155. for (int j = 0; j < result.length; j++) {
  156. result[j] = (byte) Integer.parseInt(s.substring(j * 2, j * 2 + 2), 16);
  157. }
  158. } catch (Exception e) {
  159. result = null;
  160. e.printStackTrace();
  161. // log.error("16进制字符串转字节数组时出现异常:", e);
  162. }
  163. return result;
  164. }
  165.  
  166. /**
  167. * @param bytes 字节数组
  168. * @return
  169. * @Title: byte2hexString
  170. * @Description: 字节数组转换为16进制字符串 //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
  171. * @since: 0.0.1
  172. */
  173. public static String byte2hexString(byte[] bytes) {
  174. StringBuffer buf = new StringBuffer(bytes.length * 2);
  175. for (int i = 0; i < bytes.length; i++) {
  176. if (((int) bytes[i] & 0xff) < 0x10) {
  177. buf.append("0");
  178. }
  179. buf.append(Long.toString((int) bytes[i] & 0xff, 16));
  180. }
  181. return buf.toString().toUpperCase();
  182. }
  183.  
  184. /**
  185. * @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
  186. * @return
  187. * @Title: hexString2byte
  188. * @Description: 16进制字符串转字节数组
  189. * @since: 0.0.1
  190. */
  191. public static byte[] hexString2byte(String hexString) {
  192. if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
  193. return null;
  194. }
  195. byte[] bytes = new byte[hexString.length() / 2];
  196. for (int i = 0; i < hexString.length(); i += 2) {
  197. bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
  198. }
  199. return bytes;
  200. }
  201.  
  202. /**
  203. * @param i 需要转的int类型数字
  204. * @return
  205. * @Title: byte1ToBcd2
  206. * @Description: int类型转BCD码
  207. * @since: 0.0.1
  208. */
  209. public static String byte1ToBcd2(int i) {
  210. // return (new Integer(i / 16).toString() + (new Integer(i % 16)).toString());
  211. return Integer.toString(i / 16) + Integer.toString(i % 16);
  212. }
  213.  
  214. /**
  215. * @param b 字节数组
  216. * @return
  217. * @Title: byteToHex2
  218. * @Description: 字节数组转换为16进制字符串 For example, byte[] {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF} will be changed to String "0123456789ABCDEF"
  219. * @since: 0.0.1
  220. */
  221. public static String byteToHex2(byte[] b) {
  222. StringBuffer result = new StringBuffer();
  223. String tmp = "";
  224.  
  225. for (int i = 0; i < b.length; i++) {
  226. tmp = Integer.toHexString(b[i] & 0xff);
  227. if (tmp.length() == 1) {
  228. result.append("0" + tmp);
  229. } else {
  230. result.append(tmp);
  231. }
  232. }
  233. return result.toString().toUpperCase();
  234. }
  235.  
  236. /**
  237. * @param num 数字
  238. * @param len 字节数组长度
  239. * @return
  240. * @Title: intToHexBytes
  241. * @Description: int类型转16进制字节数组
  242. */
  243. public static byte[] intToHexBytes(int num, int len) {
  244. byte[] bytes = null;
  245. String hexString = Integer.toHexString(num);
  246. if (len > 0) {
  247. int length = len * 2;
  248. hexString = CustomStringUtils.leftFill(hexString, '0', length);
  249. bytes = CommonUtils.hexString2byte(hexString);
  250. }
  251. return bytes;
  252. }
  253.  
  254. /*public static String byteToHex3(byte[] b) {
  255. String result = "";
  256. String tmp = "";
  257.  
  258. for (int n = 0; n < b.length; n++) {
  259. tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
  260. if (tmp.length() == 1) {
  261. result = result + "0" + tmp;
  262. } else {
  263. result = result + tmp;
  264. }
  265. if (n < b.length - 1) {
  266. result = result + "";
  267. }
  268. }
  269. return result.toUpperCase();
  270. }*/
  271.  
  272. /**
  273. * @param str 需要转换编码的字符串
  274. * @return
  275. * @Title: iso2Gbk
  276. * @Description: 将ISO-8859-1编码的字符串转成GBK编码的字符串
  277. * @since: 0.0.1
  278. */
  279. public static String iso2Gbk(String str) {
  280. if (null == str) {
  281. return str;
  282. }
  283. try {
  284. return new String(str.getBytes("ISO-8859-1"), "GBK");
  285. } catch (UnsupportedEncodingException e) {
  286. // log.error("不支持的编码异常:", e);
  287. e.printStackTrace();
  288. return str;
  289. }
  290. }
  291.  
  292. // /**
  293. // * @param message
  294. // * @return
  295. // * @Title: getSubElement
  296. // * @Description: 分解各子域到HashMap
  297. // * @since: 0.0.1
  298. // */
  299. // public static Map<String, String> getSubElement(byte[] message) {
  300. // Map<String, String> map = new HashMap<String, String>();
  301. // String key = null;
  302. // String value = null;
  303. // int len = 0;
  304. // int idx = 0;
  305. // while (idx < message.length) {
  306. // key = new String(message, idx, 2);
  307. // idx += 2; //取了SE id 移2位
  308. // len = Integer.parseInt(new String(message, idx, 2));
  309. // idx += 2; //取了SE id的内容长度 移2位
  310. // value = new String(message, idx, len);
  311. // map.put(key, value);
  312. // idx += len;
  313. // }
  314. // return map;
  315. // }
  316.  
  317. //byte数组转成long
  318.  
  319. /**
  320. * @param b 将字节数组转long类型 位置为小端
  321. * @return
  322. */
  323. public static long byteToLong(byte[] b) {
  324. long s = 0;
  325. long s0 = b[0] & 0xff;// 最低位
  326. long s1 = b[1] & 0xff;
  327. long s2 = b[2] & 0xff;
  328. long s3 = b[3] & 0xff;
  329. long s4 = b[4] & 0xff;// 最低位
  330. long s5 = b[5] & 0xff;
  331. long s6 = b[6] & 0xff;
  332. long s7 = b[7] & 0xff;
  333.  
  334. // s0不变
  335. s1 <<= 8;
  336. s2 <<= 16;
  337. s3 <<= 24;
  338. s4 <<= 8 * 4;
  339. s5 <<= 8 * 5;
  340. s6 <<= 8 * 6;
  341. s7 <<= 8 * 7;
  342. s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
  343. return s;
  344. }
  345.  
  346. /**
  347. * @param b 将字节数组转int类型 位置为小端
  348. * @return
  349. */
  350. public static int byteToInt(byte[] b) {
  351. int s = 0;
  352. int s0 = b[0] & 0xff;// 最低位
  353. int s1 = b[1] & 0xff;
  354. int s2 = b[2] & 0xff;
  355. int s3 = b[3] & 0xff;
  356.  
  357. // s0不变
  358. s1 <<= 8;
  359. s2 <<= 16;
  360. s3 <<= 24;
  361.  
  362. s = s0 | s1 | s2 | s3;
  363. return s;
  364. }
  365.  
  366. /**
  367. * int类型转换小端的byte数组
  368. * @param i
  369. * @return
  370. */
  371. public static byte[] intToLittleBytes(int i) {
  372. ByteBuffer byteBuffer = ByteBuffer.allocate(4);
  373. byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
  374. byteBuffer.asIntBuffer().put(i);
  375. byte[] littleBytes = byteBuffer.array();
  376. return littleBytes;
  377. }
  378.  
  379. /**
  380. * 将一个字节转成10进制
  381. * @param b
  382. * @return
  383. */
  384. public static int byteToInt(byte b) {
  385. int value = b & 0xff;
  386. return value;
  387. }
  388.  
  389. /**
  390. * 字节数组合并
  391. * @param bt1 字节数组bt1
  392. * @param bt2 字节数组bt2
  393. * @return
  394. */
  395. public static byte[] byteMerger(byte[] bt1, byte[] bt2){
  396. byte[] bt3 = new byte[bt1.length+bt2.length];
  397. System.arraycopy(bt1, 0, bt3, 0, bt1.length);
  398. System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
  399. return bt3;
  400. }
  401.  
  402. }

DES算法总结,代码如下:

  1. import java.security.GeneralSecurityException;
  2. import java.security.SecureRandom;
  3.  
  4. import javax.crypto.Cipher;
  5. import javax.crypto.KeyGenerator;
  6. import javax.crypto.SecretKey;
  7. import javax.crypto.SecretKeyFactory;
  8. import javax.crypto.spec.DESKeySpec;
  9. import javax.crypto.spec.IvParameterSpec;
  10. import javax.crypto.spec.SecretKeySpec;
  11.  
  12. public final class DesUtils {
  13.  
  14. private static final byte[] ZERO_IVC = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
  15.  
  16. /**
  17. * 生成秘钥
  18. * @return 16字节3des秘钥
  19. * @throws GeneralSecurityException
  20. */
  21. public static byte[] create3DESKey() throws GeneralSecurityException {
  22. KeyGenerator kg = KeyGenerator.getInstance("DESede");
  23. kg.init(112);//must be equal to 112 or 168
  24. byte[] key24 = kg.generateKey().getEncoded();
  25. byte[] result = new byte[16];
  26. System.arraycopy(key24, 0, result, 0, 16);
  27. return result;
  28. }
  29.  
  30. /**
  31. * 3DES加密cbc模式
  32. * @param content 待加密数据
  33. * @param key 秘钥
  34. * @param ivb 向量
  35. * @return 加密结果
  36. * @throws GeneralSecurityException
  37. */
  38. public static byte[] encryptBy3DesCbc(byte[] content, byte[] key, byte[] ivb) throws GeneralSecurityException {
  39. byte[] _3deskey = new byte[24];
  40. System.arraycopy(key, 0, _3deskey, 0, 16);
  41. System.arraycopy(key, 0, _3deskey, 16, 8);
  42.  
  43. Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
  44. SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
  45. IvParameterSpec iv = new IvParameterSpec(ivb);
  46. cipher.init(Cipher.ENCRYPT_MODE, secureKey, iv);
  47. return cipher.doFinal(content);
  48. }
  49. /**
  50. * 3DES解密cbc模式
  51. * @param content 待解密数据
  52. * @param key 秘钥
  53. * @param ivb 向量
  54. * @return 解密结果
  55. * @throws GeneralSecurityException
  56. */
  57. public static byte[] decryptBy3DesCbc(byte[] content, byte[] key, byte[] ivb) throws GeneralSecurityException {
  58. byte[] _3deskey = new byte[24];
  59. System.arraycopy(key, 0, _3deskey, 0, 16);
  60. System.arraycopy(key, 0, _3deskey, 16, 8);
  61.  
  62. Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
  63. SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
  64. IvParameterSpec iv = new IvParameterSpec(ivb);
  65. cipher.init(Cipher.DECRYPT_MODE, secureKey, iv);
  66. long start = System.currentTimeMillis();
  67. System.out.println(start);
  68. return cipher.doFinal(content);
  69. }
  70. /**
  71. * 3DES加密cbc模式,默认向量
  72. * @param content 待加密数据
  73. * @param key 秘钥
  74. * @return 加密结果
  75. * @throws GeneralSecurityException
  76. */
  77. public static byte[] encryptBy3DesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
  78. return encryptBy3DesCbc(content, key, ZERO_IVC);
  79. }
  80.  
  81. /**
  82. * 3DES解密cbc模式,默认向量
  83. * @param content 带解密数据
  84. * @param key 秘钥
  85. * @return 解密结果
  86. * @throws GeneralSecurityException
  87. */
  88. public static byte[] decryptBy3DesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
  89. return decryptBy3DesCbc(content, key, ZERO_IVC);
  90. }
  91.  
  92. /**
  93. * 3DES加密Ecb模式
  94. * @param content 待加密数据
  95. * @param key 加密秘钥
  96. * @return 加密结果
  97. * @throws GeneralSecurityException
  98. */
  99. public static byte[] encryptBy3DesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
  100. byte[] _3deskey = new byte[24];
  101. System.arraycopy(key, 0, _3deskey, 0, 16);
  102. System.arraycopy(key, 0, _3deskey, 16, 8);
  103.  
  104. Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
  105. SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
  106. cipher.init(Cipher.ENCRYPT_MODE, secureKey);
  107. return cipher.doFinal(content);
  108. }
  109.  
  110. /**
  111. * 3DES解密Ecb模式
  112. * @param content 待解密数据
  113. * @param key 秘钥
  114. * @return 解密结果
  115. * @throws GeneralSecurityException
  116. */
  117. public static byte[] decryptBy3DesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
  118. byte[] _3deskey = new byte[24];
  119. System.arraycopy(key, 0, _3deskey, 0, 16);
  120. System.arraycopy(key, 0, _3deskey, 16, 8);
  121.  
  122. Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
  123. SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
  124. cipher.init(Cipher.DECRYPT_MODE, secureKey);
  125. return cipher.doFinal(content);
  126. }
  127.  
  128. /**
  129. * 3DES加密Ecb模式(3倍密钥长)
  130. * @param content 待加密数据
  131. * @param key 加密秘钥
  132. * @return 加密结果
  133. * @throws GeneralSecurityException
  134. */
  135. public static byte[] encryptBy3DesEcbThreeThreeTimes(byte[] content, byte[] key) throws GeneralSecurityException {
  136. if (key.length != 24) {
  137. throw new RuntimeException("密钥长度不是24.");
  138. }
  139.  
  140. Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
  141. SecretKey secureKey = new SecretKeySpec(key, "DESede");
  142. cipher.init(Cipher.ENCRYPT_MODE, secureKey);
  143. return cipher.doFinal(content);
  144. }
  145.  
  146. /**
  147. * 3DES解密Ecb模式((3倍密钥长))
  148. * @param content 待解密数据
  149. * @param key 秘钥
  150. * @return 解密结果
  151. * @throws GeneralSecurityException
  152. */
  153. public static byte[] decryptBy3DesEcbThreeThreeTimes(byte[] content, byte[] key) throws GeneralSecurityException {
  154. if (key.length != 24) {
  155. throw new RuntimeException("密钥长度不是24.");
  156. }
  157.  
  158. Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
  159. SecretKey secureKey = new SecretKeySpec(key, "DESede");
  160. cipher.init(Cipher.DECRYPT_MODE, secureKey);
  161. return cipher.doFinal(content);
  162. }
  163.  
  164. /**
  165. * des的cbc模式加密算法
  166. * @param content 待加密数据
  167. * @param key 密钥
  168. * @return 加密结果
  169. * @throws GeneralSecurityException
  170. */
  171. public static byte[] encryptByDesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
  172. return encryptByDesCbc(content, key, ZERO_IVC);
  173. }
  174. /**
  175. * des的cbc模式解密算法
  176. * @param content 待解密数据
  177. * @param key 密钥
  178. * @return 解密结果
  179. * @throws GeneralSecurityException
  180. */
  181. public static byte[] decryptByDesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
  182. return decryptByDesCbc(content, key, ZERO_IVC);
  183. }
  184.  
  185. /**
  186. * des的cbc模式加密算法
  187. * @param content 待加密数据
  188. * @param key 加密密钥
  189. * @return 加密结果
  190. * @throws GeneralSecurityException
  191. */
  192. public static byte[] encryptByDesCbc(byte[] content, byte[] key, byte[] icv) throws GeneralSecurityException {
  193. SecureRandom sr = new SecureRandom();
  194. DESKeySpec dks = new DESKeySpec(key);
  195. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  196. SecretKey secretKey = keyFactory.generateSecret(dks);
  197. Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
  198. IvParameterSpec iv = new IvParameterSpec(icv);
  199.  
  200. cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr);
  201.  
  202. return cipher.doFinal(content);
  203. }
  204.  
  205. /**
  206. * des的cbc模式解密算法
  207. * @param content 待解密数据
  208. * @param key 密钥
  209. * @return 解密结果
  210. * @throws GeneralSecurityException
  211. */
  212. public static byte[] decryptByDesCbc(byte[] content, byte[] key, byte[] icv) throws GeneralSecurityException {
  213. SecureRandom sr = new SecureRandom();
  214. DESKeySpec dks = new DESKeySpec(key);
  215. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  216. SecretKey secretKey = keyFactory.generateSecret(dks);
  217. Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
  218. IvParameterSpec iv = new IvParameterSpec(icv);
  219.  
  220. cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr);
  221.  
  222. return cipher.doFinal(content);
  223. }
  224.  
  225. /**
  226. * des加密算法,ECB方式,NoPadding模式,数据字节必须是8的整数倍
  227. * @param content 数据字节必须是8的整数倍
  228. * @param key 密钥
  229. * @return 加密结果
  230. * @throws GeneralSecurityException
  231. */
  232. public static byte[] encryptByDesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
  233. Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
  234. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  235. SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key));
  236. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  237. return cipher.doFinal(content);
  238. }
  239.  
  240. /**
  241. * des解密算法,ECB方式,NoPadding模式,数据字节必须是8的整数倍
  242. * @param content 数据字节必须是8的整数倍
  243. * @param key 密钥
  244. * @throws GeneralSecurityException
  245. * @return
  246. */
  247. public static byte[] decryptByDesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
  248. Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
  249. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  250. SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key));
  251. cipher.init(Cipher.DECRYPT_MODE, secretKey);
  252. return cipher.doFinal(content);
  253. }
  254.  
  255. /**
  256. * 本项目用于生成外部设备认证码和校验卡认证码(javacard GP规范 SCP02安全通道)(cardCryptogram)
  257. * B.1.2.1 Full Triple DES MAC
  258. * The full triple DES MAC is as defined in [ISO 9797-1] as MAC Algorithm 1 with output transformation 3,
  259. * without truncation, and with triple DES taking the place of the block cipher.
  260. * @param content 待加密数据
  261. * @param key 加密密钥
  262. * @return 加密结果后8字节
  263. * @throws Exception
  264. */
  265. public static byte[] encryptBy3DesCbcLast8Mac(byte[] content, byte[] key) throws GeneralSecurityException {
  266. byte[] edata = encryptBy3DesCbc(content, key);
  267.  
  268. byte[] result = new byte[8];
  269. System.arraycopy(edata, edata.length - 8, result, 0, 8);
  270. return result;
  271. }
  272. /**
  273. * 将b1和b2做异或,然后返回
  274. * @param b1
  275. * @param b2
  276. * @return 异或结果
  277. */
  278. public static byte[] xOr(byte[] b1, byte[] b2) {
  279. byte[] tXor = new byte[Math.min(b1.length, b2.length)];
  280. for (int i = 0; i < tXor.length; i++)
  281. tXor[i] = (byte) (b1[i] ^ b2[i]); // 异或(Xor)
  282. return tXor;
  283. }
  284.  
  285. /**
  286. * 整形转字节
  287. * @param n 整形数值
  288. * @param buf 结果字节数组
  289. * @param offset 填充开始位置
  290. */
  291. public static void int2byte(int n, byte buf[], int offset){
  292. buf[offset] = (byte)(n >> 24);
  293. buf[offset + 1] = (byte)(n >> 16);
  294. buf[offset + 2] = (byte)(n >> 8);
  295. buf[offset + 3] = (byte)n;
  296. }
  297.  
  298. /**
  299. * 长整形转字节
  300. * @param n 长整形数值
  301. * @param buf 结果字节数组
  302. * @param offset 填充开始位置
  303. */
  304. public static void long2byte(long n, byte buf[], int offset){
  305. buf[offset] = (byte)(int)(n >> 56);
  306. buf[offset + 1] = (byte)(int)(n >> 48);
  307. buf[offset + 2] = (byte)(int)(n >> 40);
  308. buf[offset + 3] = (byte)(int)(n >> 32);
  309. buf[offset + 4] = (byte)(int)(n >> 24);
  310. buf[offset + 5] = (byte)(int)(n >> 16);
  311. buf[offset + 6] = (byte)(int)(n >> 8);
  312. buf[offset + 7] = (byte)(int)n;
  313. }
  314. /**
  315. * @Title: hexString2byte
  316. * @Description: 16进制字符串转字节数组
  317. * @since: 0.0.1
  318. * @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
  319. * @return
  320. */
  321. public static byte[] hexString2byte(String hexString) {
  322. if (null == hexString || hexString.length() % 2 != 0) {
  323. return null;
  324. }
  325. byte[] bytes = new byte[hexString.length() / 2];
  326. for (int i = 0; i < hexString.length(); i+=2) {
  327. bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
  328. }
  329. return bytes;
  330. }
  331.  
  332. /**
  333. * @Title: byte2hexString
  334. * @Description: 字节数组转换为16进制字符串 //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
  335. * @since: 0.0.1
  336. * @param bytes 字节数组
  337. * @return
  338. */
  339. public static String byte2hexString(byte[] bytes) {
  340. StringBuffer buf = new StringBuffer(bytes.length * 2);
  341. for (int i = 0; i < bytes.length; i++) {
  342. if (((int)bytes[i] & 0xff) < 0x10) {
  343. buf.append("0");
  344. }
  345. buf.append(Long.toString((int) bytes[i] & 0xff, 16));
  346. }
  347. return buf.toString().toUpperCase();
  348. }
  349.  
  350. /**
  351. * 3DES加密Ecb模式
  352. * @param data 待加密数据
  353. * @param key 加密秘钥
  354. * @return 加密结果
  355. * @throws GeneralSecurityException
  356. */
  357. public static String encryptBy3DesEcb(String data, String key) {
  358. byte[] content = hexString2byte(data);
  359. byte[] deskey = hexString2byte(key);
  360. String hex2S = "";
  361. try {
  362. byte[] doFinal = encryptBy3DesEcb(content, deskey);
  363. hex2S = byte2hexString(doFinal);
  364. } catch (GeneralSecurityException e) {
  365. e.printStackTrace();
  366. }
  367. return hex2S;
  368. }
  369.  
  370. /**
  371. * 分散算法
  372. * @param data 数据(卡号)
  373. * @param key 根密钥
  374. * @return
  375. */
  376. public static String getHashProtectKey(String data, String key) {
  377. String tempKey, protect_key;
  378. tempKey =byte2hexString(xOr(hexString2byte(data),hexString2byte("FFFFFFFFFFFFFFFF")));
  379. protect_key = encryptBy3DesEcb(data, key);
  380. protect_key = protect_key + encryptBy3DesEcb(tempKey, key);
  381. return protect_key;
  382. }
  383.  
  384. /**
  385. * 分散密钥
  386. * @param data 数据(卡号)
  387. * @param key 根密钥
  388. * @return
  389. * @throws GeneralSecurityException
  390. */
  391. public static String getHashProtectKey(byte[] data, byte[] key) throws GeneralSecurityException {
  392. byte[] tempKeyBytes = xOr(data, hexString2byte("FFFFFFFFFFFFFFFF"));
  393. byte[] key1 = encryptBy3DesEcb(data, key);
  394. byte[] key2 = encryptBy3DesEcb(tempKeyBytes, key);
  395. byte[] disperKeyBytes = CommonUtils.byteMerger(key1, key2);
  396. String disperKey = CommonUtils.byte2hexString(disperKeyBytes);
  397. return disperKey;
  398. }
  399.  
  400. }

MAC算法总结,代码如下:

  1. import java.security.GeneralSecurityException;
  2.  
  3. /**
  4. * 计算MAC的工具类
  5. */
  6. public class MacUtils {
  7.  
  8. private static final byte[] ZERO_IVC = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
  9.  
  10. /**
  11. * PBOC-3DES-MAC算法
  12. *
  13. * 计算MAC(hex) PBOC_3DES_MAC(符合ISO9797Alg3Mac标准) (16的整数补8000000000000000)
  14. * 前n-1组使用单长密钥DES 使用密钥是密钥的左8字节) 最后1组使用双长密钥3DES (使用全部16字节密钥)
  15. *
  16. * 算法步骤:初始数据为D,初始向量为I,3DES秘钥为K0,秘钥低8字节DES秘钥K1;
  17. * 1、数据D分组并且填充:将字节数组D进行分组,每组8个字节,分组编号从0开始,分别为D0...Dn;最后一个分组不满8字节的,先填充一个字节80,
  18. * 后续全部填充00,满8字节的,新增一个8字节分组(80000000 00000000);
  19. * 2、进行des循环加密:(1)D0和初始向量I进行按位异或得到结果O0;(2)使用秘钥K1,DES加密结果O0得到结果I1,
  20. * 将I1和D1按位异或得到结果D1;(3)循环第二步骤得到结果Dn; 3、将Dn使用16字节秘钥K0进行3DES加密,得到的结果就是我们要的MAC。
  21. * @param data
  22. * @param key
  23. * @param icv
  24. * @return
  25. * @throws Exception
  26. */
  27. public static byte[] calculatePboc3desMAC(byte[] data, byte[] key, byte[] icv) throws Exception {
  28.  
  29. if (key == null || data == null)
  30. throw new RuntimeException("data or key is null.");
  31. if (key.length != 16)
  32. throw new RuntimeException("key length is not 16 byte.");
  33.  
  34. byte[] leftKey = new byte[8];
  35. System.arraycopy(key, 0, leftKey, 0, 8);
  36.  
  37. // 拆分数据(8字节块/Block)
  38. final int dataLength = data.length;
  39. final int blockCount = dataLength / 8 + 1;
  40. final int lastBlockLength = dataLength % 8;
  41.  
  42. byte[][] dataBlock = new byte[blockCount][8];
  43. for (int i = 0; i < blockCount; i++) {
  44. int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
  45. System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
  46. }
  47. dataBlock[blockCount - 1][lastBlockLength] = (byte) 0x80;
  48.  
  49. byte[] desXor = DesUtils.xOr(dataBlock[0], icv);
  50. for (int i = 1; i < blockCount; i++) {
  51. byte[] des = DesUtils.encryptByDesCbc(desXor, leftKey);
  52. desXor = DesUtils.xOr(dataBlock[i], des);
  53. }
  54. desXor = DesUtils.encryptBy3DesCbc(desXor, key);
  55. return desXor;
  56. }
  57.  
  58. /**
  59. * PBOC-DES-MAC算法
  60. * @param data
  61. * @param key
  62. * @param icv
  63. * @return
  64. * @throws Exception
  65. */
  66. public static byte[] calculatePbocdesMAC(byte[] data, byte[] key, byte[] icv) throws Exception {
  67.  
  68. if (key == null || data == null)
  69. throw new RuntimeException("data or key is null.");
  70. if (key.length != 8)
  71. throw new RuntimeException("key length is not 16 byte.");
  72.  
  73. // 拆分数据(8字节块/Block)
  74. final int dataLength = data.length;
  75. final int blockCount = dataLength / 8 + 1;
  76. final int lastBlockLength = dataLength % 8;
  77.  
  78. byte[][] dataBlock = new byte[blockCount][8];
  79. for (int i = 0; i < blockCount; i++) {
  80. int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
  81. System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
  82. }
  83. dataBlock[blockCount - 1][lastBlockLength] = (byte) 0x80;
  84.  
  85. byte[] desXor = DesUtils.xOr(dataBlock[0], icv);
  86. for (int i = 1; i < blockCount; i++) {
  87. byte[] des = DesUtils.encryptByDesCbc(desXor, key);
  88. desXor = DesUtils.xOr(dataBlock[i], des);
  89. }
  90. desXor = DesUtils.encryptByDesCbc(desXor, key);
  91. return desXor;
  92. }
  93.  
  94. /**
  95. * ANSI X9.9MAC算法 <br/>
  96. * (1) ANSI X9.9MAC算法只使用单倍长密钥。 <br/>
  97. * (2) MAC数据先按8字节分组,表示为D0~Dn,如果Dn不足8字节时,尾部以字节00补齐。 <br/>
  98. * (3) 用MAC密钥加密D0,加密结果与D1异或作为下一次的输入。 <br/>
  99. * (4) 将上一步的加密结果与下一分组异或,然后再用MAC密钥加密。<br/>
  100. * (5) 直至所有分组结束,取最后结果的左半部作为MAC。<br/>
  101. * 采用x9.9算法计算MAC (Count MAC by ANSI-x9.9).
  102. *
  103. * @param key 8字节密钥数据
  104. * @param data 待计算的缓冲区
  105. * @throws GeneralSecurityException
  106. */
  107. public static byte[] calculateANSIX9_9MAC(byte[] key, byte[] data) throws GeneralSecurityException {
  108.  
  109. final int dataLength = data.length;
  110. final int lastLength = dataLength % 8;
  111. final int lastBlockLength = lastLength == 0 ? 8 : lastLength;
  112. final int blockCount = dataLength / 8 + (lastLength > 0 ? 1 : 0);
  113.  
  114. // 拆分数据(8字节块/Block)
  115. byte[][] dataBlock = new byte[blockCount][8];
  116. for (int i = 0; i < blockCount; i++) {
  117. int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
  118. System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
  119. }
  120.  
  121. byte[] desXor = new byte[8];
  122. for (int i = 0; i < blockCount; i++) {
  123. byte[] tXor = DesUtils.xOr(desXor, dataBlock[i]);
  124. desXor = DesUtils.encryptByDesEcb(tXor, key); // DES加密
  125. }
  126. return desXor;
  127. }
  128.  
  129. /**
  130. * 采用ANSI x9.19算法计算MAC (Count MAC by ANSI-x9.19).<br/>
  131. * 将ANSI X9.9的结果做如下计算<br/>
  132. * (6) 用MAC密钥右半部解密(5)的结果。 <br/>
  133. * (7) 用MAC密钥左半部加密(6)的结果。<br/>
  134. * (8) 取(7)的结果的左半部作为MAC。<br/>
  135. * @param key 16字节密钥数据
  136. * @param data 待计算的缓冲区
  137. * @throws GeneralSecurityException
  138. */
  139. public static byte[] calculateANSIX9_19MAC(byte[] key, byte[] data) throws GeneralSecurityException {
  140. if (key == null || data == null)
  141. return null;
  142.  
  143. if (key.length != 16) {
  144. throw new RuntimeException("秘钥长度错误.");
  145. }
  146.  
  147. byte[] keyLeft = new byte[8];
  148. byte[] keyRight = new byte[8];
  149. System.arraycopy(key, 0, keyLeft, 0, 8);
  150. System.arraycopy(key, 8, keyRight, 0, 8);
  151.  
  152. byte[] result99 = calculateANSIX9_9MAC(keyLeft, data);
  153.  
  154. byte[] resultTemp = DesUtils.decryptByDesEcb(result99, keyRight);
  155. return DesUtils.encryptByDesEcb(resultTemp, keyLeft);
  156. }
  157.  
  158. }

MAC1Utils工具类:

  1. /**
  2. * 计算MAC1的工具类,是CPU卡在充值过程中要计算MAC1,然后通卡公司返回MAC2
  3. */
  4. public class Mac1Utils {
  5.  
  6. /**
  7. *
  8. * @param walletSequence 钱包交易流水(16进制)
  9. * @param beforeAmt 充值前金额(10进制)
  10. * @param txnAmt 充值金额(10进制)
  11. * @param tradeType 交易类型
  12. * @param psamTerminalCode 终端机编号
  13. * @param random 伪随机数
  14. * @param rechargeKey 充值密钥密文
  15. * @param protectKey 充值密钥保护密钥
  16. * @return
  17. * @throws Exception
  18. */
  19. public static String getMac1(String walletSequence, long beforeAmt, long txnAmt, String tradeType, String psamTerminalCode, String random, String rechargeKey, String protectKey) throws Exception {
  20. //获取充值密钥明文
  21. byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
  22. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  23. byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes);
  24.  
  25. // System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes));
  26.  
  27. // if (walletSequence.length() == 6) {
  28. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  29. // } else {
  30. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  31. // }
  32. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  33.  
  34. // System.out.println("walletSequence:" + walletSequence);
  35.  
  36. //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
  37. String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000");
  38. System.out.println("calcProcessKeyData:" + calcProcessKeyData);
  39.  
  40. //获取过程密钥
  41. byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
  42. byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes);
  43.  
  44. // System.out.println("processKey:" + DesUtils.byte2hexString(processKeyBytes));
  45.  
  46. String balance = CustomStringUtils.leftFill(Long.toHexString(beforeAmt), '0', 8);
  47. String chargeFee = CustomStringUtils.leftFill(Long.toHexString(txnAmt), '0', 8);
  48.  
  49. String macData = CustomStringUtils.append(balance, chargeFee, tradeType, psamTerminalCode);
  50. byte[] macDataBytes = DesUtils.hexString2byte(macData);
  51.  
  52. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  53. byte[] calcPbocDesMacBytes = MacUtils.calculatePbocdesMAC(macDataBytes, processKeyBytes, icv);
  54. String calcPbocDesMac = DesUtils.byte2hexString(calcPbocDesMacBytes);
  55.  
  56. String mac1 = calcPbocDesMac.substring(0, 8);
  57. return mac1;
  58. }
  59.  
  60. /**
  61. *
  62. * @param walletSequence 钱包交易流水(16进制)
  63. * @param beforeBalanceHex 充值前金额(16进制)
  64. * @param rechargeFeeHex 充值金额(16进制)
  65. * @param tradeType 交易类型
  66. * @param psamTerminalCode 终端机编号
  67. * @param random 伪随机数
  68. * @param rechargeKey 充值密钥密文
  69. * @param protectKey 充值密钥保护密钥
  70. * @return
  71. * @throws Exception
  72. */
  73. public static String getMac1(String walletSequence, String beforeBalanceHex, String rechargeFeeHex, String tradeType, String psamTerminalCode, String random, String rechargeKey, String protectKey) throws Exception {
  74. //获取充值密钥明文
  75. byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
  76. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  77. byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes);
  78.  
  79. System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes));
  80.  
  81. // if (walletSequence.length() == 6) {
  82. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  83. // } else {
  84. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  85. // }
  86. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  87.  
  88. // System.out.println("walletSequence:" + walletSequence);
  89.  
  90. //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
  91. String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000");
  92.  
  93. //获取过程密钥
  94. byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
  95. byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes);
  96.  
  97. System.out.println("processKey:" + DesUtils.byte2hexString(processKeyBytes));
  98.  
  99. String balance = CustomStringUtils.leftFill(beforeBalanceHex, '0', 8);
  100. String chargeFee = CustomStringUtils.leftFill(rechargeFeeHex, '0', 8);
  101.  
  102. String macData = CustomStringUtils.append(balance, chargeFee, tradeType, psamTerminalCode);
  103. byte[] macDataBytes = DesUtils.hexString2byte(macData);
  104. System.out.println("macData:" + macData);
  105.  
  106. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  107. byte[] calcPbocDesMacBytes = MacUtils.calculatePbocdesMAC(macDataBytes, processKeyBytes, icv);
  108. String calcPbocDesMac = DesUtils.byte2hexString(calcPbocDesMacBytes);
  109.  
  110. String mac1 = calcPbocDesMac.substring(0, 8);
  111. return mac1;
  112. }
  113.  
  114. /**
  115. *
  116. * @param walletSequence 电子钱包联机交易序号(16进制)
  117. * @param rechargeFee 充值金额(10进制)
  118. * @param tradeType 交易类型
  119. * @param psamTerminalCode 终端机编号
  120. * @param tradeDateTime 主机交易日期时间
  121. * @param random 随机数
  122. * @param rechargeKey 充值密钥密文
  123. * @param protectKey 保护密钥
  124. * @return
  125. * @throws Exception
  126. */
  127. public static String getMac2(String walletSequence, long rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String random, String rechargeKey, String protectKey) throws Exception {
  128.  
  129. //获取充值密钥明文
  130. byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
  131. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  132. byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes);
  133.  
  134. System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes));
  135.  
  136. // if (walletSequence.length() == 6) {
  137. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  138. // } else {
  139. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  140. // }
  141. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  142.  
  143. //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
  144. String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000");
  145.  
  146. //获取过程密钥
  147. byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
  148. byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes);
  149.  
  150. //充值金额
  151. String chargeFee = CustomStringUtils.leftFill(Long.toHexString(rechargeFee), '0', 8);
  152. String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime);
  153.  
  154. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  155. byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data);
  156.  
  157. byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
  158. String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes);
  159.  
  160. String mac2 = calcPbocdesMac.substring(0, 8);
  161. return mac2;
  162. }
  163.  
  164. /**
  165. *
  166. * @param walletSequence 电子钱包联机交易序号(16进制)
  167. * @param rechargeFee 充值金额(16进制)
  168. * @param tradeType 交易类型
  169. * @param psamTerminalCode 终端机编号
  170. * @param tradeDateTime 主机交易日期时间
  171. * @param random 随机数
  172. * @param rechargeKey 充值密钥密文
  173. * @param protectKey 保护密钥
  174. * @return
  175. * @throws Exception
  176. */
  177. public static String getMac2(String walletSequence, String rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String random, String rechargeKey, String protectKey) throws Exception {
  178.  
  179. //获取充值密钥明文
  180. byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
  181. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  182. byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes);
  183.  
  184. System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes));
  185.  
  186. // if (walletSequence.length() == 6) {
  187. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  188. // } else {
  189. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  190. // }
  191. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  192.  
  193. //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
  194. String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000");
  195.  
  196. //获取过程密钥
  197. byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
  198. byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes);
  199.  
  200. //充值金额
  201. String chargeFee = CustomStringUtils.leftFill(rechargeFee, '0', 8);
  202. String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime);
  203.  
  204. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  205. byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data);
  206.  
  207. byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
  208. String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes);
  209.  
  210. String mac2 = calcPbocdesMac.substring(0, 8);
  211. return mac2;
  212. }
  213.  
  214. /**
  215. * 计算MAC2
  216. * @param rechargeFee 充值金额
  217. * @param tradeType 交易类型
  218. * @param psamTerminalCode 终端机编号
  219. * @param tradeDateTime 交易日期时间
  220. * @param processKey 过程密钥
  221. * @return
  222. * @throws Exception
  223. */
  224. public static String getMac2(String rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String processKey) throws Exception {
  225.  
  226. byte[] processKeyBytes = DesUtils.hexString2byte(processKey);
  227.  
  228. //4字节交易金额+1字节交易类型+6字节终端机编号+4字节主机交易日期+3字节主机交易时间
  229. String chargeFee = CustomStringUtils.leftFill(rechargeFee, '0', 8);
  230. String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime);
  231.  
  232. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  233. byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data);
  234.  
  235. byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
  236. String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes);
  237.  
  238. String mac2 = calcPbocdesMac.substring(0, 8);
  239. return mac2;
  240. }
  241.  
  242. }

TACUtils工具类:

  1. public class TacUtils {
  2.  
  3. /**
  4. * 计算TAC
  5. * @param afterAmt 新余额(充值后金额)(10进制)
  6. * @param walletSequence 钱包交易序号
  7. * @param txnAmt 充值金额(10进制)
  8. * @param tradeType 交易类型
  9. * @param psamTerminalCode 终端机编号
  10. * @param tradeDateTime 交易日期时间
  11. * @param tacKey tac密钥
  12. * @param protectKey 保护密钥
  13. * @return
  14. * @throws Exception
  15. */
  16. public static String getTac(long afterAmt, String walletSequence, long txnAmt, String tradeType, String psamTerminalCode, String tradeDateTime, String tacKey, String protectKey) throws Exception {
  17.  
  18. //获取TAC密钥明文
  19. byte[] tacKeyBytes = DesUtils.hexString2byte(tacKey);
  20. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  21. byte[] tacKeyClearTextBytes = DesUtils.decryptBy3DesEcb(tacKeyBytes, protectKeyBytes);
  22.  
  23. int half = tacKeyClearTextBytes.length / 2;
  24. byte[] b1 = new byte[half];
  25. byte[] b2 = new byte[half];
  26.  
  27. System.arraycopy(tacKeyClearTextBytes, 0, b1, 0, half);
  28. System.arraycopy(tacKeyClearTextBytes, half, b2, 0, half);
  29.  
  30. //tac过程密钥
  31. byte[] tacProcessKeyBytes = DesUtils.xOr(b1, b2);
  32.  
  33. //4字节电子存折或电子钱包新余额
  34. String newBalance = CustomStringUtils.leftFill(Long.toHexString(afterAmt), '0', 8);
  35. String chargeFee = CustomStringUtils.leftFill(Long.toHexString(txnAmt), '0', 8);
  36.  
  37. // if (walletSequence.length() == 6) {
  38. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  39. // } else {
  40. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  41. // }
  42. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  43.  
  44. //4字节电子存折或电子钱包新余额 + 2字节电子存折或电子钱包联机交易序号(加1前) + 4字节交易金额 + 1字节交易类型标识 + 6字节终端机编号 + 4字节主机交易日期 + 3字节主机交易时间
  45. String tacData = CustomStringUtils.append(newBalance, walletSequence, chargeFee, tradeType, psamTerminalCode, tradeDateTime);
  46.  
  47. System.out.println("tacData:" + tacData);
  48. System.out.println("tacProceessKey:" + DesUtils.byte2hexString(tacProcessKeyBytes));
  49.  
  50. byte[] tacDataBytes = DesUtils.hexString2byte(tacData);
  51. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  52.  
  53. byte[] calculatePbocdesMACBytes = MacUtils.calculatePbocdesMAC(tacDataBytes, tacProcessKeyBytes, icv);
  54. String calculatePbocdesMAC = DesUtils.byte2hexString(calculatePbocdesMACBytes);
  55.  
  56. String tac = calculatePbocdesMAC.substring(0, 8);
  57. return tac;
  58. }
  59.  
  60. /**
  61. * 计算TAC
  62. * @param rechargeFeeHex 新余额(充值后金额)(16进制)
  63. * @param walletSequence 钱包交易序号
  64. * @param rechargeFeeHex 充值金额(16进制)
  65. * @param tradeType 交易类型
  66. * @param psamTerminalCode 终端机编号
  67. * @param tradeDateTime 交易日期时间
  68. * @param tacKey tac密钥
  69. * @param protectKey 保护密钥
  70. * @return
  71. * @throws Exception
  72. */
  73. public static String getTac(String afterBalanceHex, String walletSequence, String rechargeFeeHex, String tradeType, String psamTerminalCode, String tradeDateTime, String tacKey, String protectKey) throws Exception {
  74.  
  75. //获取TAC密钥明文
  76. byte[] tacKeyBytes = DesUtils.hexString2byte(tacKey);
  77. byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
  78. byte[] tacKeyClearTextBytes = DesUtils.decryptBy3DesEcb(tacKeyBytes, protectKeyBytes);
  79.  
  80. System.out.println("tacKeyClearText:" + DesUtils.byte2hexString(tacKeyClearTextBytes));
  81.  
  82. int half = tacKeyClearTextBytes.length / 2;
  83. byte[] b1 = new byte[half];
  84. byte[] b2 = new byte[half];
  85.  
  86. System.arraycopy(tacKeyClearTextBytes, 0, b1, 0, half);
  87. System.arraycopy(tacKeyClearTextBytes, half, b2, 0, half);
  88.  
  89. //tac过程密钥
  90. byte[] tacProcessKeyBytes = DesUtils.xOr(b1, b2);
  91.  
  92. //4字节电子存折或电子钱包新余额
  93. String newBalance = CustomStringUtils.leftFill(afterBalanceHex, '0', 8);
  94. String chargeFee = CustomStringUtils.leftFill(rechargeFeeHex, '0', 8);
  95.  
  96. // if (walletSequence.length() == 6) {
  97. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
  98. // } else {
  99. // walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
  100. // }
  101. // walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4);
  102.  
  103. //4字节电子存折或电子钱包新余额 + 2字节电子存折或电子钱包联机交易序号(加1前) + 4字节交易金额 + 1字节交易类型标识 + 6字节终端机编号 + 4字节主机交易日期 + 3字节主机交易时间
  104. String tacData = CustomStringUtils.append(newBalance, walletSequence, chargeFee, tradeType, psamTerminalCode, tradeDateTime);
  105.  
  106. System.out.println("tacData:" + tacData);
  107. System.out.println("tacProceessKey:" + DesUtils.byte2hexString(tacProcessKeyBytes));
  108.  
  109. byte[] tacDataBytes = DesUtils.hexString2byte(tacData);
  110. byte[] icv = DesUtils.hexString2byte("0000000000000000");
  111.  
  112. byte[] calculatePbocdesMACBytes = MacUtils.calculatePbocdesMAC(tacDataBytes, tacProcessKeyBytes, icv);
  113. String calculatePbocdesMAC = DesUtils.byte2hexString(calculatePbocdesMACBytes);
  114.  
  115. String tac = calculatePbocdesMAC.substring(0, 8);
  116. return tac;
  117. }
  118.  
  119. }

DES算法和MAC算法总结的更多相关文章

  1. 最小生成树---Prim算法和Kruskal算法

    Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...

  2. mahout中kmeans算法和Canopy算法实现原理

    本文讲一下mahout中kmeans算法和Canopy算法实现原理. 一. Kmeans是一个很经典的聚类算法,我想大家都非常熟悉.虽然算法较为简单,在实际应用中却可以有不错的效果:其算法原理也决定了 ...

  3. 使用Apriori算法和FP-growth算法进行关联分析

    系列文章:<机器学习实战>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章 ...

  4. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  5. 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

    一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...

  6. 用Spark学习FP Tree算法和PrefixSpan算法

    在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...

  7. 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

    字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...

  8. 最小生成树之Prim算法和Kruskal算法

    最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...

  9. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

随机推荐

  1. 利用Tensorflow进行自然语言处理(NLP)系列之一Word2Vec

    同步笔者CSDN博客(https://blog.csdn.net/qq_37608890/article/details/81513882). 一.概述 本文将要讨论NLP的一个重要话题:Word2V ...

  2. 使用qemu启动dd制作的img镜像

    1. 准备工作 应用场景 在需要单机取证时,需要在不影响对象业务的情况下进行取证或分析,可以使用dd 对目标服务器进行镜像,生成img文件,镜像可以通过winhex进行静态分析.但是想要动态分析服务器 ...

  3. 工作在Amazon:为何晋升如此难?

    英文原文:Why It's So Difficult to Climb Amazon's Corporate Ladder 本文作者 Brad Stone 的新书 The Everything Sto ...

  4. js操作对象属性值为字符串

    今天在项目开发中遇到一个没遇到过的问题,这个问题是需要对比两个对象a和b,a是一个只有一个属性的对象,b是一个含有多个属性对象,如果b中包含和a一模一样的属性名和值,则把这个一样的属性和值从b中删除了 ...

  5. Phonegap 环境配置

    目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...

  6. 补充的css知识点

    1.文字一行显示   超出的用...表示 .ellipsis{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  7. sprint3最终演示及团队贡献分

    团队名:在考虑 团队项目:复利计算 项目演示: 之前的功能都有演示过就不再一一截图,把我们新增加的功能说一下 首先用户进入我们的网页可以登录或者注册,注册的用户可以直接输入用户名及密码登录,没有注册的 ...

  8. Thunder团队第七周 - Scrum会议6

    Scrum会议6 小组名称:Thunder 项目名称:i阅app Scrum Master:苗威 工作照片: 宋雨在照相,所以不在相片中. 参会成员: 王航:http://www.cnblogs.co ...

  9. struts2文件上传突破2M限制

    struts配置文件 <action name="upload" class="strutsFileUpload"> <result name ...

  10. struts2 不返回result的做法

    有时候 比如提交一个弹框的表单 提交成功后我们只是让表单关闭并不进行页面跳转,那么action 里面就returne null, 然后result 也不用配置了 版权声明:本文为博主原创文章,未经博主 ...