﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-道。道。道-随笔分类-encrypt/decode</title><link>http://www.cppblog.com/eday/category/3610.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 22:37:30 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 22:37:30 GMT</pubDate><ttl>60</ttl><item><title>软件加密技术和注册机制</title><link>http://www.cppblog.com/eday/archive/2007/02/11/18667.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Sun, 11 Feb 2007 13:41:00 GMT</pubDate><guid>http://www.cppblog.com/eday/archive/2007/02/11/18667.html</guid><description><![CDATA[
		<p>　　本文是一篇软件加密技术的基础性文章，简要介绍了软件加密的一些基本常识和一些加密产品，适用于国内软件开发商或者个人共享软件开发者阅读参考。</p>
		<p>　　<strong>1、加密技术概述</strong></p>
		<p>　　一个密码系统的安全性只在于密钥的保密性，而不在算法的保密性。</p>
		<p>　　对纯数据的加密的确是这样。对于你不愿意让他看到这些数据（数据的明文）的人，用可靠的加密算法，只要破解者不知道被加密数据的密码，他就不可解读这些数据。</p>
		<p>　　但是，软件的加密不同于数据的加密，它只能是“隐藏”。不管你愿意不愿意让他（合法用户，或 Cracker）看见这些数据（软件的明文），软件最终总要在机器上运行，对机器，它就必须是明文。既然机器可以“看见”这些明文，那么 Cracker，通过一些技术，也可以看到这些明文。</p>
		<p>　　于是，从理论上，任何软件加密技术都可以破解。只是破解的难度不同而已。有的要让最高明的 Cracker 忙上几个月，有的可能不费吹灰之力，就被破解了。</p>
		<p>　　所以，反盗版的任务（技术上的反盗版，而非行政上的反盗版）就是增加 Cracker 的破解难度。让他们花费在破解软件上的成本，比他破解这个软件的获利还要高。这样 Cracker 的破解变得毫无意义——谁会花比正版软件更多的钱去买盗版软件？</p>
		<p>　　<strong>2、密码学简介</strong></p>
		<p>　　<strong>2.1   概念</strong></p>
		<p>　　<strong>（1） 发送者和接收者</strong></p>
		<p>　　假设发送者想发送消息给接收者，且想安全地发送信息：她想确信偷听者不能阅读发送的消息。</p>
		<p>　　<strong>（2） 消息和加密</strong></p>
		<p>　　消息被称为明文。用某种方法伪装消息以隐藏它的内容的过程称为加密，加了密的消息称为密文，而把密文转变为明文的过程称为解密。</p>
		<p>　　明文用M（消息）或P（明文）表示，它可能是比特流（文本文件、位图、数字化的语音流或数字化的视频图像）。至于涉及到计算机，P是简单的二进制数据。明文可被传送或存储，无论在哪种情况，M指待加密的消息。</p>
		<p>　　密文用C表示，它也是二进制数据，有时和M一样大，有时稍大（通过压缩和加密的结合，C有可能比P小些。然而，单单加密通常达不到这一点）。加密函数E作用于M得到密文C，用数学表示为：</p>
		<p>　　E（M）=C.</p>
		<p>　　相反地，解密函数D作用于C产生M</p>
		<p>　　D（C）=M.</p>
		<p>　　先加密后再解密消息，原始的明文将恢复出来，下面的等式必须成立：</p>
		<p>　　D（E（M））=M</p>
		<p>　　<strong>（3） 鉴别、完整性和抗抵赖</strong></p>
		<p>　　除了提供机密性外，密码学通常有其它的作用：.</p>
		<p>　　（a） 鉴别</p>
		<p>　　消息的接收者应该能够确认消息的来源；入侵者不可能伪装成他人。</p>
		<p>　　（b） 完整性检验</p>
		<p>　　消息的接收者应该能够验证在传送过程中消息没有被修改；入侵者不可能用假消息代替合法消息。</p>
		<p>　　（c） 抗抵赖</p>
		<p>　　发送者事后不可能虚假地否认他发送的消息。</p>
		<p>　　<strong>（4） 算法和密钥</strong></p>
		<p>　　密码算法也叫密码，是用于加密和解密的数学函数。（通常情况下，有两个相关的函数：一个用作加密，另一个用作解密）</p>
		<p>　　如果算法的保密性是基于保持算法的秘密，这种算法称为受限制的算法。受限制的算法具有历史意义，但按现在的标准，它们的保密性已远远不够。大的或经常变换的用户组织不能使用它们，因为每有一个用户离开这个组织，其它的用户就必须改换另外不同的算法。如果有人无意暴露了这个秘密，所有人都必须改变他们的算法。</p>
		<p>　　更糟的是，受限制的密码算法不可能进行质量控制或标准化。每个用户组织必须有他们自己的唯一算法。这样的组织不可能采用流行的硬件或软件产品。但窃听者却可以买到这些流行产品并学习算法，于是用户不得不自己编写算法并予以实现，如果这个组织中没有好的密码学家，那么他们就无法知道他们是否拥有安全的算法。</p>
		<p>　　尽管有这些主要缺陷，受限制的算法对低密级的应用来说还是很流行的，用户或者没有认识到或者不在乎他们系统中内在的问题。</p>
		<p>　　现代密码学用密钥解决了这个问题，密钥用K表示。K可以是很多数值里的任意值。密钥K的可能值的范围叫做密钥空间。加密和解密运算都使用这个密钥（即运算都依赖于密钥，并用K作为下标表示），这样，加/解密函数现在变成：</p>
		<p>　　EK（M）=C</p>
		<p>　　DK（C）=M.</p>
		<p>　　DK（EK（M））=M.</p>
		<p>　　有些算法使用不同的加密密钥和解密密钥，也就是说加密密钥K1与相应的解密密钥K2不同，在这种情况下：</p>
		<p>　　EK1（M）=C</p>
		<p>　　DK2（C）=M</p>
		<p>　　DK2 （EK1（M））=M</p>
		<p>　　所有这些算法的安全性都基于密钥的安全性；而不是基于算法的细节的安全性。这就意味着算法可以公开，也可以被分析，可以大量生产使用算法的产品，即使偷听者知道你的算法也没有关系；如果他不知道你使用的具体密钥，他就不可能阅读你的消息。</p>
		<p>　　密码系统由算法、以及所有可能的明文、密文和密钥组成的。</p>
		<p>　　基于密钥的算法通常有两类：对称算法和公开密钥算法。下面将分别介绍：</p>
		<p>　　<strong>2.2   对称密码算法</strong></p>
		<p>　　对称算法有时又叫传统密码算法，就是加密密钥能够从解密密钥中推算出来，反过来也成立。在大多数对称算法中，加/解密密钥是相同的。这些算法也叫秘密密钥算法或单密钥算法，它要求发送者和接收者在安全通信之前，商定一个密钥。对称算法的安全性依赖于密钥，泄漏密钥就意味着任何人都能对消息进行加/解密。只要通信需要保密，密钥就必须保密。</p>
		<p>　　对称算法的加密和解密表示为：</p>
		<p>　　EK（M）=C</p>
		<p>　　DK（C）=M</p>
		<p>　　对称算法可分为两类。一次只对明文中的单个比特（有时对字节）运算的算法称为序列算法或序列密码。另一类算法是对明文的一组比特亚行运算，这些比特组称为分组，相应的算法称为分组算法或分组密码。现代计算机密码算法的典型分组长度为64比特——这个长度大到足以防止分析破译，但又小到足以方便使用（在计算机出现前，算法普遍地每次只对明文的一个字符运算，可认为是序列密码对字符序列的运算）。</p>
		<p>　　<strong>2.3   公开密码算法</strong></p>
		<p>　　公开密钥算法（也叫非对称算法）是这样设计的：用作加密的密钥不同于用作解密的密钥，而且解密密钥不能根据加密密钥计算出来（至少在合理假定的长时间内）。之所以叫做公开密钥算法，是因为加密密钥能够公开，即陌生者能用加密密钥加密信息，但只有用相应的解密密钥才能解密信息。在这些系统中，加密密钥叫做公开密钥（简称公钥），解密密钥叫做私人密钥（简称私钥）。私人密钥有时也叫秘密密钥。为了避免与对称算法混淆，此处不用秘密密钥这个名字。</p>
		<p>　　用公开密钥K加密表示为</p>
		<p>　　EK（M）=C.</p>
		<p>　　虽然公开密钥和私人密钥是不同的，但用相应的私人密钥解密可表示为：</p>
		<p>　　DK（C）=M</p>
		<p>　　有时消息用私人密钥加密而用公开密钥解密，这用于数字签名（后面将详细介绍），尽管可能产生混淆，但这些运算可分别表示为：</p>
		<p>　　EK（M）=C</p>
		<p>　　DK（C）=M</p>
		<p>　　当前的公开密码算法的速度，比起对称密码算法，要慢的多，这使得公开密码算法在大数据量的加密中应用有限。</p>
		<p>　　<strong>2.4   单向散列函数</strong></p>
		<p>　　单向散列函数 H（M） 作用于一个任意长度的消息 M，它返回一个固定长度的散列值 h，其中 h 的长度为 m .</p>
		<p>　　输入为任意长度且输出为固定长度的函数有很多种，但单向散列函数还有使其单向的其它特性：</p>
		<p>　　（1） 给定 M ，很容易计算 h ；</p>
		<p>　　（2） 给定 h ，根据 H（M） = h 计算 M 很难 ；</p>
		<p>　　（3） 给定 M ，要找到另一个消息 M‘ 并满足 H（M） = H（M’） 很难。</p>
		<p>　　在许多应用中，仅有单向性是不够的，还需要称之为“抗碰撞”的条件：</p>
		<p>　　要找出两个随机的消息 M 和 M‘，使 H（M） = H（M’） 满足很难。</p>
		<p>　　由于散列函数的这些特性，由于公开密码算法的计算速度往往很慢，所以，在一些密码协议中，它可以作为一个消息 M 的摘要，代替原始消息 M，让发送者为 H（M） 签名而不是对 M 签名 .</p>
		<p>　　如 SHA 散列算法用于数字签名协议 DSA中。</p>
		<p>　　<strong>2.5   数字签名</strong></p>
		<p>　　提到数字签名就离不开公开密码系统和散列技术。</p>
		<p>　　有几种公钥算法能用作数字签名。在一些算法中，例如RSA，公钥或者私钥都可用作加密。用你的私钥加密文件，你就拥有安全的数字签名。在其它情况下，如DSA，算法便区分开来了？？数字签名算法不能用于加密。这种思想首先由Diffie和Hellman提出 .</p>
		<p>　　基本协议是简单的 ：</p>
		<p>　　（1） A 用她的私钥对文件加密，从而对文件签名。</p>
		<p>　　（2） A 将签名的文件传给B.</p>
		<p>　　（3） B用A的公钥解密文件，从而验证签名。</p>
		<p>　　这个协议中，只需要证明A的公钥的确是她的。如果B不能完成第（3）步，那么他知道签名是无效的。</p>
		<p>　　这个协议也满足以下特征：</p>
		<p>　　（1） 签名是可信的。当B用A的公钥验证信息时，他知道是由A签名的。</p>
		<p>　　（2） 签名是不可伪造的。只有A知道她的私钥。</p>
		<p>　　（3） 签名是不可重用的。签名是文件的函数，并且不可能转换成另外的文件。</p>
		<p>　　（4） 被签名的文件是不可改变的。如果文件有任何改变，文件就不可能用A的公钥验证。</p>
		<p>　　（5） 签名是不可抵赖的。B不用A的帮助就能验证A的签名。</p>
		<p>　　在实际应用中，因为公共密码算法的速度太慢，签名者往往是对消息的散列签名而不是对消息本身签名。这样做并不会降低签名的可信性。</p>
		<p>　　<strong>3    当前流行的一些软件保护技术</strong></p>
		<p>　　3.1   序列号保护</p>
		<p>　　数学算法一项都是密码加密的核心，但在一般的软件加密中，它似乎并不太为人们关心，因为大多数时候软件加密本身实现的都是一种编程的技巧。但近几年来随着序列号加密程序的普及，数学算法在软件加密中的比重似乎是越来越大了。</p>
		<p>　　看看在网络上大行其道的序列号加密的工作原理。当用户从网络上下载某个shareware——共享软件后，一般都有使用时间上的限制，当过了共享软件的试用期后，你必须到这个软件的公司去注册后方能继续使用。注册过程一般是用户把自己的私人信息（一般主要指名字）连同信用卡号码告诉给软件公司，软件公司会根据用户的信息计算出一个序列码，在用户得到这个序列码后，按照注册需要的步骤在软件中输入注册信息和注册码，其注册信息的合法性由软件验证通过后，软件就会取消掉本身的各种限制，这种加密实现起来比较简单，不需要额外的成本，用户购买也非常方便，在互联网上的软件80%都是以这种方式来保护的。</p>
		<p>　　软件验证序列号的合法性过程，其实就是验证用户名和序列号之间的换算关系是否正确的过程。其验证最基本的有两种，一种是按用户输入的姓名来生成注册码，再同用户输入的注册码比较，公式表示如下：</p>
		<p>　　序列号 = F（用户名）</p>
		<p>　　但这种方法等于在用户软件中再现了软件公司生成注册码的过程，实际上是非常不安全的，不论其换算过程多么复杂，解密者只需把你的换算过程从程序中提取出来就可以编制一个通用的注册程序。</p>
		<p>　　另外一种是通过注册码来验证用户名的正确性，公式表示如下：</p>
		<p>　　用户名称 = F逆（序列号） （如ACDSEE）</p>
		<p>　　这其实是软件公司注册码计算过程的反算法，如果正向算法与反向算法不是对称算法的话，对于解密者来说，的确有些困难，但这种算法相当不好设计。</p>
		<p>　　于是有人考虑到以下的算法：</p>
		<p>　　F1（用户名称） = F2（序列号）</p>
		<p>　　F1、F2是两种完全不同的的算法，但用户名通过F1算法计算出的特征字等于序列号通过F2算法计算出的特征字，这种算法在设计上比较简单，保密性相对以上两种算法也要好的多。如果能够把F1、F2算法设计成不可逆算法的话，保密性相当的好；可一旦解密者找到其中之一的反算法的话，这种算法就不安全了。一元算法的设计看来再如何努力也很难有太大的突破，那么二元呢？</p>
		<p>　　特定值 = F（用户名，序列号）</p>
		<p>　　这个算法看上去相当不错，用户名称与序列号之间的关系不再那么清晰了，但同时也失去了用户名于序列号的一一对应关系，软件开发者必须自己维护用户名称与序列号之间的唯一性，但这似乎不是难以办到的事，建个数据库就可以了。当然也可以把用户名称和序列号分为几个部分来构造多元的算法。</p>
		<p>　　特定值 = F（用户名1，用户名2，...序列号1，序列号2...）</p>
		<p>　　现有的序列号加密算法大多是软件开发者自行设计的，大部分相当简单。而且有些算法作者虽然下了很大的功夫，效果却往往得不到它所希望的结果。</p>
		<p>　　3.2   时间限制</p>
		<p>　　有些程序的试用版每次运行都有时间限制，例如运行10分钟或20分钟就停止工作，必须重新运行该程序才能正常工作。这些程序里面自然有个定时器来统计程序运行的时间。</p>
		<p>　　这种方法使用的较少。</p>
		<p>　　3.3   Key File 保护</p>
		<p>　　Key File（注册文件）是一种利用文件来注册软件的保护方式。Key File一般是一个小文件，可以是纯文本文件，也可以是包含不可显示字符的二进制文件，其内容是一些加密过或未加密的数据，其中可能有用户名、注册码等信息。文件格式则由软件作者自己定义。试用版软件没有注册文件，当用户向作者付费注册之后，会收到作者寄来的注册文件，其中可能包含用户的个人信息。用户只要将该文件放入指定的目录，就可以让软件成为正式版。该文件一般是放在软件的安装目录中或系统目录下。软件每次启动时，从该文件中读取数据，然后利用某种算法进行处理，根据处理的结果判断是否为正确的注册文件，如果正确则以注册版模式来运行。</p>
		<p>　　这种保护方法使用也不多。</p>
		<p>　　3.4   CD-check</p>
		<p>　　即光盘保护技术。程序在启动时判断光驱中的光盘上是否存在特定的文件，如果不存在则认为用户没有正版光盘，拒绝运行。在程序运行的过程当中一般不再检查光盘的存在与否。Windows下的具体实现一般是这样的：先用GetLogicalDriveStrings（ ）或GetLogicalDrives（ ）得到系统中安装的所有驱动器的列表，然后再用GetDriveType（ ）检查每一个驱动器，如果是光驱则用CreateFileA（ ）或FindFirstFileA（ ）等函数检查特定的文件存在与否，并可能进一步地检查文件的属性、大小、内容等。</p>
		<p>　　3.5   软件狗</p>
		<p>　　软件狗是一种智能型加密工具。它是一个安装在并口、串口等接口上的硬件电路，同时有一套使用于各种语言的接口软件和工具软件。当被狗保护的软件运行时，程序向插在计算机上的软件狗发出查询命令，软件狗迅速计算查询并给出响应，正确的响应保证软件继续运行。如果没有软件狗，程序将不能运行，复杂的软硬件技术结合在一起防止软件盗版。真正有商业价值得软件一般都用软件狗来保护。</p>
		<p>　　平时常见的狗主要有“洋狗”（国外狗）和“土狗”（国产狗）。这里“洋狗”主要指美国的彩虹和以色列的HASP，“土狗”主要有金天地（现在与美国彩虹合资，叫“彩虹天地”）、深思、尖石。总的说来，“洋狗”在软件接口、加壳、反跟踪等“软”方面没有“土狗”好，但在硬件上破解难度非常大；而“土狗”在软的方面做的很好，但在硬件上不如“洋狗”，稍有单片机功力的人，都可以复制。</p>
		<p>　　3.6   软盘加密</p>
		<p>　　通过在软盘上格式化一些非标准磁道，在这些磁道上写入一些数据，如软件的解密密钥等等。这种软盘成为“钥匙盘”。软件运行时用户将软盘插入，软件读取这些磁道中的数据，判断是否合法的“钥匙盘”。</p>
		<p>　　软盘加密还有其它一些技术，如弱位加密等等。</p>
		<p>　　随着近年来软盘的没落，这种方法基本上退出了历史舞台。</p>
		<p>　　3.7   将软件与机器硬件信息结合</p>
		<p>　　用户得到（买到或从网上下载）软件后，安装时软件从用户的机器上取得该机器的一些硬件信息（如硬盘序列号、BOIS序列号等等），然后把这些信息和用户的序列号、用户名等进行计算，从而在一定程度上将软件和硬件部分绑定。用户需要把这一序列号用Email、电话或邮寄等方法寄给软件提供商或开发商，软件开发商利用注册机（软件）产生该软件的注册号寄给用户即可。软件加密虽然加密强度比硬件方法较弱，但它具有非常廉价的成本、方便的使用方法等优点。非常适合做为采用光盘（CDROM）等方式发授软件的加密方案。</p>
		<p>　　此种加密算法的优点</p>
		<p>　　·    不同机器注册码不同。用户获得一个密码只能在一台机器上注册使用软件。不同于目前大多软件采用的注册方法，即只要知道注册码，可在任何机器上安装注册。</p>
		<p>　　·    不需要任何硬件或软盘</p>
		<p>　　·    可以选择控制软件运行在什么机器、运行多长时间或次数等</p>
		<p>　　·    可让软件在不注册前的功能为演示软件，只能运行一段时间或部分功能。注册后就立即变为正式软件</p>
		<p>　　·    采用特别技术，解密者很难找到产生注册号码的规律</p>
		<p>　　·    在使用注册号产生软件（注册机）时可采用使用密码、密钥盘、总次数限制等方法</p>
		<p>　　·    方便易用，价格低廉。</p>
		<p>　　这种加密还有以下特点</p>
		<p>　　1、 注册加密的软件，只能在一台机器上安装使用。把软件拷贝到其它机器上不能运行。</p>
		<p>　　2、 若用户想在另一机器上安装运行，必须把软件在这一机器上运行时的序列号，寄给软件出版商换取注册密码。当然应再交一份软件费用。</p>
		<p>　　3、 此加密方法特别适应在因特网上发布的软件及用光盘发布的软件。</p>
		<p>　　注释：</p>
		<p>　　1、“加密技术概述”部分内容参考了大学教材“密码学基础”。</p>
		<p>　　2、“当前流行的一些软件保护技术”部分内容参考了“加密与解密--软件保护技术及完全解决方案”一文。</p>
<img src ="http://www.cppblog.com/eday/aggbug/18667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-02-11 21:41 <a href="http://www.cppblog.com/eday/archive/2007/02/11/18667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>