你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 网络与通信
Delphi单机数据库系统的安全性研究与应用
 

摘 要:本文深入讨论了Delphi环境下流的工作原理,通过重载ToleStream流的读(Read)、写(Write)函数,并结合OLE复合文档实现数据加密,有效地增强单 机数据库系统的安全性。

关键词:流; 函数重载; OLE复合文档 ;数据加密

 

一、引言

目前,很多C/S(Client/Server)分布式应用系统为了改善系统的工作效率和提高系统的伸缩性,都把SQL服务器上的一些基本数据分发到各个客户机上。这一过程有两种选择:一是在客户机上安装SQL Server桌面版,二是把SQL服务器上的数据转换为Paradox 数据表或Access数据库等形式。从系统“瘦身”角度看,更多程序员选择后者,但此时,SQL服务器的安全保密功能对客户机上的数据库便完全失效,须由程序员重新进行数据安全加密。传统的方法是往转换后的数据表添加口令,然后在应用系统中使用TSession对象自动打开带有口令的数据表。事实上,这一方法有着严重的不足:因为Paradox 7数据表存在着万能口令“jIGGAe”或“cupcdvum”(用户在Database Desktop中,用万能口令就能打开所有添加口令的数据表);而深受程序员喜爱的Access数据库的口令破解程序也在互联网上广为传播。为了更有效地增强单机数据库系统的安全性,本文深入讨论了Delphi环境下流的工作原理,并在ToleStream类的基础上派生一个子类,通过重载其读(Read)、写(Write)函数,并结合OLE复合文档,实现数据加密。

二、原理机制     

2.1  Delphi流的工作原理

Delphi,“流”是指数据从一个对象到另一个对象的流动。简单来说,就是建立在面向对象基础上的一种抽象的处理数据的工具。当应用程序与外界环境进行信息交换时,存在着两个对象:一个是应用程序的对象,另一个是文件对象,目前,Windows操作系统已把键盘、屏幕、打印机和通信端口等扩充为文件进行处理。若在程序中建立一个流对象,并指定这个流对象与某个文件对象建立连接,那么在程序中操作了流对象后,文件系统将对相应的文件对象产生作用。

Dephi提供了一个抽象的数据类型TStream来支持对流式数据的操作,流式数据通常是来自文件、数据库、内存对象、OLE对象等,几种常用流的继承关系如图1所示。TStream中定义了所有流的共同属性和方法,现把一些主要的属性和方法做如下介绍:

1Size:此属性以字节返回流中数据大小;

2Position:此属性控制流中存取指针的位置;

3Read:此方法实现将数据从流中读出。函数原形为:

Function Read(var Buffer;Count:Longint):Longint;virtual;abstract;参数Buffer为数据读出时放置的缓冲区,Count为需要读出的数据的字节数,该方法返回值为实际读出的字节数,它可以小于或等于Count中指定的值。

4Write:此方法实现将数据写入流中。函数原形为:

Function Write(var Buffer;Count:Longint):Longint;virtual;abstract;参数Buffer为将要写入流中的数据的缓冲区,Count为数据的长度字节数,该方法返回值为实际写入流中的字节数。

TObject
                       |       
     
                TStream
      
|               |              |
  
TcustomMemoryStream   ToleStream   THandleStream
      
|                             |
    
TMemoryStream                  TFileStream
             
1Delphi的几种常用流的继承关系。

 

 

22  数据库的流操作

Delphi提供了TclientDataSet控件来支持数据库的流操作,该控件继承自TDataSet,其数据存储文件格式扩展名为.cds.xml,是基于文件型数据存储和操作的控件。TclientDataSett控件封装了对数据进行操作处理的接口和功能,其本身并不依赖BDEODBCADO等数据库驱动程序,所以是开发单机“瘦”数据库应用程序的理想控件。

TclientDataSet控件的SaveToStream()LoadFromStream()函数可完成数据库与流的读写转换操作。具体的函数原形和参数说明如下:

1)函数原形:procedure SaveToStream(Stream: TStream; Format: TDataPacketFormat = dfBinary);功能是把TclientDataSet控件所连接的数据写到Stream中。参数Stream是一个抽象流,其具体对象可以是TmemoryStreamToleStreamTfileStream等,可见,TclientDataSet控件就是通过SaveToStream函数把数据表的内容输出到内存流、OLE接口流或文件流等,从而完成与其它对象交换信息;参数Format是指流的格式,有三种格式:dfBinary(二进制), dfXML(可扩展标记语言), dfXMLUTF8UTF8可扩展标记语言)。

    2)函数原形: LoadFromStream(Stream: TStream); 功能是把Stream流的内容读入到TclientDataSet控件中,特别指出:这里的Stream应是一个数据表格式的流,否则数据加载失败。

23  数据加密方案

TclientDataSet控件通过SaveToStream函数把数据表的信息写入到某一个流中,实质是调用该流的write函数来完成写入功能的。根据这一特点,我们设计如下的数据加密方案:在ToleStream类的基础上派生一个子类TPasswordstream,然后重载该子类的ReadWrite函数,使数据表的每个字节在写入或读出TPasswordstream流时,分别与同一字符串的某位相应字符进行相加或相减,最终选用OLE复合文档来保存加密后的流数据,OLE复合文档的原理与编程可参见文献[4]。由于数据表的信息在写入流之前已作了一定规律的变换,所以保存在OLE复合文档中流数据已失去数据表格式,读出该流数据时应有相应的解密过程,否则加载失败。

三、代码实现

31新建单元Unit2,从ToleStream基类派生TPasswordstream类,并编写加密、解密过程。

unit Unit2;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, AxCtrls;

type

  TPasswordstream=class(TOlestream) //Tolestream为基类,

//派生Tpasswordstream

 private

 fkeyStr:string;  //加密字符串

 public

 function read(var buffer;count:longint): longint;override; //重载read函数

 function write(const buffer;count:longint): longint;override; //重载write

//函数

 property keyStr:string read fkeyStr write fkeyStr ;

 end;

implementation

function TPasswordstream.write(const buffer; count:longint):longint;

 var

 Pbu,Pmy,mykey:pchar;

 i,enc:integer;

begin

 getmem(pmy,count); //pmy分配内存

 mykey:=pchar(keyStr); //keyStr 转换为pchar指针

 try

 pbu:=pchar(@buffer); //buffer转换为pchar指针

 for i:=0 to count-1 do

 //buffer的每个字符与keyStr字符串相应的一位字符相加,结果放入pmy指向的//内存区

 begin

 enc:=(ord(pbu[i])+ord(mykey

 [(i mod length(keyStr))])) mod 256;

 Pmy[i]:=char(enc);

 end;

 result:=inherited write(Pmy^,count);

 //pmy指向的内存内容写入文件

 finally

 freemem(Pmy,count); //释放pmy内存

 end;

end;

function TPasswordstream.read(var buffer;count:longint):

 longint;

var

 Pbu,Pmy,mykey:pchar;

 i,mycount,enc:integer;

begin

 getmem(Pmy,count);// pmy分配内存

 mykey:=pchar(keyStr); //keyStr 转换为pchar指针

 try

 mycount:=inherited read(Pmy^,count);

 //将文件内容读入pmy指向的内存区域

 Pbu:=Pchar(@buffer); //buffer转换为pchar指针

 for i:=0 to mycount-1 do

//buffer的每个字符与keyStr字符串相应的一位字符相减,结果放入pmy指向的内//存区

 begin

 enc:=(ord(Pmy[i])-ord(mykey

 [(i mod length(keyStr))])) mod 256;

 Pbu[i]:=chr(enc);

 end;

 finally

 freemem(Pmy,count); //释放pmy内存

 end;

 result:=mycount;

end;

end.

32在单元Unit1中,使用Tpasswordstream对象,并结合OLE复合文档,完成数据加密、解密过程。

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, Buttons, DB, DBClient, Grids, DBGrids,ActiveX,AxCtrls,

  DBTables;

type

  TForm1 = class(TForm)

    BitBtn1: TBitBtn;

    BitBtn2: TBitBtn;

    DataSource1: TDataSource;

    DBGrid1: TDBGrid;

    ClientDataSet1: TClientDataSet;

    ClientDataSet2: TClientDataSet;

    DBGrid2: TDBGrid;

    DataSource2: TDataSource;

    Table1: TTable;

    procedure BitBtn1Click(Sender: TObject);

    procedure BitBtn2Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

var

  Form1: TForm1;

implementation

uses unit2; //引用unit2单元

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);

var

Hre:HResult;

RootStorage,SubStorage:IStorage ;

Istr1:IStream;

OleStream1:TPasswordstream;

begin

Hre:=StgCreateDocfile('MyOleDoc.ole',STGM_CREATE or STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,0,RootStorage); //建立一个名为 

 // MyOleDoc.ole复合文档

if not SUCCEEDED(Hre) then   Application.Terminate;

Hre:=RootStorage.CreateStorage('Database',STGM_CREATE or STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,0,0,SubStorage); //建立一个名为  

// Database的存储

if  not SUCCEEDED(Hre) then  Application.Terminate;

Hre:=SubStorage.CreateStream('employee',STGM_CREATE or STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,0,0,Istr1);  //建立一个名为employee

//的流

if  not SUCCEEDED(Hre) then Application.Terminate;

ClientDataSet1.Active:=True;

OleStream1:=TPasswordstream.Create(Istr1);//建立Tpasswordstream对象

OleStream1.keystr:='FoShan';//设置加密字符串为"FoShan

ClientDataSet1.SaveToStream(OleStream1); //调用Tpasswordstream对象的write

//函数把加密后的employee数据表写入到MyOleDoc.ole 复合文档的 Database 存储//下,并以 名为//employee的流进行保存

OleStream1.Free;

end;

procedure TForm1.BitBtn2Click(Sender: TObject);

var

Hre:HResult;

RootStorage,SubStorage:IStorage ;

Istr1:IStream;

OleStream1:TPasswordstream;

begin

ClientDataSet2.Active:=False;

Hre:=StgOpenStorage('MyOleDoc.ole',nil, STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,nil,0,RootStorage); //打开一个名为MyOleDoc.ole复合文档

if  not SUCCEEDED(Hre) then  Application.Terminate;

Hre:=RootStorage.OpenStorage('Database',nil,STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,nil,0,SubStorage); //打开一个名为Database的存储

 if not SUCCEEDED(Hre) then Application.Terminate;;   

Hre:=SubStorage.OpenStream('employee',nil,STGM_READWRITE or STGM_DIRECT or STGM_SHARE_EXCLUSIVE,0,Istr1); //打开一个名为employee的流

OleStream1:=TOleStream.Create(Istr1);

if not SUCCEEDED(Hre) then Application.Terminate;

OleStream1:=TPasswordstream.Create(Istr1); //建立Tpasswordstream对象

OleStream1.keystr:='FoShan'; //设置解密字符串为"FoShan

ClientDataSet2.LoadFromStream(OleStream1); //调用Tpasswordstream对象的read

//函数解密

OleStream1.Free;

ClientDataSet2.Active:=True;

end;

end.

四、结束语

本文深入讨论了Delphi环境下数据表以加密流的方式保存到OLE复合文档的全过程,和传统的口令加密方法对比,该方法让用户真正拥有自主的数据安全机制。若要破解该加密方法,不仅要遍历OLE复合文档中的存储和流的名称,而且还要破解加密后的流数据,可见,数据破解的难度是极高的,

参考文献

1.[]Macro Cantu著 《Delphi高级开发指南》电子工业出版社  19981

2.[]Eric Harmon著 《Delphi COM深入编程》机械工业出版社  200010

3.郑莉  主编        C++语言程序设计》   清华大学出版社  20017

4.黄雄波 丘陵《基于Delphi下的OLE结构化存储原理与应用》电脑编程技巧与维护 2003.?(代发表)

5. []Charlie Calvert著 《Delphi 4编程技术内幕》机械工业出版社 19996

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089