Oracle 带Key的hmac_md5加密方法,调用Java实现

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

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

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

package com.xxxxx.xxxxx.open.interfaces.utils;

import com.qiniu.common.Constants;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class ZrSignUtils {

    public static String signTopRequest(Map<String, String> params, String secret, String signMethod, String body) throws Exception {
        // 第一步:检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);

        // 第二步:把所有参数名和参数值串在一起
        StringBuilder query = new StringBuilder();
        if ("hmac_md5".equalsIgnoreCase(signMethod)) {
            query.append(secret);
        }
        for (String key : keys) {
            String value = params.get(key);
            if (areNotEmpty(new String[]{key, value})) {
                query.append(key).append(value);
            }

        }
        // 第三步:把请求主体拼接在参数后面
        if (body != null) {
            query.append(body);
        }

        // 第四步:使用MD5/HMAC加密
        byte[] bytes;
        if ("hmac_md5".equalsIgnoreCase(signMethod)) {
            bytes = encryptHMAC(query.toString(), secret);
        } else {
            query.append(body).append(secret);
            bytes = encryptMD5(query.toString());
        }

        // 第五步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
        return byte2hex(bytes);
    }

    public static boolean areNotEmpty(String[] values) {
        boolean result = true;
        if ((values == null) || (values.length == 0))
            result = false;
        else {
            for (String value : values) {
                result &= !isEmpty(value);
            }
        }
        return result;
    }
    public static boolean isEmpty(String value) {
        int strLen;
        if ((value == null) || ((strLen = value.length()) == 0))
            return true;
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(value.charAt(i))) {
                return false;
            }
        }
        return true;
    }
    public static byte[] encryptHMAC(String data, String secret) throws IOException {
        byte[] bytes = null;
        try {
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.UTF_8), "HmacMD5");
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data.getBytes(Constants.UTF_8));
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse.toString());
        }
        return bytes;
    }

    public static byte[] encryptMD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");

        byte[] bytes = md.digest(data.getBytes(Constants.UTF_8));
        return bytes;
//        return encryptMD5(data.getBytes(Constants.CHARSET_UTF8));
    }

    public static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

    public static void main(String[] arg){
        Map<String,String> map=new HashMap<>();
        map.put("method","taobao.qimen.deliveryorder.confirm");
        map.put("timestamp","2023-01-07 07:44:00");
        map.put("format","json");
        map.put("app_key","NRP_YST_KEY_20230101_TEST");
        map.put("sign_method","hmac_md5");
        try {
            String a = signTopRequest(map,"BS@8p&xOZ6eY=BETA","hmac_md5","{\n" +
                    "    \"request\":{\n" +
                    "        \"deliveryOrder\":{\n" +
                    "            \"deliveryOrderCode\":\"T1234\",\n" +
                    "            \"deliveryOrderId\":\"C1234\",\n" +
                    "            \"warehouseCode\":\"W1234\",\n" +
                    "            \"orderType\":\"JYCK\",\n" +
                    "            \"status\":\"NEW\",\n" +
                    "            \"outBizCode\":\"WB1234\",\n" +
                    "            \"confirmType\":\"0\",\n" +
                    "            \"orderConfirmTime\":\"2016-09-08 12:00:00\",\n" +
                    "            \"operatorCode\":\"O23\",\n" +
                    "            \"operatorName\":\"老王\",\n" +
                    "            \"operateTime\":\"2016-09-09 12:00:00\"\n" +
                    "        },\n" +
                    "        \"packages\":{\n" +
                    "            \"package\":[\n" +
                    "                {\n" +
                    "                    \"logisticsCode\":\"SF\",\n" +
                    "                    \"logisticsName\":\"顺丰\",\n" +
                    "                    \"expressCode\":\"Y1234\"\n" +
                    "                }\n" +
                    "            ]\n" +
                    "        },\n" +
                    "        \"orderLines\":{\n" +
                    "            \"orderLine\":[\n" +
                    "                {\n" +
                    "                    \"orderLineNo\":\"1\",\n" +
                    "                    \"orderSourceCode\":\"P1234\",\n" +
                    "                    \"subSourceCode\":\"J1234\",\n" +
                    "                    \"itemCode\":\"I1234\",\n" +
                    "                    \"itemId\":\"WI1234\",\n" +
                    "                    \"inventoryType\":\"ZP\",\n" +
                    "                    \"ownerCode\":\"OW1234\",\n" +
                    "                    \"itemName\":\"淘公仔\",\n" +
                    "                    \"planQty\":\"12\",\n" +
                    "                    \"actualQty\":\"12\",\n" +
                    "                    \"batchs\":{\n" +
                    "                        \"batch\":[\n" +
                    "                            {\n" +
                    "                                \"batchCode\":\"PC1234\",\n" +
                    "                                \"productDate\":\"2016-09-09\",\n" +
                    "                                \"expireDate\":\"2017-09-09\",\n" +
                    "                                \"produceCode\":\"PH1234\",\n" +
                    "                                \"inventoryType\":\"ZP\",\n" +
                    "                                \"actualQty\":\"12\"\n" +
                    "                            }\n" +
                    "                        ]\n" +
                    "                    }\n" +
                    "                },\n" +
                    "                {\n" +
                    "                    \"orderLineNo\":\"1\",\n" +
                    "                    \"orderSourceCode\":\"P1234\",\n" +
                    "                    \"subSourceCode\":\"J1234\",\n" +
                    "                    \"itemCode\":\"I1234\",\n" +
                    "                    \"itemId\":\"WI1234\",\n" +
                    "                    \"inventoryType\":\"ZP\",\n" +
                    "                    \"ownerCode\":\"OW1234\",\n" +
                    "                    \"itemName\":\"淘公仔\",\n" +
                    "                    \"planQty\":\"12\",\n" +
                    "                    \"actualQty\":\"12\",\n" +
                    "                    \"batchs\":{\n" +
                    "                        \"batch\":[\n" +
                    "                            {\n" +
                    "                                \"batchCode\":\"PC1234\",\n" +
                    "                                \"productDate\":\"2016-09-09\",\n" +
                    "                                \"expireDate\":\"2017-09-09\",\n" +
                    "                                \"produceCode\":\"PH1234\",\n" +
                    "                                \"inventoryType\":\"ZP\",\n" +
                    "                                \"actualQty\":\"12\"\n" +
                    "                            }\n" +
                    "                        ]\n" +
                    "                    }\n" +
                    "                }\n" +
                    "            ]\n" +
                    "        }\n" +
                    "    }\n" +
                    "}");
            System.out.println("==========================================");
            System.out.println(a);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

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

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

create or replace and compile java source named zrsignutils as
import java.nio.charset.Charset;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class ZrSignUtils {

    public static String signTopRequest( String secret, String signMethod, String body) throws Exception {

      StringBuilder query = new StringBuilder();
      byte[] bytes;
      if ("hmac_md5".equalsIgnoreCase(signMethod)) {
          query.append(body);
          bytes = encryptHMAC(query.toString(), secret);
      } else {
          query.append(body).append(secret);
          bytes = encryptMD5(query.toString());
      }


      return byte2hex(bytes);
    }
    public static boolean areNotEmpty(String[] values) {
        boolean result = true;
        if ((values == null) || (values.length == 0))
            result = false;
        else {
            for (String value : values) {
                result &= !isEmpty(value);
            }
        }
        return result;
    }
    public static boolean isEmpty(String value) {
        int strLen;
        if ((value == null) || ((strLen = value.length()) == 0))
            return true;
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(value.charAt(i))) {
                return false;
            }
        }
        return true;
    }
    public static byte[] encryptHMAC(String data, String secret) throws IOException {
        byte[] bytes = null;
        try {
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(Charset.forName("UTF-8")), "HmacMD5");
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data.getBytes(Charset.forName("UTF-8")));
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse.toString());
        }
        return bytes;
    }
   public static byte[] encryptMD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");

        byte[] bytes = md.digest(data.getBytes(Charset.forName("UTF-8")));
        return bytes;
    }

    public static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }


}

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

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

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

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

MD5/HMAC-MD5加密工具

获得结果:

代码调用过程:

declare
  secret     varchar2(1500);
  signmethod varchar2(1500);
  body       varchar2(4000);
  result     varchar2(150);
begin
  secret     := '34014E57072C7AA3D57E8A30038B1AA1';
  signmethod := 'hmac_md5';
  body       := 'MAKE A SIMPLE TEST';
  result     := cux_ww_person_pkg2.md5_n2(secret     => secret,
                                          signmethod => signmethod,
                                          body       => body);

  dbms_output.put_line(result);
end;

 代码调用结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值