All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.api.internal.util.TaobaoUtils Maven / Gradle / Ivy

package com.taobao.api.internal.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import com.taobao.api.ApiException;
import com.taobao.api.Constants;
import com.taobao.api.SecretException;
import com.taobao.api.TaobaoResponse;
import com.taobao.api.internal.parser.json.ObjectJsonParser;
import com.taobao.api.internal.util.json.JSONReader;
import com.taobao.api.internal.util.json.JSONValidatingReader;
import com.taobao.api.internal.util.json.JSONWriter;

/**
 * 系统工具类。
 * 
 * @author carver.gu
 * @since 1.0, Sep 12, 2009
 */
public abstract class TaobaoUtils {
    private static final byte[] IV_BYTES = "0102030405060708".getBytes();
    private static final String AES = "AES";
    private static String intranetIp;
    private static final String MAC_HMAC_MD5 = "HmacMD5";

    private TaobaoUtils() {
    }

    /**
     * 给TOP请求签名。
     * 
     * @param requestHolder
     *            所有字符型的TOP请求参数
     * @param secret
     *            签名密钥
     * @param signMethod
     *            signMethod 签名方法,目前支持:空(老md5)、md5, hmac_md5三种
     * @return 签名
     */
    public static String signTopRequest(RequestParametersHolder requestHolder, String secret, String signMethod)
            throws IOException {
        return signTopRequest(requestHolder.getAllParams(), null, secret, signMethod);
    }

    /**
     * 给TOP请求签名。
     * 
     * @param params
     *            所有字符型的TOP请求参数
     * @param body
     *            请求主体内容
     * @param secret
     *            签名密钥
     * @param signMethod
     *            签名方法,目前支持:空(老md5)、md5, hmac_md5三种
     * @return 签名
     */
    public static String signTopRequest(Map params, String body, String secret, String signMethod)
            throws IOException {
        // 第一步:检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);

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

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

        // 第四步:使用MD5/HMAC加密
        byte[] bytes;
        if (Constants.SIGN_METHOD_HMAC.equals(signMethod)) {
            bytes = encryptHMAC(query.toString(), secret);
        } else if (Constants.SIGN_METHOD_HMAC_SHA256.equals(signMethod)) {
            bytes = encryptHMACSHA256(query.toString(), secret);
        }  else {
            query.append(secret);
            bytes = encryptMD5(query.toString());
        }

        // 第五步:把二进制转化为大写的十六进制
        return byte2hex(bytes);
    }

    /**
     * 给TOP带body体的请求签名,适用于TOP批量API和奇门API的请求签名。
     * 
     * @param requestHolder
     *            所有字符型的TOP请求参数
     * @param body
     *            请求body体
     * @param secret
     *            签名密钥
     * @return 签名
     */
    public static String signTopRequestWithBody(RequestParametersHolder requestHolder, String body, String secret,
            String signMethod) throws IOException {
        Map params = requestHolder.getAllParams();
        return signTopRequest(params, body, secret, signMethod);
    }
    
    private static byte[] encryptHMACSHA256(String data, String secret) throws IOException  {
    	byte[] bytes = null;
    	try {
	        SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), "HmacSHA256");
	        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
	        mac.init(secretKey);
	        bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8));
    	} catch (GeneralSecurityException gse) {
            throw new IOException(gse.toString());
        }
        return bytes;
    }

    private static byte[] encryptHMAC(String data, String secret) throws IOException {
        byte[] bytes = null;
        try {
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), "HmacMD5");
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8));
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse.toString());
        }
        return bytes;
    }

    /**
     * 对字符串采用UTF-8编码后,用MD5进行摘要。
     */
    public static byte[] encryptMD5(String data) throws IOException {
        return encryptMD5(data.getBytes(Constants.CHARSET_UTF8));
    }

    /**
     * 对字节流进行MD5摘要。
     */
    public static byte[] encryptMD5(byte[] data) throws IOException {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data);
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse.toString());
        }
        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();
    }

    /**
     * 清除字典中值为空的项。
     * 
     * @param 
     *            泛型
     * @param map
     *            待清除的字典
     * @return 清除后的字典
     */
    public static  Map cleanupMap(Map map) {
        if (map == null || map.isEmpty()) {
            return null;
        }

        Map result = new HashMap(map.size());
        Set> entries = map.entrySet();

        for (Entry entry : entries) {
            if (entry.getValue() != null) {
                result.put(entry.getKey(), entry.getValue());
            }
        }

        return result;
    }

    /**
     * 把JSON字符串转化为对象结构。
     * 
     * @param json
     *            JSON字符串
     * @return 对象结构,一般为Map
     */
    public static Object jsonToObject(String json) {
        JSONReader jr = new JSONValidatingReader();
        return jr.read(json);
    }

    /**
     * 把对象结构转换为JSON字符串。
     * 
     * @param object
     *            对象结构
     * @return JSON字符串
     */
    public static String objectToJson(Object object) {
        JSONWriter writer = new JSONWriter(false, true);
        return writer.write(object);
    }

    /**
     * 把对象结构转换为XML字符串。
     * 
     * @param object
     *            对象结构
     * @return XML字符串
     */
    public static String objectToXml(Object object) {
        XmlWriter writer = new XmlWriter();
        return writer.write(object);
    }

    /**
     * 把JSON字符串解释为对象结构。
     * 
     * @param 
     *            API响应类型
     * @param json
     *            JSON字符串
     * @param clazz
     *            API响应类
     * @return API响应对象
     */
    public static  T parseResponse(String json, Class clazz) throws ApiException {
        ObjectJsonParser parser = new ObjectJsonParser(clazz);
        T rsp = parser.parse(json, Constants.RESPONSE_TYPE_TOP);
        rsp.setBody(json);
        return rsp;
    }

    /**
     * 获取本机的局域网IP。
     */
    public static String getIntranetIp() {
        if (intranetIp == null) {
            try {
                intranetIp = InetAddress.getLocalHost().getHostAddress();
            } catch (Exception e) {
                intranetIp = "127.0.0.1";
            }
        }
        return intranetIp;
    }

    public static String aesEncrypt(String content, byte[] encryptKey) throws SecretException {
        try {
            return aesEncrypt(content.getBytes(Constants.CHARSET_UTF8), encryptKey);
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }

    /**
     * AES解密
     * 
     * @param content
     *            待解密的byte[]
     * @param decryptKey
     *            解密密钥
     * @return 解密后的byte
     * @throws SecretException
     */
    public static String aesDecrypt(String content, byte[] decryptKey) throws SecretException {
        try {
            return new String(aesDecrypt(content.getBytes(Constants.CHARSET_UTF8), decryptKey), Constants.CHARSET_UTF8);
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }

    /**
     * AES解密
     * 
     * @param encryptBytes
     *            待解密的byte[]
     * @param decryptKey
     *            解密密钥
     * @return 解密后的byte
     * @throws SecretException
     */
    public static byte[] aesDecrypt(byte[] encryptBytes, byte[] decryptKey) throws SecretException {
        IvParameterSpec iv = new IvParameterSpec(IV_BYTES);
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey, AES), iv);
            return cipher.doFinal(Base64.decode(encryptBytes));
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }

    /**
     * AES加密
     * 
     * @param content
     *            待加密的内容
     * @param encryptKey
     *            加密密钥
     * @return 加密后的byte[]
     * @throws SecretException
     */
    public static String aesEncrypt(byte[] content, byte[] encryptKey) throws SecretException {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance(AES);
            kgen.init(new SecureRandom(encryptKey));

            IvParameterSpec iv = new IvParameterSpec(IV_BYTES);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey, AES), iv);

            return base64Encode(cipher.doFinal(content));
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }
    
    public static void main(String[] args) throws SecretException {
    }

    /**
     * . BASE64 编码(byte[]).
     *
     * @param src
     *            byte[] inputed string
     * @return String returned string
     */
    public static String base64Encode(byte[] src) {
        try {
            return base64Encode(src, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * . BASE64 编码(byte[]).
     *
     * @param src
     *            byte[] inputed string
     * @param charsetName
     * @return String returned string
     * @throws UnsupportedEncodingException
     */
    public static String base64Encode(byte[] src, String charsetName) throws UnsupportedEncodingException {
        byte[] res = Base64.encodeToByte(src, false);
        return (src != null ? new String(res, charsetName) : null);
    }

    /**
     * @see #hmacMD5Encrypt(String, byte[])
     * 
     * @param encryptText
     *            被签名的字符串
     * @param encryptKey
     *            密钥
     * @return
     * @throws Exception
     */
    public static String hmacMD5EncryptToBase64(String encryptText, byte[] encryptKey, int compressLen) throws SecretException {
        try {
            return base64Encode(compress(hmacMD5Encrypt(encryptText, encryptKey), compressLen));
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }

    /**
     * @see #hmacMD5Encrypt(String, byte[])
     * 
     * @param encryptText
     *            被签名的字符串
     * @param encryptKey
     *            密钥
     * @return
     * @throws Exception
     */
    public static String hmacMD5EncryptToBase64(String encryptText, byte[] encryptKey) throws SecretException {
        try {
            return base64Encode(hmacMD5Encrypt(encryptText, encryptKey));
        } catch (Exception e) {
            throw new SecretException(e);
        }
    }

    /**
     * 使用 HMAC-MD5 签名方法对对encryptText进行签名
     * 
     * @param encryptText
     *            被签名的字符串
     * @param encryptKey
     *            密钥
     * @return
     * @throws Exception
     */
    public static byte[] hmacMD5Encrypt(String encryptText, byte[] encryptKey) throws Exception {
        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        SecretKey secretKey = new SecretKeySpec(encryptKey, MAC_HMAC_MD5);
        // 生成一个指定 Mac 算法 的 Mac 对象
        Mac mac = Mac.getInstance(MAC_HMAC_MD5);
        // 用给定密钥初始化 Mac 对象
        mac.init(secretKey);

        byte[] text = encryptText.getBytes(Constants.CHARSET_UTF8);
        // 完成 Mac 操作
        return mac.doFinal(text);
    }

    /**
     * 生成滑动窗口
     * 
     * @param input
     * @param slideSize
     * @return
     */
    public static List getSlideWindows(String input, int slideSize) {
        List windows = new ArrayList();
        int startIndex = 0;
        int endIndex = 0;
        int currentWindowSize = 0;
        String currentWindow = null;

        while (endIndex < input.length() || currentWindowSize > slideSize) {
            boolean startsWithLetterOrDigit;
            if (currentWindow == null) {
                startsWithLetterOrDigit = false;
            } else {
                startsWithLetterOrDigit = isLetterOrDigit(currentWindow.charAt(0));
            }

            if (endIndex == input.length() && !startsWithLetterOrDigit) {
                break;
            }

            if (currentWindowSize == slideSize && !startsWithLetterOrDigit && isLetterOrDigit(input.charAt(endIndex))) {
                endIndex++;
                currentWindow = input.substring(startIndex, endIndex);
                currentWindowSize = 5;

            } else {
                if (endIndex != 0) {
                    if (startsWithLetterOrDigit) {
                        currentWindowSize -= 1;
                    } else {
                        currentWindowSize -= 2;
                    }
                    startIndex++;
                }

                while (currentWindowSize < slideSize && endIndex < input.length()) {
                    char currentChar = input.charAt(endIndex);
                    if (isLetterOrDigit(currentChar)) {
                        currentWindowSize += 1;
                    } else {
                        currentWindowSize += 2;
                    }
                    endIndex++;
                }
                currentWindow = input.substring(startIndex, endIndex);

            }
            windows.add(currentWindow);
        }
        return windows;
    }
    
    private static boolean isLetterOrDigit(char x) {
        if (0 <= x && x <= 127) {
            return true;
        }
        return false;
    }

    private static byte[] compress(byte[] input, int toLength) {
        if (toLength < 0) {
            return null;
        }
        byte[] output = new byte[toLength];
        for (int i = 0; i < output.length; i++) {
            output[i] = 0;
        }

        for (int i = 0; i < input.length; i++) {
            int index_output = i % toLength;
            output[index_output] ^= input[i];
        }

        return output;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy