利用Delphi 中“流”实现文件加密器
前 言
数据流是面向对象程序设计语言中面向对象思想的典
型体现。它彻底地取代了早期的利用函数实现输入输出的
功能, 同时也克服了利用函数实现输入输出功能的诸多弊
端, 简单来说, 流就是建立在面向对象基础上的一种抽象
的处理数据的工具。在流中, 可定义一些处理数据的基本
操作如读取数据, 写入数据等, 程序员是对流进行所有操
作的, 而不用关心流的另一头数据的真正流向。流不但可
以处理文件, 还可以处理动态内存、网络数据等多种数据
形式。掌握好对流的操作在程序中充分利用流的方便性,
不仅能使在编写面向过程的程序时效率大大提高, 而且在
对网络数据流的控制方面显得更加灵活, 利用对数据流的
控制还可以很容易的实现制作可执行电子贺卡、制作
OICQ、实现网络传输屏幕图像等等应用。
下面以文件加密为例说明Delphi 中流的概念及应用。
1 Delphi 中流的基本概念及函数声明
111 在Delphi 中, 所有流对象的基类为TStream 类, 其中
定义了所有流的共同属性和方法。
(1) TStream 类中定义的属性介绍如下:
①Size : 此属性以字节为单位返回流中数据大小。
②Position : 此属性控制流中存取指针的位置。
(2) TStream 中定义的虚方法有四个:
①Read : 此方法实现将数据从流中读出。函数原形为:
Function Read (var Buffer ; Count : Longint) : Longint ;
virtual ; abstract ;
参数Buffer 为数据读出时放置的缓冲区, Count 为需要
读出的数据的字节数, 该方法返回值为实际读出的字节数,
它可以小于或等于Count 中指定的值。
②Write : 此方法实现将数据写入流中。函数原形为:
Function Write ( var Buffer ; Count : Longint ) :
Longint ; virtual ; abstract ;
参数Buffer 为将要写入流中的数据的缓冲区, Count
为数据的长度字节数, 该方法返回值为实际写入流中的字
节数。
③Seek : 此方法实现流中读取指针的移动。函数原形
如下:
Function Seek ( Offset : Longint ; Origint : Word ) :
Longint ; virtual ; abstract ;
参数Origint 指出指针移动参照的基准, 其可能的取值
如下:
●soFrombeginning : Offset 为数据开始处。此时
Offset 必须大于或者等于零。
●soFromCurrent : Offset 指针的当前位置。
●soFromEnd : Offset 为移动后指针距离数据结束
的位置。此时Offset 必须小于或者等于零。
该方法返回值为移动后指针的位置。
参数Offset 表示以Origint 为基准指针移动的方向和字
节数。Offset 为正表示指针从数据头向数据尾移动, Offset
为负表示指针从数据尾向数据头方向移动。
④Setsize : 此方法实现改变数据的大小。函数原形为:
Function Setsize (NewSize : Longint) ; virtual ;
(3) TStream 类中定义的3 个静态方法:
①ReadBuffer : 此方法的作用是从流中当前位置读取数
据。函数原形为:
Procedure ReadBuffer (var Buffer ; Count : Longint) ;
参数的定义跟上面的Read 相同。注意: 当读取的数据
字节数与需要读取的字节数不相同时, 将产生EReadError
异常。
②WriteBuffer : 此方法的作用是在当前位置向流写入
数据。函数原形为:
Procedure WriteBuffer (var Buffer ; Count : Longint) ;
参数的定义跟上面的Write 相同。注意: 当写入的数
据字节数与需要写入的字节数不相同时, 将产生EWriteEr2
ror 异常。
③CopyFrom: 此方法的作用是从其它流中拷贝的数据
流。函数原形为:
Function CopyFrom ( Source : TStream; Count :
Longint) : Longint ;
参数Source 为源数据流, Count 为拷贝的数据字节数。
当Count 大于0 时, CopyFrom 从Source 参数的当前位置拷
贝Count 个字节的数据; 当Count 等于0 时, CopyFrom 设
置Source 参数的Position 属性为0 , 然后拷贝Source 的所有
数据;
112 Tstream 派生出的类中, 最常用的是TFileStream 类。
TFileStream 类一般被用来存取文件
建立一个TFileStream 类实例。声明如下:
constructor Create ( const Filename : string ; Mode :
Word) ;
其中Filename 为文件名(包括路径) , 参数Mode 为找
开文件的方式, 它包括文件的打开模式和共享模式, 其可
能的取值和意义如下:
打开模式:
●fmCreate : 用指定的文件名建立文件,
如果文件已经存在则打开它。
●fmOpenRead : 以只读方式打开指定文件
●fmOpenWrite : 以只写方式打开指定文件
●fmOpenReadWrite : 以读写方式打开指定文件
共享模式:
●fmShareCompat : 共享模式与FCBs 兼容
●fmShareExclusive : 不允许别的程序以任何方式
打开文文件
●fmShareDenyWrite : 不允许别的程序以写方式
打开该文件
●fmShareDenyRead : 不允许别的程序以读方式打
开该文件
●fmShareDenyNone : 别的程序可以以任何方式找
开该文件
TStream 还有一个派生类TMemoryStream , 实际应用
非常频繁。它叫内存流, 就是说在内存中建立一个流对象。
它的基本方法和函数跟TFileStream 类相似。
2 利用流实现exe 文件的加密解密
211 文件加密器的原理:
建立两个文件, 一个用来添加资源到另外一个EXE 文
件里面, 称为添加程序。另一个被添加的EXE 文件称为头
文件。该文件的功能是把添加到自己里面的文件读出来。
加密时, 首先建立头文件, 再将明文追加到头文件尾部并
设置一个密码, 生成密文; 解密时, 先校验密码, 如正确,
则将密文从头文件中读出, 生成明文, 否则, 报错。以实
现对文件的保密。
首先建立三个函数, 其原型如下:
●Function Jmf-AddtoFile ( SourceFile , PassWord , Target2
File : string) : Boolean ;
实现分别把文件SourceFile 和字符串PassWord 添加到
文件Target File 尾部, 如果添加成功就返回True ; 否则返
回false ;
● Function Jmf-LoadFromFile ( SourceFile , Target File :
string) : Boolean ;
实现在SourceFile 中取出文件另保存为Target File. 如
果取出成功就返回True ; 否则返回false。
●Function Jmf- PassFromFile (var Password : string ; Source2
File : string) : Boolean ;
实现在SourceFile 中取出密码, 保存在Password 中。
如果取出成功就返回True ; 否则返回False。
212 实现技术
首先建立头文件。使用Delphi , 新建一工程, 在窗口
上放上一个TMaskEdit 控件(属性name 设置为password)
和两个Button (属性name 分别为: Unbind 和Cancel ; 属性
Caption 分别为“解密”和“取消”) 。其中, 在Unbind 的
Click 事件中写入代码。
独立编译此程序, 生成head. exe , 作头文件。利用此
头文件生成一个head. res 的资源文件, 预留。
然后建立添加程序。
再建一个工程, 添加以下控件: 二个TEdit ( 属性
name 分别设置为password 和position) , 一个Opendialog ,
两个TButton (其中属性name 分别设置为: Select 和En2
crypt ; 属性Caption 分别设置为“选择文件”和“加密”) 。
在Select 的Click 事件中实现对被加密exe 文件的选择, 在
Encrpyt 的Click 事件中实现将文和密码追加至head. exe 文
件结尾, 在事件处理例程中调用了ExtractRes 函数。其作
用是把head. exe 从资源文件中取出。在源程序将head.
res资源文件跟程序一起编译, 生成可执行文件AddEn2
crypt . exe.
213 使用方法
执行程序AddEncrypt , 选择需要加密的exe 文件, 并
在password 中输入加密密码, 点击“加密”按钮。源exe
文件将被同名密文取代。解密时, 执行密文, 会弹出对话
框, 询问密码, 输入密码。如密码正确则程序正常运行,
否则, 程序将报错, 无法运行。
注意: 上面的程序只不过简单地把一个文件添加到另
一个文件的尾部。实际应用中可改成可以添加多个文件,
只要根据实际大小和个数定义好偏移地址就可以了。而文
件易做图机就是把两个或者多个程序添加到一个头文件里面。
自解压程序和安装程序的原理也是一样的, 只需在文件添
加和文件读取时, 分别调用压缩和解压缩程序。另外, 因
篇幅有限, 文中只给出了源程序的关键代码, 有兴趣的读
者可自行扩弃完善。
源程序清单如下:
Function Jmf-AddtoFile ( SourceFile , Pass Word , Target File :
string) :Boolean ;
var
Target ,Source : TFileStream;
MyFileSize ,Pass WordSize :integer ;
begin
try
Source : = TFileStream. Create ( SourceFile , fmOpenRead or
fmShareExclusive) ;
Target : = TFileStream. Create ( Target File , fmOpen Write or
fmShareExclusive) ;
try
Target . Seek(0 ,soFromEnd) ;/ / 往尾部添加资源
Target . CopyFrom(Source ,0) ;
MyFileSize: = Source. Size + Sizeof (MyFileSize) ;/ / 计算资源
大小,并写入辅程尾部
Target . WriteBuffer (MyFileSize ,sizeof (MyFileSize) ) ;
PassWordSize : = Sizeof (PassWord) + sizeof (Pass WordSize) ;
Target . Seek(0 ,soFromEnd) ;
Target . WriteBuffer (PassWord ,Sizeof (PassWord) ) ;
Target . WriteBuffer (PassWordSize ,sizeof (PassWordSize) ) ;
finally
Target . Free ;
Source. Free ;
end ;
except
Result : = False ;
Exit ;
end ;
REsult : = True ;
end ;
Function Jmf-LoadFromFile ( SourceFile , Target File : string) :
Boolean ;
var
Source : TFileStream;
Target : TMemoryStream;
MyFilesize ,Position ;integer ;
begin
try
Target :
补充:综合编程 , 安全编程 ,