当前位置:   article > 正文

Oracle 带Key的hmac_md5加密方法,调用Java实现_java hmac-md5

java hmac-md5

最近有个外围系统接口需要,对方要求报文经过带Key的hmac_md5加密,经过网上的查阅,找到Oracle提供标准的API,如下。

  1. FUNCTION MD5(PASSWD IN VARCHAR2) RETURN VARCHAR2 IS
  2. --PASSWD 需要加密的字符
  3. --@REMARK:MD5加密
  4. retval varchar2(32);
  5. BEGIN
  6. retval := UTL_RAW.CAST_TO_RAW(DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING => PASSWD));
  7. RETURN retval;
  8. END;

但是这个不满足对方系统要求,对方要求带Key加密,所以没有办法只能找他们提供java源码进行使用。对方提供的源码程序如下:

  1. package com.xxxxx.xxxxx.open.interfaces.utils;
  2. import com.qiniu.common.Constants;
  3. import javax.crypto.Mac;
  4. import javax.crypto.SecretKey;
  5. import javax.crypto.spec.SecretKeySpec;
  6. import java.io.IOException;
  7. import java.security.GeneralSecurityException;
  8. import java.security.MessageDigest;
  9. import java.util.Arrays;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class ZrSignUtils {
  13. public static String signTopRequest(Map<String, String> params, String secret, String signMethod, String body) throws Exception {
  14. // 第一步:检查参数是否已经排序
  15. String[] keys = params.keySet().toArray(new String[0]);
  16. Arrays.sort(keys);
  17. // 第二步:把所有参数名和参数值串在一起
  18. StringBuilder query = new StringBuilder();
  19. if ("hmac_md5".equalsIgnoreCase(signMethod)) {
  20. query.append(secret);
  21. }
  22. for (String key : keys) {
  23. String value = params.get(key);
  24. if (areNotEmpty(new String[]{key, value})) {
  25. query.append(key).append(value);
  26. }
  27. }
  28. // 第三步:把请求主体拼接在参数后面
  29. if (body != null) {
  30. query.append(body);
  31. }
  32. // 第四步:使用MD5/HMAC加密
  33. byte[] bytes;
  34. if ("hmac_md5".equalsIgnoreCase(signMethod)) {
  35. bytes = encryptHMAC(query.toString(), secret);
  36. } else {
  37. query.append(body).append(secret);
  38. bytes = encryptMD5(query.toString());
  39. }
  40. // 第五步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
  41. return byte2hex(bytes);
  42. }
  43. public static boolean areNotEmpty(String[] values) {
  44. boolean result = true;
  45. if ((values == null) || (values.length == 0))
  46. result = false;
  47. else {
  48. for (String value : values) {
  49. result &= !isEmpty(value);
  50. }
  51. }
  52. return result;
  53. }
  54. public static boolean isEmpty(String value) {
  55. int strLen;
  56. if ((value == null) || ((strLen = value.length()) == 0))
  57. return true;
  58. for (int i = 0; i < strLen; i++) {
  59. if (!Character.isWhitespace(value.charAt(i))) {
  60. return false;
  61. }
  62. }
  63. return true;
  64. }
  65. public static byte[] encryptHMAC(String data, String secret) throws IOException {
  66. byte[] bytes = null;
  67. try {
  68. SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.UTF_8), "HmacMD5");
  69. Mac mac = Mac.getInstance(secretKey.getAlgorithm());
  70. mac.init(secretKey);
  71. bytes = mac.doFinal(data.getBytes(Constants.UTF_8));
  72. } catch (GeneralSecurityException gse) {
  73. throw new IOException(gse.toString());
  74. }
  75. return bytes;
  76. }
  77. public static byte[] encryptMD5(String data) throws Exception {
  78. MessageDigest md = MessageDigest.getInstance("MD5");
  79. byte[] bytes = md.digest(data.getBytes(Constants.UTF_8));
  80. return bytes;
  81. // return encryptMD5(data.getBytes(Constants.CHARSET_UTF8));
  82. }
  83. public static String byte2hex(byte[] bytes) {
  84. StringBuilder sign = new StringBuilder();
  85. for (int i = 0; i < bytes.length; i++) {
  86. String hex = Integer.toHexString(bytes[i] & 0xFF);
  87. if (hex.length() == 1) {
  88. sign.append("0");
  89. }
  90. sign.append(hex.toUpperCase());
  91. }
  92. return sign.toString();
  93. }
  94. public static void main(String[] arg){
  95. Map<String,String> map=new HashMap<>();
  96. map.put("method","taobao.qimen.deliveryorder.confirm");
  97. map.put("timestamp","2023-01-07 07:44:00");
  98. map.put("format","json");
  99. map.put("app_key","NRP_YST_KEY_20230101_TEST");
  100. map.put("sign_method","hmac_md5");
  101. try {
  102. String a = signTopRequest(map,"BS@8p&xOZ6eY=BETA","hmac_md5","{\n" +
  103. " \"request\":{\n" +
  104. " \"deliveryOrder\":{\n" +
  105. " \"deliveryOrderCode\":\"T1234\",\n" +
  106. " \"deliveryOrderId\":\"C1234\",\n" +
  107. " \"warehouseCode\":\"W1234\",\n" +
  108. " \"orderType\":\"JYCK\",\n" +
  109. " \"status\":\"NEW\",\n" +
  110. " \"outBizCode\":\"WB1234\",\n" +
  111. " \"confirmType\":\"0\",\n" +
  112. " \"orderConfirmTime\":\"2016-09-08 12:00:00\",\n" +
  113. " \"operatorCode\":\"O23\",\n" +
  114. " \"operatorName\":\"老王\",\n" +
  115. " \"operateTime\":\"2016-09-09 12:00:00\"\n" +
  116. " },\n" +
  117. " \"packages\":{\n" +
  118. " \"package\":[\n" +
  119. " {\n" +
  120. " \"logisticsCode\":\"SF\",\n" +
  121. " \"logisticsName\":\"顺丰\",\n" +
  122. " \"expressCode\":\"Y1234\"\n" +
  123. " }\n" +
  124. " ]\n" +
  125. " },\n" +
  126. " \"orderLines\":{\n" +
  127. " \"orderLine\":[\n" +
  128. " {\n" +
  129. " \"orderLineNo\":\"1\",\n" +
  130. " \"orderSourceCode\":\"P1234\",\n" +
  131. " \"subSourceCode\":\"J1234\",\n" +
  132. " \"itemCode\":\"I1234\",\n" +
  133. " \"itemId\":\"WI1234\",\n" +
  134. " \"inventoryType\":\"ZP\",\n" +
  135. " \"ownerCode\":\"OW1234\",\n" +
  136. " \"itemName\":\"淘公仔\",\n" +
  137. " \"planQty\":\"12\",\n" +
  138. " \"actualQty\":\"12\",\n" +
  139. " \"batchs\":{\n" +
  140. " \"batch\":[\n" +
  141. " {\n" +
  142. " \"batchCode\":\"PC1234\",\n" +
  143. " \"productDate\":\"2016-09-09\",\n" +
  144. " \"expireDate\":\"2017-09-09\",\n" +
  145. " \"produceCode\":\"PH1234\",\n" +
  146. " \"inventoryType\":\"ZP\",\n" +
  147. " \"actualQty\":\"12\"\n" +
  148. " }\n" +
  149. " ]\n" +
  150. " }\n" +
  151. " },\n" +
  152. " {\n" +
  153. " \"orderLineNo\":\"1\",\n" +
  154. " \"orderSourceCode\":\"P1234\",\n" +
  155. " \"subSourceCode\":\"J1234\",\n" +
  156. " \"itemCode\":\"I1234\",\n" +
  157. " \"itemId\":\"WI1234\",\n" +
  158. " \"inventoryType\":\"ZP\",\n" +
  159. " \"ownerCode\":\"OW1234\",\n" +
  160. " \"itemName\":\"淘公仔\",\n" +
  161. " \"planQty\":\"12\",\n" +
  162. " \"actualQty\":\"12\",\n" +
  163. " \"batchs\":{\n" +
  164. " \"batch\":[\n" +
  165. " {\n" +
  166. " \"batchCode\":\"PC1234\",\n" +
  167. " \"productDate\":\"2016-09-09\",\n" +
  168. " \"expireDate\":\"2017-09-09\",\n" +
  169. " \"produceCode\":\"PH1234\",\n" +
  170. " \"inventoryType\":\"ZP\",\n" +
  171. " \"actualQty\":\"12\"\n" +
  172. " }\n" +
  173. " ]\n" +
  174. " }\n" +
  175. " }\n" +
  176. " ]\n" +
  177. " }\n" +
  178. " }\n" +
  179. "}");
  180. System.out.println("==========================================");
  181. System.out.println(a);
  182. } catch (Exception e) {
  183. e.printStackTrace();
  184. }
  185. }
  186. }

有了对方的java源码,我们可以在Sql Developer中直接编写java程序并编译。具体的编写方法与使用方法请参考其他博主的案例,例如:Oracle数据库中使用java代码(Java Sources)_oracle中javasource_Once_Pluto的博客-CSDN博客

我们这里经过对上述java代码的处理,在Sql Developer改写后,代码如下:

  1. create or replace and compile java source named zrsignutils as
  2. import java.nio.charset.Charset;
  3. import javax.crypto.Mac;
  4. import javax.crypto.SecretKey;
  5. import javax.crypto.spec.SecretKeySpec;
  6. import java.io.IOException;
  7. import java.security.GeneralSecurityException;
  8. import java.security.MessageDigest;
  9. import java.util.Arrays;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. public class ZrSignUtils {
  13. public static String signTopRequest( String secret, String signMethod, String body) throws Exception {
  14. StringBuilder query = new StringBuilder();
  15. byte[] bytes;
  16. if ("hmac_md5".equalsIgnoreCase(signMethod)) {
  17. query.append(body);
  18. bytes = encryptHMAC(query.toString(), secret);
  19. } else {
  20. query.append(body).append(secret);
  21. bytes = encryptMD5(query.toString());
  22. }
  23. return byte2hex(bytes);
  24. }
  25. public static boolean areNotEmpty(String[] values) {
  26. boolean result = true;
  27. if ((values == null) || (values.length == 0))
  28. result = false;
  29. else {
  30. for (String value : values) {
  31. result &= !isEmpty(value);
  32. }
  33. }
  34. return result;
  35. }
  36. public static boolean isEmpty(String value) {
  37. int strLen;
  38. if ((value == null) || ((strLen = value.length()) == 0))
  39. return true;
  40. for (int i = 0; i < strLen; i++) {
  41. if (!Character.isWhitespace(value.charAt(i))) {
  42. return false;
  43. }
  44. }
  45. return true;
  46. }
  47. public static byte[] encryptHMAC(String data, String secret) throws IOException {
  48. byte[] bytes = null;
  49. try {
  50. SecretKey secretKey = new SecretKeySpec(secret.getBytes(Charset.forName("UTF-8")), "HmacMD5");
  51. Mac mac = Mac.getInstance(secretKey.getAlgorithm());
  52. mac.init(secretKey);
  53. bytes = mac.doFinal(data.getBytes(Charset.forName("UTF-8")));
  54. } catch (GeneralSecurityException gse) {
  55. throw new IOException(gse.toString());
  56. }
  57. return bytes;
  58. }
  59. public static byte[] encryptMD5(String data) throws Exception {
  60. MessageDigest md = MessageDigest.getInstance("MD5");
  61. byte[] bytes = md.digest(data.getBytes(Charset.forName("UTF-8")));
  62. return bytes;
  63. }
  64. public static String byte2hex(byte[] bytes) {
  65. StringBuilder sign = new StringBuilder();
  66. for (int i = 0; i < bytes.length; i++) {
  67. String hex = Integer.toHexString(bytes[i] & 0xFF);
  68. if (hex.length() == 1) {
  69. sign.append("0");
  70. }
  71. sign.append(hex.toUpperCase());
  72. }
  73. return sign.toString();
  74. }
  75. }

上述代码可以直接在Sql Developer编译,如果编译成功,可以再数据查对象是查到有对应的JAVA Resource和JAVA CLASS代码。如果编译有错误,编译的时候可能看不到,但是如果你通过这种查询方式,可以看到JAVA Resource有小红叉,你打开就能看到编译报的错误,并定位问题所在了。

 最后,我们写一个Function来调用它即可,然后package里面直接再调这个Fuction即可实现加密啦:

  1. FUNCTION MD5_N2(secret in varchar2,
  2. signMethod in varchar2,
  3. body in varchar2) RETURN VARCHAR2 IS
  4. LANGUAGE JAVA NAME ' ZrSignUtils.signTopRequest(java.lang.String,java.lang.String,java.lang.String) return java.lang.String ';

我们验证下加密程序,在这个网址可以获取加密:

MD5/HMAC-MD5加密工具

获得结果:

代码调用过程:

  1. declare
  2. secret varchar2(1500);
  3. signmethod varchar2(1500);
  4. body varchar2(4000);
  5. result varchar2(150);
  6. begin
  7. secret := '34014E57072C7AA3D57E8A30038B1AA1';
  8. signmethod := 'hmac_md5';
  9. body := 'MAKE A SIMPLE TEST';
  10. result := cux_ww_person_pkg2.md5_n2(secret => secret,
  11. signmethod => signmethod,
  12. body => body);
  13. dbms_output.put_line(result);
  14. end;

 代码调用结果:

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号