SHA1实现防篡改加密

本文深入解析支付宝的防篡改机制,从参数处理、排序拼接、算法加密到最终的16进制转换,详细介绍了如何确保数据传输的安全性和完整性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

防篡改介绍详见支付宝验证

实现过程:

1.参数处理 去空去 null 

/**
     * 除去数组中的null值和签名参数
     * @param sArray 签名参数组
     * @return 去掉null值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {

        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("SignData")
                    || key.equalsIgnoreCase("SignType")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

在这里也要去除空字符串,为什么呢?之前做一个项目对接,java的空串传到c中就变成null,导致签名验证一直不能通过。

2.参数排序并拼接成字符串

/** 
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @param partnerSecret 
     * @return 拼接后字符串
     * @throws UnsupportedEncodingException 
     */
    public static byte[] createLinkString(Map<String, String> params,String partnerSecret) {
 
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        byte[] result = null;
			try {
				String join = prestr+partnerSecret;
				result = join.getBytes("utf-8");//为了不同平台,对字符串进行utf-8编码的byte
				return result;
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				return result;
			}
        
    }

传递的参数要包含以下参数  ,partnerId  合作方   signTimeMax请求时间 ,encrypttype 加密算法类型

除此之外双方还要约定一个密匙 如 123

假如参数去空去 null 后拼接字符串为

param1=1&param2=2&param3=3&signTimeMax=xxxx

这时候需将密匙拼接到字符串最后变为

param1=1&param2=2&param3=3&signTimeMax=xxxx123

3.做算法加密

/**
     * SHA1加密
     * @param data 要处理的数据
     * @param key  加密算法名称
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static byte[] encryptSHA1OrMD5(byte[] data, String key) throws NoSuchAlgorithmException{
    	 MessageDigest messageDigest = MessageDigest.getInstance(key);
         messageDigest.update(data);
    	return messageDigest.digest();
    }

这里 MessageDigest  也能加密为  MD5 。

4.将计算得来的byte[] 转成16进制

/**
     * 将byte转为 HexString
     * @param byteArray
     * @return
     */
    public static String byteArrayToHex(byte[] byteArray) {
        // 首先初始化一个字符数组,用来存放每个16进制字符
        char[] hexDigits = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' };
        // new一个字符数组,这个就是用来组成结果字符串的(解释一下:一个byte是八位二进制,也就是2位十六进制字符)
        char[] resultCharArray =new char[byteArray.length * 2];
        // 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去
        int index = 0;
        for (byte b : byteArray) {
            resultCharArray[index++] = hexDigits[b>>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b& 0xf];
        }
        // 字符数组组合成字符串返回
        return new String(resultCharArray);
    }

这里也不一定要转成16进制,看具体需求。也有可能是 base64转字符串等等。

/**
     * 将byte转为 Base64String
     * @param byteArray
     * @return
     */
    public static String byteArrayToBase64(byte[] byteArray){
    	String base64Str = new String(Base64.encodeBase64(byteArray));
    	return base64Str;
    }

最后方法的调用

/**
     * 
     * @param data 要加密的数据
     * @return signData	加密后的字符串
     * @throws NoSuchAlgorithmException 
     */
    public static String encryptionAlgorithm(Map data,String partnerSecret,String SIGNTYPE) throws NoSuchAlgorithmException{
    	Map map = paraFilter(data);
    	byte[] signDataByte = createLinkString(map,partnerSecret);
    	String signData = byteArrayToHex(encryptSHA1OrMD5(signDataByte, SIGNTYPE));
    	return signData;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值