You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
7.5 KiB
245 lines
7.5 KiB
using Google.Protobuf.WellKnownTypes;
|
|
using System;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace Sog
|
|
{
|
|
/// <summary>
|
|
/// Hash辅助类
|
|
/// </summary>
|
|
public class HashHelper
|
|
{
|
|
//注意:这个算法不允许修改!!,改了会导致运营的项目的悲剧
|
|
// 自己实现字符串的hash算法,不用C#缺省的string.HashCode(),方便其他程序和工具计算结果一致
|
|
//这个算法来自Brian Kernighan 和 Dennis Ritchie的 The C Programming Language。
|
|
//这是一个很简单的哈希算法,使用了一系列奇怪的数字,形式如31,3131,31...31,看上去和DJB算法很相似。(这个就是Java的字符串哈希函数)
|
|
//c#内部用的应该和这个类似
|
|
public static int HashStringForIndex(string str)
|
|
{
|
|
const int seed = 131;
|
|
|
|
int hash = 0;
|
|
|
|
for (int i = 0; i < str.Length; i++)
|
|
{
|
|
hash = hash * seed + str[i];
|
|
}
|
|
|
|
//保证正数
|
|
return hash & 0x7FFFFFFF;
|
|
}
|
|
|
|
public static string MD5Bytes(byte[] data)
|
|
{
|
|
return HashBytes(data, "md5");
|
|
}
|
|
|
|
public static string MD5Utf8String(string str)
|
|
{
|
|
var md5 = MD5.Create();
|
|
byte[] strbyte = Encoding.UTF8.GetBytes(str);
|
|
byte[] md5Hash = md5.ComputeHash(strbyte);
|
|
string md5Str = BitConverter.ToString(md5Hash).Replace("-", "").ToLower();
|
|
return md5Str;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算文件的 MD5 值
|
|
/// </summary>
|
|
/// <param name="fileName">要计算 MD5 值的文件名和路径</param>
|
|
/// <returns>MD5 值16进制字符串</returns>
|
|
public static string MD5String(string str)
|
|
{
|
|
return HashString(str, "md5");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算文件的 sha1 值
|
|
/// </summary>
|
|
/// <param name="str">string</param>
|
|
/// <returns>sha1 值16进制字符串</returns>
|
|
public static string SHA1String(string str)
|
|
{
|
|
return HashString(str, "sha1");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算文件的 MD5 值
|
|
/// </summary>
|
|
/// <param name="fileName">要计算 MD5 值的文件名和路径</param>
|
|
/// <returns>MD5 值16进制字符串</returns>
|
|
public static string MD5File(string fileName)
|
|
{
|
|
return HashFile(fileName, "md5");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算文件的 sha1 值
|
|
/// </summary>
|
|
/// <param name="fileName">要计算 sha1 值的文件名和路径</param>
|
|
/// <returns>sha1 值16进制字符串</returns>
|
|
public static string SHA1File(string fileName)
|
|
{
|
|
return HashFile(fileName, "sha1");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算文件的哈希值
|
|
/// </summary>
|
|
/// <param name="str">string</param>
|
|
/// <param name="algName">算法:sha1,md5</param>
|
|
/// <returns>哈希值16进制字符串</returns>
|
|
private static string HashString(string str, string algName)
|
|
{
|
|
if (str == null || algName == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
byte[] array = Encoding.UTF8.GetBytes(str);
|
|
using (MemoryStream stream = new MemoryStream(array))
|
|
{
|
|
byte[] hashBytes = HashData(stream, algName);
|
|
if (hashBytes != null)
|
|
{
|
|
return ByteArrayToHexString(hashBytes);
|
|
}
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 计算文件的哈希值
|
|
/// </summary>
|
|
/// <param name="fileName">要计算哈希值的文件名和路径</param>
|
|
/// <param name="algName">算法:sha1,md5</param>
|
|
/// <returns>哈希值16进制字符串</returns>
|
|
private static string HashFile(string fileName, string algName)
|
|
{
|
|
if (! File.Exists(fileName))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
byte[] hashBytes = HashData(fs, algName);
|
|
fs.Close();
|
|
|
|
if (hashBytes != null)
|
|
{
|
|
return ByteArrayToHexString(hashBytes);
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private static HashAlgorithm CreateHashAlgorithm(string algName)
|
|
{
|
|
HashAlgorithm algorithm = null;
|
|
|
|
if (string.Compare(algName, "sha1", true) == 0)
|
|
{
|
|
algorithm = SHA1.Create();
|
|
}
|
|
else if (string.Compare(algName, "md5", true) == 0)
|
|
{
|
|
algorithm = MD5.Create();
|
|
}
|
|
|
|
return algorithm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算哈希值
|
|
/// </summary>
|
|
/// <param name="stream">要计算哈希值的 Stream</param>
|
|
/// <param name="algName">算法:sha1,md5</param>
|
|
/// <returns>哈希值字节数组</returns>
|
|
private static byte[] HashData(Stream stream, string algName)
|
|
{
|
|
if (algName == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var algorithm = CreateHashAlgorithm(algName);
|
|
if (algorithm == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
return algorithm.ComputeHash(stream);
|
|
}
|
|
catch
|
|
{
|
|
algorithm.Dispose();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static string HashBytes(byte[] data, string algName)
|
|
{
|
|
if (data == null || algName == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var algorithm = CreateHashAlgorithm(algName);
|
|
if (algorithm == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
try
|
|
{
|
|
byte[] hashData = algorithm.ComputeHash(data);
|
|
return ByteArrayToHexString(hashData);
|
|
}
|
|
catch
|
|
{
|
|
algorithm.Dispose();
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 字节数组转换为16进制表示的字符串
|
|
/// </summary>
|
|
private static string ByteArrayToHexString(byte[] buf)
|
|
{
|
|
// stackoverflow有帖子提到BitConverter有的版本会用"-"把bytes分组
|
|
return BitConverter.ToString(buf).Replace("-", "").ToLower();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取HMACSHA256 加密字符串 16位编码
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <param name="mesg"></param>
|
|
/// <returns></returns>
|
|
public static string GetHMACSHA256(string key, string mesg)
|
|
{
|
|
StringBuilder hex = new StringBuilder();
|
|
// 使用UTF-8编码将字符串转换为字节数组
|
|
byte[] keyByte = Encoding.UTF8.GetBytes(key);
|
|
byte[] messageBytes = Encoding.UTF8.GetBytes(mesg);
|
|
// 创建一个新的HMACSHA256实例,使用appKey作为密钥
|
|
using (HMACSHA256 hmac = new HMACSHA256(keyByte))
|
|
{
|
|
byte[] hashMessage = hmac.ComputeHash(messageBytes);
|
|
foreach (byte b in hashMessage)
|
|
{
|
|
hex.AppendFormat("{0:x2}", b);
|
|
}
|
|
}
|
|
return hex.ToString();
|
|
}
|
|
}
|
|
}
|
|
|