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

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();
}
}
}