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

com.taobao.api.security.SecurityClient Maven / Gradle / Ivy

The newest version!
package com.taobao.api.security;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.taobao.api.ApiException;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.SecretException;
import com.taobao.api.internal.util.Base64;
import com.taobao.api.internal.util.StringUtils;
import com.taobao.api.internal.util.TaobaoUtils;

/**
 * 加、解密客户端(单例使用,不要初始化多个)
 * 
 * @author changchun
 * @since 2016年2月26日 下午5:15:17
 */
public class SecurityClient {

    public static final String NICK = "nick";
    public static final String PHONE = "phone";
    public static final String NORMAL = "normal";
    public static final char NICK_SEPARATOR_CHAR = '~';
    public static final String NICK_SEPARATOR = String.valueOf(NICK_SEPARATOR_CHAR);
    public static final char PHONE_SEPARATOR_CHAR = '$';
    public static final String PHONE_SEPARATOR = String.valueOf(PHONE_SEPARATOR_CHAR);
    public static final char NORMAL_SEPARATOR_CHAR = (char) 0x01;
    public static final String NORMAL_SEPARATOR = String.valueOf(NORMAL_SEPARATOR_CHAR);
    public static final Map CHAR_MAP = new HashMap();
    static {
        CHAR_MAP.put(NICK, NICK_SEPARATOR_CHAR);
        CHAR_MAP.put(NORMAL, NORMAL_SEPARATOR_CHAR);
        CHAR_MAP.put(PHONE, PHONE_SEPARATOR_CHAR);
    }
    
    // 秘钥管理核心类
    private SecurityCore secretCore;

    /**
     * 
     * @param defaultTaobaoClient
     *            serverUrl必须是https协议
     * @param randomNum
     *            伪随机码
     */
    public SecurityClient(DefaultTaobaoClient defaultTaobaoClient, String randomNum) {
        this(defaultTaobaoClient, randomNum, 2, 8, Integer.MAX_VALUE);
    }

    /**
     * 
     * @param defaultTaobaoClient
     *            serverUrl必须是https协议
     * @param randomNum
     *            伪随机码
     * @param corePoolSize
     *            核心线程数
     * @param maxPoolSize
     *            最大线程数
     * @param maxQueue
     *            线程池最大队列
     */
    public SecurityClient(DefaultTaobaoClient defaultTaobaoClient, String randomNum, int corePoolSize, int maxPoolSize,
            int maxQueue) {
        secretCore = new SecurityCore(defaultTaobaoClient, randomNum, corePoolSize, maxPoolSize, maxQueue);
    }

    /**
     * 初始化秘钥(如果半小时内会调用加、解密方法,建议先初始化秘钥)。所有用户共用秘钥
     * 
     * @throws ApiException
     */
    public void initSecret() throws ApiException {
        secretCore.getSecret(null, null);
    }

    public void setRandomNum(String randomNum) {
        this.secretCore.setRandomNum(randomNum);
    }

    /**
     * 初始化秘钥(如果半小时内会调用加、解密方法,建议先初始化秘钥)。每个用户单独分配秘钥
     * 
     * @param session
     * @throws ApiException
     */
    public void initSecret(String session) throws ApiException {
        secretCore.getSecret(session, null);
    }

    /**
     * 批量解密(所有用户共用秘钥)
     * 
     * @see #decrypt(List, String, String)
     * @param dataList
     * @param type
     * @throws SecretException
     */
    public Map decrypt(List dataList, String type) throws SecretException {
        return decrypt(dataList, type, null);
    }

    /**
     * 批量解密(每个用户单独分配秘钥)
     * 
     * @see #decrypt(String, String, String)
     * @param dataList
     * @param type
     * @param session
     * @return key=密文数据,value=明文数据
     * @throws SecretException
     */
    public Map decrypt(List dataList, String type, String session) throws SecretException {
        if (dataList == null || dataList.isEmpty()) {
            throw new SecretException("dataList can`t be empty");
        }
        Map resultMap = new HashMap();
        for (String data : dataList) {
            String decryptValue = decrypt(data, type, session);
            resultMap.put(data, decryptValue);
        }
        return resultMap;
    }

    /**
     * 解密(所有用户共用秘钥)
     * 
     * @see #decrypt(String, String, String)
     * 
     * @param data
     * @param type
     * @return
     * @throws SecretException
     */
    public String decrypt(String data, String type) throws SecretException {
        return decrypt(data, type, null);
    }

    /**
     * 解密(每个用户单独分配秘钥)
     * 
     * @param data
     *            密文数据 手机号码格式:$手机号码前3位明文$base64(encrypt(phone后8位置))$111$
     *            nick格式:~base64(encrypt(nick))~111~
     * @param type
     *            解密字段类型(例如:nick\phone)
     * @param session
     *            用户身份,用户级加密必填
     * @return
     */
    public String decrypt(String data, String type, String session) throws SecretException {
        if (StringUtils.isEmpty(data) || data.length() < 4) {
            return data;
        }

        SecretData secretDataDO = null;
        if (NICK.equals(type)) {
            if (!(data.startsWith(NICK_SEPARATOR) && data.endsWith(NICK_SEPARATOR))) {
                return data;
            }
            secretDataDO = SecurityCore.getSecretData(data, NICK_SEPARATOR_CHAR);
        } else if (PHONE.equals(type)) {
            if (!(data.startsWith(PHONE_SEPARATOR) && data.endsWith(PHONE_SEPARATOR))) {
                return data;
            }
            secretDataDO = SecurityCore.getSecretData(data, PHONE_SEPARATOR_CHAR);
        } else if (NORMAL.equals(type)) {
            if (!(data.startsWith(NORMAL_SEPARATOR) && data.endsWith(NORMAL_SEPARATOR))) {
                return data;
            }
            secretDataDO = SecurityCore.getSecretData(data, NORMAL_SEPARATOR_CHAR);
        } else {
            throw new SecretException("type error");
        }

        try {
            SecretContext secretContextDO = secretCore.getSecret(session, secretDataDO.getSecretVersion());
            String decryptValue = TaobaoUtils.aesDecrypt(secretDataDO.getOriginalBase64Value(), secretContextDO.getSecret());
            if (PHONE.equals(type)) {
                // 加上手机号前3位,手机号只加密了后8位
                return secretDataDO.getPrefixValue() + decryptValue;
            }
            return decryptValue;
        } catch (ApiException e) {
            throw new SecretException("get secret error", e);
        }

    }
    
    /**
     * 判断list原始是否全部为密文数据
     * 
     * @see #isEncryptData(String, String)
     * 
     * @param dataList
     * 
     * @param type
     *            加密字段类型(例如:nick\phone)
     * @return
     * @throws SecretException
     */
    public static boolean isEncryptData(List dataList, String type) throws SecretException {
        if (dataList == null || dataList.isEmpty()) {
            return false;
        }
        boolean result = false;
        for (String data : dataList) {
            result = isEncryptData(data, type);
            if (!result) {
                return false;
            }
        }
        return result;
    }

    /**
     * 判断是否密文数据
     * 
     * @param data
     * 
     * @param type
     *            加密字段类型(例如:nick\phone)
     * @return
     * @throws SecretException
     */
    public static boolean isEncryptData(String data, String type) throws SecretException {
        if (StringUtils.isEmpty(data) || data.length() < 4) {
            return false;
        }

        Character charValue = CHAR_MAP.get(type);
        if (charValue == null) {
            throw new SecretException("type error");
        }
        char separatorChar = charValue.charValue();
        if ((separatorChar == NICK_SEPARATOR_CHAR) || (separatorChar == NORMAL_SEPARATOR_CHAR)) {
            if (data.charAt(0) == separatorChar && data.charAt(data.length() - 1) == separatorChar) {
                for (int i = data.length() - 3; i > 1; i--) {
                    char value = data.charAt(i);
                    if (separatorChar == value) {
                        String version = data.substring(i + 1, data.length() - 1);
                        if (StringUtils.isDigits(version) && Long.valueOf(version) > 0) {
                            boolean isBase64Value = Base64.isBase64Value(data.substring(1, i));
                            if (isBase64Value) {
                                return true;
                            }
                        }
                        return false;
                    }
                }
            }
        } else if (separatorChar == PHONE_SEPARATOR_CHAR) {
            for (int i = data.length() - 3; i > 1; i--) {
                char value = data.charAt(i);
                if (separatorChar == value) {
                    // 手机号码前缀
                    int phonePrefixIndex = data.indexOf(separatorChar, 1);
                    if (phonePrefixIndex != i) {
                        String version = data.substring(i + 1, data.length() - 1);
                        if (StringUtils.isDigits(version) && Long.valueOf(version) > 0) {
                            boolean isBase64Value = Base64.isBase64Value(data.substring(phonePrefixIndex + 1, i));
                            if (isBase64Value) {
                                return true;
                            }
                        }
                    }
                    return false;
                }
            }
        }
        return false;
    }

    /**
     * 加密(所有用户共用秘钥)
     * 
     * @see #encrypt(String, String, String, Long)
     * 
     * @param data
     * @param type
     * @return
     * @throws SecretException
     */
    public String encrypt(String data, String type) throws SecretException {
        return encrypt(data, type, null, null);
    }
    
    /**
     * 用老秘钥加密,只在秘钥升级时使用(所有用户共用秘钥)
     * 
     * @see #encrypt(String, String, String, Long)
     * 
     * @param data
     * @param type
     * @return
     * @throws SecretException
     */
    public String encryptPrevious(String data, String type) throws SecretException {
        return encrypt(data, type, null, -1L);
    }

    /**
     * 加密(每个用户单独分配秘钥)
     * 
     * @see #encrypt(String, String, String, Long)
     * @return
     */
    public String encrypt(String data, String type, String session) throws SecretException {
        return encrypt(data, type, session, null);
    }

    /**
     * 用老秘钥加密,只在秘钥升级时使用(每个用户单独分配秘钥)
     * 
     * @see #encrypt(String, String, String, Long)
     * @return
     */
    public String encryptPrevious(String data, String type, String session) throws SecretException {
        return encrypt(data, type, session, -1L);
    }

    /**
     * 加密之后格式。
     * 手机号码格式:$手机号码前3位明文$base64(encrypt(phone后8位置))$111$
     * nick格式:~base64(encrypt(nick))~111~
     * 
     * @param data
     *            明文数据
     * @param type
     *            加密字段类型(例如:nick\phone)
     * @param session
     *            用户身份,用户级加密必填
     * @param version
     *            秘钥历史版本
     * @return
     */
    private String encrypt(String data, String type, String session, Long version) throws SecretException {
        if (StringUtils.isEmpty(data)) {
            return data;
        }
        try {
            SecretContext secretContext = secretCore.getSecret(session, version);
            if (secretContext == null) {
                throw new SecretException("secretKey is null");
            }
            if (secretContext.getSecret() == null) {
                return data;
            }

            if (NICK.equals(type)) {
                return NICK_SEPARATOR + TaobaoUtils.aesEncrypt(data, secretContext.getSecret()) + NICK_SEPARATOR
                        + secretContext.getSecretVersion() + NICK_SEPARATOR;
            } else if (PHONE.equals(type)) {
                if (data.length() < 11) {
                    throw new SecretException("phoneNumber error");
                }
                String prefixNumber = data.substring(0, data.length() - 8);
                // 取后8位置
                String last8Number = data.substring(data.length() - 8);

                return PHONE_SEPARATOR + prefixNumber + PHONE_SEPARATOR
                        + TaobaoUtils.aesEncrypt(last8Number, secretContext.getSecret()) + PHONE_SEPARATOR
                        + secretContext.getSecretVersion() + PHONE_SEPARATOR;
            } else if (NORMAL.equals(type)) {
                return NORMAL_SEPARATOR + TaobaoUtils.aesEncrypt(data, secretContext.getSecret()) + NORMAL_SEPARATOR
                        + secretContext.getSecretVersion() + NORMAL_SEPARATOR;
            } else {
                throw new SecretException("type error");
            }
        } catch (ApiException e) {
            throw new SecretException("get secret error", e);
        }
    }

    /**
     * 批量加密(所有用户共用秘钥)
     * 
     * @see #encrypt(List, String, String)
     * @param dataList
     * @param type
     * @return
     * @throws SecretException
     */
    public Map encrypt(List dataList, String type) throws SecretException {
        return encrypt(dataList, type, null);
    }

    /**
     * 批量加密(每个用户单独分配秘钥)
     * 
     * @see #encrypt(String, String, String, Long)
     * @param dataList
     * @param type
     * @param session
     * @return key=明文数据,value=密文数据
     * @throws SecretException
     */
    public Map encrypt(List dataList, String type, String session) throws SecretException {
        if (dataList == null || dataList.isEmpty()) {
            throw new SecretException("dataList can`t be empty");
        }
        Map resultMap = new HashMap();
        for (String data : dataList) {
            String encryptValue = encrypt(data, type, session, null);
            resultMap.put(data, encryptValue);
        }
        return resultMap;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy