哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用

  0、摘要

      今天看到吉日嘎拉一篇关于管理软件中信息加密和安全的文章,感觉非常有实际意义。文中作者从实践经验出发,讨论了信息管理软件中如何通过哈希和加密进行数据保护。但是从文章评论中也可以看出很多朋友对这个方面一些基本概念比较模糊,这样就容易“照葫芦画瓢”,不能根据自身具体情况灵活选择和使用各种哈希和加密方式。本文不对哈希和加密做过于深入的讨论,而是对哈希和加密的基本概念和原理进行阐述、比较,并结合具体实践说明如何选择哈希和加密算法、如何提高安全性等问题,使朋友们做到“知其然,知其所以然”,这样就能通过分析具体情况,灵活运用哈希和加密保护数据。

  1、哈希(Hash)与加密(Encrypt)的区别

      在本文开始,我需要首先从直观层面阐述哈希(Hash)加密(Encrypt)的区别,因为我见过很多朋友对这两个概念不是很清晰,容易混淆两者。而正确区别两者是正确选择和使用哈希与加密的基础。

      概括来说,哈希(Hash)是将目标文本转换成具有相同长度的、不可逆的杂凑字符串(或叫做消息摘要),而加密(Encrypt)是将目标文本转换成具有不同长度的、可逆的密文。

      具体来说,两者有如下重要区别:

      1、哈希算法往往被设计成生成具有相同长度的文本,而加密算法生成的文本长度与明文本身的长度有关。

      例如,设我们有两段文本:“Microsoft”和“Google”。两者使用某种哈希算法得到的结果分别为:“140864078AECA1C7C35B4BEB33C53C34”和“8B36E9207C24C76E6719268E49201D94”,而使用某种加密算法的到的结果分别为“Njdsptpgu”和“Hpphmf”。可以看到,哈希的结果具有相同的长度,而加密的结果则长度不同。实际上,如果使用相同的哈希算法,不论你的输入有多么长,得到的结果长度是一个常数,而加密算法往往与明文的长度成正比。

      2、哈希算法是不可逆的,而加密算法是可逆的。

      这里的不可逆有两层含义,一是“给定一个哈希结果R,没有方法将E转换成原目标文本S”,二是“给定哈希结果R,即使知道一段文本S的哈希结果为R,也不能断言当初的目标文本就是S”。其实稍微想想就知道,哈希是不可能可逆的,因为如果可逆,那么哈希就是世界上最强悍的压缩方式了——能将任意大小的文件压缩成固定大小。

      加密则不同,给定加密后的密文R,存在一种方法可以将R确定的转换为加密前的明文S。

      这里先从直观层面简单介绍两者的区别,等下文从数学角度对两者做严谨描述后,读者朋友就知道为什么会有这两个区别了。

  2、哈希(Hash)与加密(Encrypt)的数学基础

      从数学角度讲,哈希和加密都是一个映射。下面正式定义两者:

      一个哈希算法

      有了以上定义,就很清楚为什么会存在上文提到的两个区别了。由于哈希算法的定义域是一个无限集合,而值域是一个有限集合,将无限集合映射到有限集合,根据“鸽笼原理(Pigeonhole principle)”,每个哈希结果都存在无数个可能的目标文本,因此哈希不是一一映射,是不可逆的。

      而加密算法是一一映射,因此理论上来说是可逆的。

      但是,符合上面两个定义的映射仅仅可以被叫做哈希算法和加密算法,但未必是好的哈希和加密,好的哈希和加密往往需要一些附加条件,下面介绍这些内容。

      一个设计良好的哈希算法应该很难从哈希结果找到哈希目标文本的碰撞(Collision)。那么什么是碰撞呢?对于一个哈希算法H,如果

      对上图我想已无需多言,很多朋友应该使用过类似的哈希方法进行数据保护。当前最常用的哈希算法是MD5SHA1,下面给出在.NET平台上用C#语言实现MD5和SHA1哈希的代码,由于.NET对于这两个哈希算法已经进行很很好的封装,因此我们不必自己实现其算法细节,直接调用相应的库函数即可(实际上MD5和SHA1算法都十分复杂,有兴趣的可以参考维基百科)。

using System;using System.Web.Security;namespace HashAndEncrypt{    /// <summary>    /// 哈希(Hash)工具类    /// </summary>    public sealed class HashHelper    {        /// <summary>        /// 使用MD5算法进行哈希        /// </summary>        /// <param name="source">源字串</param>        /// <returns>杂凑字串</returns>        public static string MD5Hash(string source)        {            return FormsAuthentication.HashPasswordForStoringInConfigFile(source, "MD5");        }        /// <summary>        /// 使用SHA1算法进行哈希        /// </summary>        /// <param name="source">源字串</param>        /// <returns>杂凑字串</returns>        public static string SHA1Hash(string source)        {            return FormsAuthentication.HashPasswordForStoringInConfigFile(source, "SHA1");        }    }}


 

  3.3、对简单哈希(Hash)的攻击

      下面我们讨论上述的数据保护方法是否安全。

      对于哈希的攻击,主要有寻找碰撞法穷举法

      先来说说寻找碰撞法。从哈希本身的定义和上面的数据保护原理图可以看出,如果想非法登录系统,不一定非要得到注册时的输入口令,只要能得到一个注册口令的碰撞即可。因此,如果能从杂凑串中分析出一个口令的碰撞,则大功告成。

      不过我的意见是,对这种攻击大可不必担心,因为目前对于MD5和SHA1并不存在有效地寻找碰撞方法。虽然我国杰出的数学家王小云教授曾经在国际密码学会议上发布了对于MD5和SHA1的碰撞寻找改进算法,但这种方法和很多人口中所说的“破解”相去甚远,其理论目前仅具有数学上的意义,她将破解MD5的预期步骤数从2^80降到了2^69,虽然从数学上降低了好几个数量级,但2^69对于实际应用来说仍然是一个天文数字,就好比以前需要一亿年,现在需要一万年一样。

      不过这并不意味着使用MD5或SHA1后就万事大吉了,因为还有一种对于哈希的攻击方法——穷举法。通俗来说,就是在一个范围内,如从000000到999999,将其中所有值一个一个用相同的哈希算法哈希,然后将结果和杂凑串比较,如果相同,则这个值就一定是源字串或源字串的一个碰撞,于是就可以用这个值非法登录了。

      例如,下文是对MD5的穷举攻击的代码(设攻击范围为000000到999999):

using System;using System.Web.Security;namespace HashAndEncrypt{    /// <summary>    /// MD5攻击工具类    /// </summary>    public sealed class MD5AttackHelper    {        /// <summary>        /// 对MD5进行穷举攻击        /// </summary>        /// <param name="hashString">杂凑串</param>        /// <returns>杂凑串的源串或源串碰撞(攻击失败则返回null)</returns>        public static string AttackMD5(string hashString)        {            for (int i = 0; i <= 999999; i++)            {                string testString = i.ToString();                while (testString.Length < 6)                    testString = "0" + testString;                if (FormsAuthentication.HashPasswordForStoringInConfigFile(testString, "MD5") == hashString)                    return testString;            }            return null;        }    }}

it知识库哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。