从实际问题看非对称加密的应用
近期由于工作调整的原因,很久没有写新的文章,很多朋友的留言也没有回复,十分抱歉。
本篇随笔主要依据一次应用对"非对称加密"的常用领域进行介绍,已经很了解的同学请跳过本文,以免浪费你的时间。
1.问题的提出
写这篇随笔,主要是因为公司最近要发布一个小产品,帮助用户进行一些资源预约,比如会议室什么的。这个所谓的产品是个Web网站,而这个网站客户要求发布在局域网内部。
好的,这就是产品的现状,现在老大说,这个玩意儿要收费了,几千块钱能让用户用三个月,到期后不续费就不能继续使用。
博主所在的小组收到任务去实现这个收费功能,其实要实现这个功能有很多方案,给Web程序一个注册号,使用WebService来验证这个注册号是否到期,这应该是最简单的一种实现方式,但是由于这个Web网站是发布在局域网的,所以这个解决方案被PASS掉了
2.解决方案
最终我们提出的解决方案是:发给客户一个注册文件,该注册文件中包含一个有效期,在Web程序中,我们访问该注册文件,如果注册文件中的有效期已经到期,则阻止用户继续访问。
当然,肯定有更好的解决方案,欢迎留言
针对我们提出的解决方案,我们很自然的想到几个问题
首先想到的就是该注册文件中信息的安全性,我们的程序必须能够识别该信息的可靠性,确保注册信息是我们发布的而不是用户书写的,这个任务可以由加密来完成,但是就像我们之前已经说过的,该程序是发布在用户的局域网内部的,我们必须把加密的密钥提供给Web程序,方便Web程序对注册信息进行解密然后识别,但是提供给Web程序的密钥会被用户查看到,这样他们就能自己加密一些注册信息提供给Web程序,这样肯定是不行的,到此我们就碰到的对称加密最大的缺点,为了规避这个问题,非对称加密隆重登场!!
3.非对称加密
非对称加密能够提供一对密钥,公钥和私钥,使用公钥加密的内容无法使用公钥进行解密,必须使用其对应的私钥才能解密,反之亦然,正好符合我们的要求:
我们可以自己保留私钥,把公钥提供给Web程序,这样注册文件只能由私钥生成而无法使用公钥进行生成,用户即使掌握了公钥也无法生成注册文件
简单介绍一下我们使用的非对称加密方法:RSA,该方法基于一个数学难题:大数的因子分解,该加密方法已经集成在.net的类库中,想要了解具体实现方法的请参照:《RSA加密算法说明》和《RSA加密算法实现》 (实现算法使用C++和Java写的,不过都无所谓)
在C#中我们可以使用RSACryptoServiceProvider类进行产生密钥对,明文加密和密文解密的动作,具体写法很简单,不用过多讨论,需要的朋友可以自己去MSDN,自己动手丰衣足食嘛^_^
在使用RSACryptoServiceProvider类的时候我们会发现,类库要求我们进行加密的明文必须为128个字节,多于这个数量会引发异常,所以很多朋友在网上提出解决方案,比如把明文切断,分别加密啦等等,其实我觉得这是一个误区,要解释这个误区,我们得先从非对称加密的常用领域说起
4.非对称加密的常用领域
使用非对称加密时我们一般会将私钥保留,将公钥分发给用户,当然,具体的分发动作是通过证书还是怎么样不在我们这次的讨论范围内
第一种场景:用户使用公钥进行加密,则 只能由我们自己的私钥进行解密,就可以保证我们传递的信息是加密过的只有私钥的持有人能够对密文进行解密,其他人(包括公钥的持有人)也是无法解密密文的,但是这同样带来一个问题,由于非对称加密实现算法较为复杂,加密过程比较耗时,因此,我们一般将对称加密和非对称加密结合使用,即:使用对称加密算法对明文进行加密,使用非对称加密算法对对称加密的密钥进行加密,其实说到底,就是使用非对称加密算法进行对称加密密钥的发布,这也是“一次一密”的一种实现方法。
第二种场景是我们使用私钥进行加密,公钥的持有人都可以使用公钥进行解密,这样,公钥持有人就可以确认该内容是由私钥的持有人发布出来的,同样,由于非对称加密和解密比较耗时的原因,我们可以对该实现方式进行改良,最常见的改良方式为:我们可以对明文进行散列操作,最终将明文散列为较短的一个散列码,然后我们使用私钥对该散列码进行加密,在公钥的持有人收到消息后,可以重复上面的操作,比对自己的散列码和解析出的散列码是否相同,如果相同,则可以证明该消息是由公钥的持有人发布的,这就是我们常说的电子签名,当然我们也可以将上面提到的对称密钥的发布过程也包含在电子签名的过程中,以此来保证消息的内容只有公钥的持有人能够查看
通过上面两种应用场景我们可以发现,非对称加密算法只要能够满足128个字节的加密就能满足所有的应用需求。
5.问题的解决
到此,我们的问题已经可以解决:
1.在注册文件中写入一个使用有效期,
2.使用散列算法(如MD5)对该有效期进行散列产生散列码
3.使用私钥对散列码进行签名,作为消息头
这样我们就能产生一个注册文件
解析注册文件的过程为
1.使用相同的散列算法对消息内容进行散列
2.使用公钥对消息头进行解密
3.比较解密后的消息头和消息内容的散列码是否一致
这样我们既可以保证消息内容的可靠性又保证了消息内容的完整性,问题解决!!
6.使用MD5进行加密??
经常听到有人说:“我们的用户密码使用MD5、SHA1进行加密”等等说法,其实我个人觉得,MD5和SHA1不能说是一种加密算法,更确切的说是一种散列(HASH)算法,理想状态下,不同内容使用MD5/SHA1进行散列后的得到的散列码是不一样的,由于散列算法理论上来说是一种不可逆的算法,所以很多网站使用散列算法来对其用户密码进行保护,最常见的使用方法是:将用户注册时的密码散列后保存到数据库中,在用户登录时,将用户输入的密码进行散列,和数据库中的散列码进行比较,如果二者相同,则可以正常登录。网上流行的MD5的破解器其实也就是将常见的字符组合进行暴力破解,如果用户的密码足够复杂,则使用散列算法进行密码保护既可以免去保存密钥的麻烦,又可以保证数据库和网络传输过程中密码的安全性,不失为一种比较好的解决方案