private void PutToCache(string session, Nullable <Int64> secretVersion, SecretContext secretContext) { string cacheKey = GenerateSecretKey(session, secretVersion); lock (CacheLock) { if (session != null) { if (AppUserSecretCache.ContainsKey(cacheKey)) { AppUserSecretCache[cacheKey] = secretContext; } else { AppUserSecretCache.Add(cacheKey, secretContext); } } else { if (AppSecretCache.ContainsKey(cacheKey)) { AppSecretCache[cacheKey] = secretContext; } else { AppSecretCache.Add(cacheKey, secretContext); } } } }
/// <summary> /// 设置空缓存 /// </summary> /// <param name="secretContext"></param> private void SetNullCache(SecretContext secretContext) { long currentTime = TopUtils.GetCurrentTimeMillis(); secretContext.InvalidTime = currentTime + (DEFAULT_INTERVAL * 1000); secretContext.MaxInvalidTime = currentTime + (DEFAULT_MAX_INTERVAL * 1000); }
/// <summary> /// 手机号后4位H-MAC值 /// </summary> /// <param name="data"></param> /// <param name="separator"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string SearchPhoneIndex(string data, string separator, SecretContext secretContext) { if (data.Length != 4) { throw new SecretException("phoneNumber error"); } return(separator + SecurityUtil.HmacMD5EncryptToBase64(data, secretContext.Secret) + separator); }
/// <summary> /// 解密(每个用户单独分配秘钥) /// </summary> /// <param name="data"> /// 密文数据 手机号码格式:$手机号码前3位明文$base64(encrypt(phone后8位))$111$ /// simple格式:~base64(encrypt(nick))~111~ /// </param> /// <param name="type">解密字段类型(例如:simple\phone)</param> /// <param name="session">用户身份,用户级加密必填</param> /// <returns></returns> public string Decrypt(string data, string type, string session) { if (string.IsNullOrEmpty(data) || data.Length < 4) { return(data); } // 获取分隔符 Nullable <char> charValue = null; SecurityBiz.GetSeparatorCharMap().TryGetValue(type, out charValue); if (charValue == null) { throw new SecretException("type error"); } // 校验 char separator = charValue.Value; if (!(data[0] == separator && data[data.Length - 1] == separator)) { return(data); } SecretData secretDataDO = null; if (data[data.Length - 2] == separator) { secretDataDO = SecurityBiz.GetIndexSecretData(data, separator); } else { secretDataDO = SecurityBiz.GetSecretData(data, separator); } // 非法密文 if (secretDataDO == null) { return(data); } // 如果密文数据的版本号小于0代表公共秘钥 if (secretDataDO.SecretVersion < 0) { secretDataDO.SecretVersion = Math.Abs(secretDataDO.SecretVersion.Value); session = null; } securityCounter.AddDecryptCount(type, session);// 计数器 SecretContext secretContextDO = secretCore.GetSecret(session, secretDataDO.SecretVersion); string decryptValue = SecurityUtil.AESDecrypt(secretDataDO.OriginalBase64Value, secretContextDO.Secret); if (PHONE.Equals(type) && !secretDataDO.Search) { // 加上手机号前3位,手机号只加密了后8位 return(secretDataDO.OriginalValue + decryptValue); } return(decryptValue); }
/// <summary> /// 加密之后格式。 手机号码格式:$手机号码前3位明文$base64(encrypt(phone后8位))$111$ /// nick格式:~base64(encrypt(nick))~111~ /// </summary> /// <param name="data">明文数据</param> /// <param name="type">加密字段类型(例如:nick\phone)</param> /// <param name="session">用户身份,用户级加密必填</param> /// <param name="version">秘钥历史版本</param> /// <returns></returns> private string Encrypt(string data, string type, string session, Nullable <Int64> version) { if (string.IsNullOrEmpty(data)) { return(data); } SecretContext secretContext = secretCore.GetSecret(session, version); if (secretContext == null) { throw new SecretException("secretKey is null"); } if (secretContext.Secret == null) { return(data); } string separator = null; SecurityBiz.GetSeparatorMap().TryGetValue(type, out separator); if (separator == null) { throw new SecretException("type error"); } SecurityCounter.AddEncryptCount(type);// 计数器 bool isEncryptIndex = secretCore.IsIndexEncrypt(type, version); // 支持密文检索 if (isEncryptIndex) { if (PHONE.Equals(type)) { return(SecurityBiz.EncryptPhoneIndex(data, separator, secretContext)); } else { int compressLen = secretCore.GetCompressLen(); int slideSize = secretCore.GetSlideSize(); return(SecurityBiz.EncryptNormalIndex(data, compressLen, slideSize, separator, secretContext)); } } else { if (PHONE.Equals(type)) { return(SecurityBiz.EncryptPhone(data, separator, secretContext)); } else { return(SecurityBiz.EncryptNormal(data, separator, secretContext)); } } }
/// <summary> /// 异步更新秘钥 /// </summary> /// <param name="session"></param> /// <param name="secretVersion"></param> private void AsynUpdateSecret(string session, Nullable <Int64> secretVersion) { string cacheKey = GenerateSecretKey(session, secretVersion); lock (AsynQueueKeyLock) { // 不需要重复提交秘钥请求 if (asynQueueKey.ContainsKey(cacheKey)) { return; } SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion)); if (secretContext != null && secretContext.IsValid()) { return; } asynQueueKey.Add(cacheKey, EmptyObject); } WaitCallback secretApiCallback = (state) => { try { CallSecretApi(session, secretVersion); } catch (Exception e) { Log.Error(string.Format("asyn update secret error: {0}", e.Message)); } finally { lock (AsynQueueKeyLock) { asynQueueKey.Remove(cacheKey); } } }; try { ThreadPool.QueueUserWorkItem(secretApiCallback); } catch (Exception e) { lock (AsynQueueKeyLock) { asynQueueKey.Remove(cacheKey); } Log.Error(string.Format("add QueueUserWorkItem error: {0}", e.Message)); } }
/// <summary> /// 加密手机后4位转H-MAC /// </summary> /// <param name="data"></param> /// <param name="separator"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string EncryptPhoneIndex(string data, string separator, SecretContext secretContext) { if (data.Length < 11) { return(data); } // 取后4位 string last4Number = data.Substring(data.Length - 4); return(separator + SecurityUtil.HmacMD5EncryptToBase64(last4Number, secretContext.Secret) + separator + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + secretContext.SecretVersion + separator + separator); }
/// <summary> /// 加密手机尾号后8位 /// </summary> /// <param name="data"></param> /// <param name="separator"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string EncryptPhone(string data, string separator, SecretContext secretContext) { if (data.Length < 11) { return(data); } string prefixNumber = data.Substring(0, data.Length - 8); // 取后8位置 string last8Number = data.Substring(data.Length - 8); return(separator + prefixNumber + separator + SecurityUtil.AESEncrypt(last8Number, secretContext.Secret) + separator + secretContext.SecretVersion + separator); }
/// <summary> /// 滑窗加密 /// </summary> /// <param name="data"></param> /// <param name="compressLen"></param> /// <param name="slideSize"></param> /// <param name="separator"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string EncryptNormalIndex(string data, int compressLen, int slideSize, string separator, SecretContext secretContext) { List <string> slideList = SecurityUtil.GetSlideWindows(data, slideSize); StringBuilder builder = new StringBuilder(); foreach (string slide in slideList) { builder.Append(SecurityUtil.HmacMD5EncryptToBase64(slide, secretContext.Secret, compressLen)); } return(separator + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + builder.ToString() + separator + secretContext.SecretVersion + separator + separator); }
/// <summary> /// 密文检索。 手机号码格式:$base64(H-MAC(phone后4位))$ simple格式:base64(H-MAC(滑窗)) /// </summary> /// <param name="data">明文数据</param> /// <param name="type">加密字段类型(例如:simple\phone)</param> /// <param name="session">用户身份,用户级加密必填</param> /// <param name="version">秘钥历史版本</param> /// <returns></returns> private string Search(string data, string type, string session, Nullable <Int64> version) { if (string.IsNullOrEmpty(data)) { return(data); } SecretContext secretContext = secretCore.GetSecret(session, version); if (secretContext == null) { throw new SecretException("secretKey is null"); } if (secretContext.Secret == null) { return(data); } string separator = null; SecurityBiz.GetSeparatorMap().TryGetValue(type, out separator); if (separator == null) { throw new SecretException("type error"); } // 公共秘钥版本号用负数区分 if (session == null) { SecretContext publicSecretContext = new SecretContext(); publicSecretContext.Secret = secretContext.Secret; publicSecretContext.SecretVersion = -secretContext.SecretVersion; secretContext = publicSecretContext; } securityCounter.AddSearchCount(type, session);// 计数器 if (PHONE.Equals(type)) { return(SecurityBiz.SearchPhoneIndex(data, separator, secretContext)); } else { int compressLen = secretCore.GetCompressLen(); int slideSize = secretCore.GetSlideSize(); return(SecurityBiz.SearchNormalIndex(data, compressLen, slideSize, secretContext)); } }
/// <summary> /// 获取秘钥 /// </summary> /// <param name="session"></param> /// <param name="secretVersion"></param> /// <returns></returns> public SecretContext GetSecret(string session, Nullable <Int64> secretVersion) { SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion)); if (secretContext != null) { if (secretContext.IsValid()) { return(secretContext); } if (secretContext.IsMaxValid()) { // 异步更新秘钥 AsynUpdateSecret(session, secretVersion); return(secretContext); } string cacheKey = GenerateSecretKey(session, secretVersion); lock (CacheLock) { if (session != null) { AppUserSecretCache.Remove(cacheKey); } else { AppSecretCache.Remove(cacheKey); } } // 同步调用获取秘钥 return(CallSecretApi(session, secretVersion)); } else { // 同步调用获取秘钥 return(CallSecretApi(session, secretVersion)); } }
/// <summary> /// 调用获取秘钥api /// </summary> /// <param name="session"></param> /// <param name="secretVersion"></param> /// <returns></returns> private SecretContext CallSecretApi(string session, Nullable <Int64> secretVersion) { // 获取伪随机码 if (string.IsNullOrEmpty(randomNum)) { throw new ArgumentException("randomNum can`t be empty"); } TopSecretGetRequest request = new TopSecretGetRequest(); request.RandomNum = randomNum; request.SecretVersion = secretVersion; if (streetest) { request.AddOtherParameter("tb_eagleeyex_t", "1"); } TopSecretGetResponse response; if (session != null && session.StartsWith(UNDERLINE)) { string customerUserId = session.Substring(1); if (!StringUtil.IsDigits(customerUserId)) { throw new ArgumentException("session invalid"); } request.CustomerUserId = Convert.ToInt64(customerUserId); response = topClient.Execute(request, null); } else { response = topClient.Execute(request, session); } if (!response.IsError) { IDictionary <string, Object> appConfig = null; if (!string.IsNullOrEmpty(response.AppConfig)) { appConfig = (IDictionary <string, Object>)TopUtils.JsonToObject(response.AppConfig); putAppConfig(appConfig); } SecretContext secretContext = new SecretContext(); if (response.Secret != null) { long currentTime = TopUtils.GetCurrentTimeMillis(); secretContext.InvalidTime = currentTime + (response.Interval * 1000); secretContext.MaxInvalidTime = (currentTime + (response.MaxInterval * 1000)); secretContext.Secret = Convert.FromBase64String(response.Secret); secretContext.SecretVersion = response.SecretVersion; } else { if (appConfig != null) { object publishStatus = null; appConfig.TryGetValue(PUBLISH_STATUS, out publishStatus); if (BETA_STATUS.Equals(publishStatus)) { // 设置空缓存 SetNullCache(secretContext); } } } PutToCache(session, secretVersion, secretContext); return(secretContext); } else { // 查找不到历史秘钥 if ("20005".Equals(response.SubErrCode)) { SecretContext secretContext = new SecretContext(); // 设置空缓存 SetNullCache(secretContext); PutToCache(session, secretVersion, secretContext); return(secretContext); } throw new SecretException(response.ErrCode, response.ErrMsg, response.SubErrCode, response.SubErrMsg); } }
/// <summary> /// 密文检索 /// </summary> /// <param name="data"></param> /// <param name="compressLen"></param> /// <param name="slideSize"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string SearchNormalIndex(string data, int compressLen, int slideSize, SecretContext secretContext) { List <string> slideList = SecurityUtil.GetSlideWindows(data, slideSize); StringBuilder builder = new StringBuilder(); foreach (string slide in slideList) { builder.Append(SecurityUtil.HmacMD5EncryptToBase64(slide, secretContext.Secret, compressLen)); } return(builder.ToString()); }
/// <summary> /// 生成密文数据 /// </summary> /// <param name="data"></param> /// <param name="separator"></param> /// <param name="secretContext"></param> /// <returns></returns> public static string EncryptNormal(string data, string separator, SecretContext secretContext) { return(separator + SecurityUtil.AESEncrypt(data, secretContext.Secret) + separator + secretContext.SecretVersion + separator); }