package com.gustz.dove.cli.api.security.service.impl; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import com.gustz.dove.cli.api.service.impl.AbstBaseService; import com.gustz.dove.cli.api.service.util.AESCodec; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import com.sinovatech.rd.wcsb.cli.api.security.service.EncryptService; import com.gustz.dove.cli.api.service.util.ClientConstants; /** * * TODO: 加密服务的接口实现 * * @author ZHENFENG ZHANG * @since [ Aug 12, 2015 ] */ @Service public class EncryptServiceImpl extends AbstBaseService<String> implements EncryptService { private final Logger logger = LoggerFactory.getLogger(getClass()); private static final String TMP_KEYT = "19700101-JAVA-010101"; /** * AES加密方式 */ public static String AES_ETYPE = "aes"; /** * RAW加密方式 */ public static String RAW_ETYPE = "raw"; /** * 获取客户端APP凭证 * * @param cliAppCode 客户端APP编码 * @param devAcCode 开发者号 * @param deviceCode 设备编码(手机设备) * @return * @throws Exception */ private String getCliAppSecret(final String cliAppCode, String devAcCode, String deviceCode) throws Exception { logger.info("获取客户端APP密钥 参数cliAppCode[{}] devAcCode[{}] deviceCode[{}].", cliAppCode, devAcCode, deviceCode); // if (StringUtils.isBlank(cliAppCode) || StringUtils.isBlank(devAcCode) || StringUtils.isBlank(deviceCode)) { throw new IllegalArgumentException("Args client app code/dev acount code/device id is null."); } // 转为16进制字符串 1. final StringBuffer sbf = new StringBuffer(Hex.encodeHexString(cliAppCode.getBytes(ClientConstants.CHARSET))); sbf.append(devAcCode).append(deviceCode); // 获取消息摘要(原始密钥data) final String _data = getPubDigest40(sbf.insert(1, "!@#").insert(sbf.length() - 3, ")(*").append("A").reverse().toString()); // 新密钥 2. final String _seed = getSecretSeed(devAcCode, deviceCode); // 执行加密 4. return AESCodec.encrypt(_seed, _data); } /** * 获取开发者密钥AES * * @param cliAppCode 客户端APP编码 * @param devAcCode 开发者号 * @param wecAppId 微信APP ID * @return */ @Override public String getDevAesKeyt(String cliAppCode, String devAcCode, String wecAppId) { logger.info("获取开发者密钥AES 参数cliAppCode[{}] []", cliAppCode); // Assert.hasText(cliAppCode, "client app code"); Assert.hasText(devAcCode, "dev accoutcode"); Assert.hasText(wecAppId, "wechat app id"); try { // Base64转码 final StringBuffer sbf = new StringBuffer(); sbf.append(Base64.encodeBase64String((cliAppCode + devAcCode + wecAppId).getBytes(ClientConstants.CHARSET))); // final String _key = sbf.insert(2, "(*&").insert(sbf.length() - 2, "@#$").append("B").toString(); // 获取消息摘要 return getPubDigest40(_key) + "000"; } catch (Exception e) { logger.error("获取开发者密钥AES异常\n", e); } return ClientConstants.FAIL_RSP; } /** * 获取开发者token * * @param devAcCode 开发者号 * @param wecAppId 微信APP ID * @return */ @Override public String getDevToken(String devAcCode, String wecAppId) { logger.info("获取开发者token 参数devAcCode[{}].", devAcCode); // Assert.hasText(devAcCode, "dev accoutcode"); Assert.hasText(wecAppId, "wechat app id"); try { // Base64转码 final StringBuffer sbf = new StringBuffer(); sbf.append(Base64.encodeBase64String((devAcCode + wecAppId).getBytes(ClientConstants.CHARSET))); // final String _key = sbf.insert(2, "@#$").insert(sbf.length() - 6, "^&*").append("C").reverse().toString(); // 获取消息摘要 return getPubDigest32(_key); } catch (Exception e) { logger.error("获取开发者token异常\n", e); } return ClientConstants.FAIL_RSP; } /** * 获取公用的消息摘要40 * * @param data * @return * @throws NoSuchAlgorithmException */ private static String getPubDigest40(final String data) throws NoSuchAlgorithmException { // MD5密钥生成 1. MessageDigest _md5 = MessageDigest.getInstance(ClientConstants.MD5_ALGO); _md5.update(data.getBytes(ClientConstants.CHARSET)); final String _data2 = Base64.encodeBase64String(_md5.digest()); // SHA1密钥生成 2. MessageDigest _sha = MessageDigest.getInstance(ClientConstants.SHA_ALGO); _sha.update(_data2.getBytes(ClientConstants.CHARSET)); // return Hex.encodeHexString(_sha.digest()); } /** * 获取公用的消息摘要32 * * @param data * @return * @throws NoSuchAlgorithmException */ private static String getPubDigest32(final String data) throws NoSuchAlgorithmException { // SHA1密钥生成 1. MessageDigest _sha = MessageDigest.getInstance(ClientConstants.SHA_ALGO); _sha.update(data.getBytes(ClientConstants.CHARSET)); final String _data2 = Base64.encodeBase64String(_sha.digest()); // MD5密钥生成 2. MessageDigest _md5 = MessageDigest.getInstance(ClientConstants.MD5_ALGO); _md5.update(_data2.getBytes(ClientConstants.CHARSET)); // return Hex.encodeHexString(_md5.digest()); } /** * 加密客户端APP数据 * * @param cliAppCode 客户端APP编码 * @param userAcCode 账号/微信号 * @param deviceCode 设备编码(手机设备) * @param data 明文数据 * @return 密文数据 */ @Override public String encryptCliAppData(final String cliAppCode, String userAcCode, String deviceCode, String data) { try { // 复合密钥 final String appSecret = this.getCliAppSecret(cliAppCode, userAcCode, deviceCode); // 旧密钥 1. final String _seed = getSecretSeed(userAcCode, deviceCode); // 新密钥 2. final String _newKeyt = AESCodec.decrypt(_seed, appSecret); // 执行加密 return AESCodec.encrypt(getSecretSeed(_newKeyt, TMP_KEYT), data); } catch (Exception e) { logger.error("加密客户端APP数据异常\n", e); throw new IllegalStateException(e); } } /** * 解密客户端APP数据 * * @param cliAppCode 客户端APP编码 * @param userAcCode 账号/微信号 * @param deviceCode 设备编码(手机设备) * @param encryptData 密文数据 * @return 明文数据 */ @Override public String decryptCliAppData(final String cliAppCode, String userAcCode, String deviceCode, String encryptData) { try { // 复合密钥 final String appSecret = this.getCliAppSecret(cliAppCode, userAcCode, deviceCode); // 旧密钥 1. final String _seed = getSecretSeed(userAcCode, deviceCode); // 新密钥 2. final String _newKeyt = AESCodec.decrypt(_seed, appSecret); // 执行加密 return AESCodec.decrypt(getSecretSeed(_newKeyt, TMP_KEYT), encryptData); } catch (Exception e) { logger.error("解密客户端APP数据异常\n", e); throw new IllegalStateException(e); } } private static String getSecretSeed(String code, String code2) throws NoSuchAlgorithmException { return code + "-" + code2; } @Override protected void setAccessTokenX(long sn, String cliAppCode, String devAcCode) { //ignored } }