GUID和散列算法(C#)

本文介绍C#代码中如何获取GUID,以及几种常用的散列算法,如MD5、SHA-1、SHA-256、SHA-384和SHA-512算法。

GUID

GUID可以在计算机中生成唯一的代码,用于标识需要唯一ID的资源。C#代码中获取GUID可以使用System命名空间中的Guid结构;为方便使用,可以在cfx/Encode.cs文件中封装相关功能,如下面的代码。

C#
using System;
using System.Text;
using System.Security.Cryptography;

namespace cfx
{
    public static class Encode
    {
        // guid字符串
        public static string GetGuid()
        {
            return Guid.NewGuid().ToString("N");
        }
    }
}

代码中使用Guid结构的NewGuid()静态方法生成新的Guid实例,然后通过ToString()方法获取其字符串格式,请注意方法的参数,可以设置为:

  • "D","b563915c-45d8-4e2e-9d15-7d79815a3e18"格式,如果不指定参数,默认使用此格式。
  • "N","a2d12e04215c4e48b28a7c4252b53b84"格式。这也是封装代码中使用的格式,总是返回32个字符的GUID字符串,在数据库中可以使用定长文本字段保存此数据。
  • "B","{0809f5c9-9653-4637-acc7-ac8c68d3a929}"格式。
  • "P","(f5c56e19-34b4-4e8b-8939-4dc62005f2fd)"格式。
  • "X","{0x46c479f2,0x1f47,0x4890,{0x83,0xa2,0x66,0x75,0x0b,0xab,0xa4,0x70}}"格式。

MD5和SHA算法

基本的散列算法包括MD和SHA系列算法,下面先来看如何将字符串通过MD5算法进行散列处理(cfx/Encode.cs)。

C#
using System;
using System.Text;
using System.Security.Cryptography;

namespace cfx
{
    public static class Encode
    {
        // 其它代码
        //将字符串转换为字节数组
        public static byte[] StrToByte(string s)
        {
            try { return Encoding.Default.GetBytes(s); }
            catch { return null; }
        }

        //将字节数组内容以十六进制字符串显示
        public static string ByteToHexStr(byte[] b)
        {
            try
            {
                StringBuilder result =
                    new StringBuilder(b.Length * 2);
                for (int i = 0; i < b.Length; i++)
                {
                    result.Append(b[i].ToString("X2"));
                }
                return result.ToString();
            }
            catch { return ""; }
        }
        // 散列编码
        public static string Md5(this string s)
        {
            byte[] b = StrToByte(s);
            using (MD5CryptoServiceProvider csp =
                new MD5CryptoServiceProvider())
            {
                byte[] hash = csp.ComputeHash(b);
                return ByteToHexStr(hash);
            }
        }
    }
}

代码中,首先定义了StrToByte()和ByteToHexStr()方法,其中,StrToByte()方法的功能是将字符串转换为字节数组,ByteToHexStr()方法是将字节数组转换为十六进制形式的字符串,其中字母使用大写形式。Md5()方法定义为string类型的扩展方法,其中主要使用MD5CryptoServiceProvider类实现MD5算法。下面的代码,在Program.cs代码中测试Md5()方法的应用。

C#
using System;
using cfx;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("123456".Md5());
            Console.WriteLine(Encode.Md5("123456"));
        }
    }
}

本例会显示两行相同的内容。

SHA算法包括SHA-1、SHA-256、SHA-384、SHA-512等,下面是对字符串进行散列处理的封装方法(cfx/Encode.cs)。

C#
using System;
using System.Text;
using System.Security.Cryptography;

namespace cfx
{
    public static class Encode
    {
        // 其它代码
        //
        public static string Sha1(this string s)
        {
            byte[] b = StrToByte(s);
            using (SHA1CryptoServiceProvider csp =
                new SHA1CryptoServiceProvider())
            {
                byte[] hash = csp.ComputeHash(b);
                return ByteToHexStr(hash);
            }
        }
        //
        public static string Sha256(this string s)
        {
            byte[] b = StrToByte(s);
            using (SHA256CryptoServiceProvider csp =
                new SHA256CryptoServiceProvider())
            {
                byte[] hash = csp.ComputeHash(b);
                return ByteToHexStr(hash);
            }
        }
        //
        public static string Sha384(this string s)
        {
            byte[] b = StrToByte(s);
            using (SHA384CryptoServiceProvider csp =
                new SHA384CryptoServiceProvider())
            {
                byte[] hash = csp.ComputeHash(b);
                return ByteToHexStr(hash);
            }
        }
        //
        public static string Sha512(this string s)
        {
            byte[] b = StrToByte(s);
            using (SHA512CryptoServiceProvider csp =
                new SHA512CryptoServiceProvider())
            {
                byte[] hash = csp.ComputeHash(b);
                return ByteToHexStr(hash);
            }
        }
    }
}

代码中主要使用了SHA1CryptoServiceProvider、SHA256CryptoServiceProvider、SHA384CryptoServiceProvider、SHA512CryptoServiceProvider类分别实现SHA-1、SHA-256、SHA-384和SHA-512算法。实现应用中,建议使用较复杂的SHA-384和SHA-512算法对文本内容进行加密,如保存的用户登录密码。

应用中,用户的登录密码一般不使用明文保存,可以保证即使数据库泄露也不会暴露密码内容;同时,也应该对用户设置的密码进行格式上的限制,不应使用过于简单的组合,过于简单的密码依然有可能通过碰撞测试对比检测出来,即将密码进行散列与保存的密码散列内容进行对比。对于密码的格式,可以要求至少8个字符,必须包括大、小写字母、数字和其它符号或者更加严格的格式。

下面的代码,在Program.cs文件中模拟检查输入密码正确性的功能。

C#
using System;
using cfx;

namespace csfx_demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string pwd = "123456";
            string pwdEncode = pwd.Sha384();
            string inputPwd = "123456";
            Console.WriteLine(inputPwd.Sha384() == pwdEncode);  // True
        }
    }
}

代码中,假设密码(pwd)为123456。pwdEncode为密码的加密文本,代码中使用了SHA-384算法,此内容在应用系统中一般会保存在数据库。inputPwd为输入的密码,系统中一般是密码输入文本框中输入的内容,判断输入密码正确性时,将输入内容进行散列,然后与保存的密码散列内容进行对比。本例,可以修改inputPwd变量的内容来观察执行结果。