Use DELPHI to implement file encryption and compression
Author: e Mengyuan (wnhoo)
Mail:[email protected]
Love and love
Click to download this detailed description file
Overview:
In this document, we will talk about the implementation of data encryption, data compression and self-decompression of a single file. Similarly, compression of multiple files or folders can be achieved with a slight modification.
Keywords: Encrypted compression, Zlib, stream, resource files
introduction:
In daily life, we must have used famous compression software such as WINZip and WINRAR, which means that we will inevitably encounter problems such as data encryption and data compression during the software development process! This article discusses this technical problem, and also thanks to all netizens for their skills. Every time I face a problem and want to solve it, the skills you have worked hard to find always make me suddenly clear and the problem will be solved. This article mainly uses DELPH’s powerful stream processing skills to achieve data encryption and compression, and is used in actual software program development. I will write down my personal experience and development experience and share it with you.
1. System functions
1) Data compression
Use two stream classes provided by DELPHI (TComPRessionStream and TDecompressionStream) to complete the compression and decompression of data.
2) Data encryption and compression
Data encryption is realized through the application of "stream" in Delphi programming, mainly using Tfilestream and Tmemorystream, two derived classes of Tstream; the data compression part adopts the implementation method of 1)
3) Double-click the compressed file to automatically associate and decompress
By changing the association of the registry extension with program files, Tregistry is mainly used; and the API function SHChangeNotify realizes the immediate presentation of the registration effect.
4) Can generate self-extracting files
The self-decompressed file realizes automatic decompression of data compression 1) and data encryption compression 2); and, through the use of resource files, the self-decompression of data is realized to achieve the executable self-decompression file and data file, and the self-decompression of data is achieved.
2. System implementation
2.1. Working principle
2.2. Description of key technologies
(I) ZLIB
1) Base class TCustomZlibStream: is the base class of the TCompressionStream and TDecompressionStream classes. It mainly has a property: OnProgress. This event will occur during the compression or decompression of the class.
Format: ProcedureOnProgress(Sender:TObject);dynamic;
2) Compression class TCompressionStream: In addition to inheriting the OnProgress property of the base class, another attribute is added: CompressionRate, which is defined as follows:
PropertyCompressionRate:SinglereadGetCompressionRate;
Through this property, the compression ratio can be obtained.
Several important methods are defined as follows:
ConstructorTCompressionStream.Create(CompressionLevel:TCompressionLevel;Dest:TStream);
Among them: TcompressionLevel (compression type), it is defined by the following:
1) clNone: No data compression is performed;
2) clFastest: performs rapid compression, sacrificing compression efficiency;
3) clDefault: perform normal compression;
4) clMax: Maximize compression and sacrifice speed;
Dest: Destination stream, used to store compressed data.
FunctionTCompressionStream.Write(constBuffer;Count:Longint):Longint;
Among them: Buffer: data that needs to be compressed;
Count: The number of bytes of data to be compressed;
The function returns the number of bytes written to the stream.
Note: The data of the compressed class TCompressionStream can only be written. If you try to read the data from within, a "Error" exception will occur. The data that needs to be compressed is written to the stream through the method Write method, and is compressed during the writing process, and is saved in the memory stream (TmemoryStream) provided by the constructor, and the OnProcess event is triggered.
3) Decompression class TDecompressionStream: In contrast to compressed class TcompressionStream, its data can only be read out. If you try to write data inside it, an "Error" exception will occur.
Its several important methods are defined as follows:
ConstructorCreate(Source:TStream);
Among them: Source is a stream that stores compressed data;
FunctionRead(varBuffer;Count:Longint):Longint;
Data readout function, Buffer: store data buffer; Count: the size of the buffer;
The function returns the number of read bytes. During the reading process, the data is decompressed and the OnProcess event is triggered.
(II)
In Delphi, the base class of all stream objects is the TStream class, which defines common properties and methods of all streams.
The properties defined in the TStream class are as follows:
1), Size: This property returns the data size in the stream in bytes.
2) Position: This property controls the position of accessing pointers in the flow.
There are four virtual methods defined in Tstream:
1) Read: This method implements reading data from the stream, and the return value is the actual number of bytes read, which can be less than or equal to the specified value.
2) Write: This method implements writing data into the stream, and the return value is the number of bytes actually written to the stream.
3) Seek: This method realizes the movement of the read pointer in the stream, and the return value is the position of the pointer after the movement.
The function prototype is: FunctionSeek(Offset:Longint;Origint:Word):Longint;virtual;abstract;
The parameter Offset is the number of offset bytes. The parameter Origin points out the actual significance of Offset. The possible values are as follows:
soFromBeginning:Offset is the pointer distance data starts. At this time, Offset must be greater than or equal to zero.
soFromCurrent:Offset is the relative position of the pointer and the current pointer after moving.
soFromEnd:Offset is the position where the pointer distance data ends after moving. At this time, Offset must be less than or equal to zero.
4) Setsize: This method realizes changing the size of the data.
In addition, several static methods are defined in the TStream class:
1) ReadBuffer: The function of this method is to read data from the current position in the stream, the same as the Read above.
Note: When the number of bytes read is different from the number of bytes to be read, an EReadError exception will be generated.
2) WriteBuffer: The function of this method is to write data to the stream at the current location, the same as the Write above.
Note: When the number of bytes written in data is different from the number of bytes to be written, an EWriteError exception will be generated.
3) CopyFrom: The function of this method is to copy data streams from other streams.
The function prototype is: FunctionCopyFrom(Source:TStream;Count:Longint):Longint;
The parameter Source is the stream that provides data, and Count is the number of data bytes copied. When Count is greater than 0, CopyFrom copies Count bytes of data from the current position of the Source parameter; when Count is equal to 0, CopyFrom sets the Position property of the Source parameter to 0, and then copies all data from Source;
Commonly derived classes of Tstream:
TFileStream (access to file streams)
TStringStream (processes string type data in memory)
TmemoryStream (for working memory area data processing)
TBlobStream (data processing of BLOB type fields)
TwinSocketStream (read and write processing of socket)
ToleStream (data processing of COM interface)
TresourceStream (processing of resource file streams)
The most commonly used one is the TFileStream class. To access files using the TFileStream class, you must first create an instance. The statement is as follows:
constructorCreate(constFilename:string;Mode:Word);
Filename is the file name (including path)
Mode is the way to open a file. It includes the file's opening mode and sharing mode. The possible values and meanings are as follows:
Open mode:
fmCreate: Create a file with the specified file name, and open it if the file already exists.
fmOpenRead: Open the specified file in read-only
fmOpenWrite: Open the specified file in a write-only manner
fmOpenReadWrite: Open the specified file in writing mode
Sharing mode:
fmShareCompat: Shared mode is compatible with FCBs
fmShareExclusive: No other programs are allowed to open the file in any way
fmShareDenyWrite: No other programs are allowed to open the file in writing
fmShareDenyRead: No other programs are allowed to open the file in read mode
fmShareDenyNone: Other programs can open the file in any way
(III) Resource File
1) Create resource files
First create a plain text file of .Rc.
Format: Resource Identifier Keyword Resource File Name
Resource identifier: a special label when calling a resource in the program;
Keywords: Identify resource file type;
Wave: The resource file is a sound file;
RCDATA: JPEG file;
AVI: AVI animation;
ICON: icon file;
BITMAP: bitmap file;
CURSOR: cursor file;
EXEFILE: EXE file
Resource file name: The full name of the file stored on disk of the resource file
For example:
myzjyexefilezjy.exe
2) Compile resource files
Under /Bin of DELPHI installation directory, use BRCC32.exe to compile the resource file.RC. Of course, you can also copy BRCC32 to the program document directory separately for use.
For example:
Brcc32wnhoo_reg.Rc
3) Resource file reference
…
Implementation
{$R*.dfm}
{$Rwnhoo_reg.Res}
…
4) Call resource files
(1) Access the bitmap in the resource file (Bitmap)
Image.Picture.Bitmap.Handle:=LoadBitmap(hInstance,'Resource Identifier');
Note: If the bitmap is not loaded successfully, the program will still be executed, but the image will no longer be displayed. You can judge whether the load is successful based on the return value of the LoadBitmap function. If the load is successful, the return value is non-0, and if the load is failed, the return value is 0.
Another method of accessing and displaying bitmap is as follows
Image.Picture.Bitmap.LoadFromResourceName(hInstance,'Resource Identifier');
(2) Access the cursor in the resource file
Screen.Cursors[] is a cursor array. Using the cursor file we can add a customized cursor to this property. Because the default cursor index value in the array is 0, it is best to set the customized cursor index value to 1 unless you want to replace the default cursor.
Screen.Cursors[1]:=LoadCursor(hInstance,'Resource Identifier');
Image.Cursor:=1;
(3) Access icons in resource files
Putting the icon in the resource file allows you to dynamically change the application icon.
application.Icon.Handle:=LoadIcon(hInstance,'Resource Identifier');
(4) Access the AVI in the resource file
Animate.ResName:='MyAvi';//Resource Identifier Number
Animate.Active:=True;
(5) Access JPEG in resource file
Add the jpeg unit to the use unit.
var
Fjpg:TJpegImage;
FStream:TResourceStream;
Begin
Fjpg:=TJpegImage.Create;
//TresourceStream usage
FStream:=TResourceStream.Create(Hinstance,'resource identifier', resource type);
FJpg.LoadFromStream(FStream);
Image.Picture.Bitmap.Assign(FJpg);
(6) Access Wave in resource file
Add MMSystem to the uses unit
PlaySound(pchar('mywav'), Hinstance, Snd_ASyncorSnd_Memoryorsnd_Resource);
(IV) INI file operation
(1) Structure of INI file:
;This is the comments section about the INI file
[node]
Keyword = value
...
The INI file allows multiple nodes, and each node allows multiple keywords. The "=" is followed by the value of the keyword (there are three types: string, integer value and boolean value. The string is stored in There are no quotes in the INI file, the true Boolean value is represented by 1, and the false Boolean value is represented by 0). Comments begin with a semicolon ";".
(2) Operation of INI file
1. Add IniFiles to the Uses section of the Interface;
2. Add a line to the Var variable definition part: inifile:Tinifile; Then, you can create, open, read, write and other operations on the variable myinifile.
3. Open the INI file: inifile:=Tinifile.create('tmp.ini');
4. Read the value of the keyword:
a:=inifile.Readstring('node','keyword', default value); //string type
b:=inifile.Readinteger('node','keyword', default value);//integer type
c:=inifile.Readbool('node','keyword', default value); //boolean type
Where [Default] is the default value returned when the keyword does not exist in the INI file.
5. Write to INI file:
inifile.writestring('node','keyword', variable or string value);
inifile.writeinteger('node','keyword', variable or integer value);
inifile.writebool('node','keyword', variable or True or False);
When the node of this INI file does not exist, the above statement will also automatically create the INI file.
6. Delete keywords:
inifile.DeleteKey('node','keyword');//Keyword Delete
inifile.EraseSection('node');//Node removal
7. Node operation:
inifile.readsection('node',TStrings variable);// All keyword names in the specified section can be read into a string list variable;
inifile.readsections(TStrings variable);//You can read all the subsection names in the INI file into a string list variable.
inifile.readsectionvalues('node',TStrings variable);// All lines (including keywords, =, values) in the specified section in the INI file can be read into a string list variable.
8. Release: inifile.distory; or inifile.free;
(V) Document Relationship
uses
registry,shlobj;
//Realize related registration
procedureTmyzip.regzzz;
var
reg:TRegistry;
Begin
reg:=TRegistry.Create;
reg.RootKey:=HKEY_CLASSES_ROOT;
reg.OpenKey('.zzz',true);
reg.WriteString('','myzip');
reg.CloseKey;
reg.OpenKey('myzip/shell/open/command',true);
//Executable program used to open .zzz files
reg.WriteString('','"'+application.ExeName+'""%1"');
reg.CloseKey;
reg.OpenKey('myzip/DefaultIcon',true);
//Please the icon of the current executable program as the icon of the .zzz file
reg.WriteString('',''+application.ExeName+',0');
reg.Free;
//Refresh now
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
end;
2.3. Implementation of encryption and compression
1. Generate INI temporary encrypted file
Temporary file format for INI for encryption:
[FILE1]//Node, multi-file encryption can be achieved using FILE1..N in software
FILENAME=Compressed file name
PASSWORD=Decompression password
FILESIZE=File size
FILEDATE=Create date
ISJM=Is it necessary to decompress?
If you implement information storage of multiple files and folders, you can store the password keyword under a total node. This article only implements encryption of a single file, so as long as the above format is enough.
2. Merge the data file with the INI file used for encryption, which can be implemented in the form of a file stream.
Encrypted file structure diagram:
Figure (1)
Figure (2)
The above two forms can be used according to actual conditions. This article adopts the structure of Figure (1).
3. For encrypted data, ZLIB technology is used to realize compressed storage and generate new compressed files.
2.4. See 2.2(V) for the implementation of file associations
2.5. Implementation of self-decompression
1. Create an executable program file specifically from decompression
2. Create resource files in 1
3. Put the resource file into the program of this compression tool in this article and compile it together.
4. Generate a self-extracting file by merging the resource file with the compressed file.
Self-extracting file structure diagram:
5. Self-decompression implementation: by decomposing the encrypted compressed data in its own file, then decompressing the decomposed encrypted compressed data again and decomposing the real data file.
2.6 System Programming
This is all the code of the core part of this software implementation, and here we will explain all the technical details of this software in detail.
//wnhoo_zzz.pas
unitwnhoo_zzz;
interface
uses
Windows, Forms, SysUtils, Classes, zlib, Registry, INIFILES, Dialogs, shlobj;
type
pass=string[20];
type
Tmyzip=class
Private
{privatedeclarationshere}
protected
{protecteddeclarationshere}
public
procedureregzzz;
procedures_file(infileName,outfileName:string;password:pass;isjm:boolean;ysbz:integer);
functionjy_file(infileName:string;password:pass=''):boolean;
procedurezjywj(varfilename:string);
constructorCreate;
destructorDestroy;override;
{publicdeclarationshere}
published
{publisheddeclarationshere}
end;
Implementation
constructorTmyzip.Create;
Begin
inheritedCreate;//Initialize the inherited part
end;
//############################################################################################################################# #####
//Original file encryption
procedurejm_File(vfile:string;varTarget:TMemoryStream;password:pass;isjm:boolean);
{
vfile: Encrypted file
target:Output target stream after encryption》》》》》
password: Password
isjm: Is it encrypted?
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------
Encrypted file SIZE = original file SIZE + [INI encrypted compressed information file] SIZE + SIZE storing the size data type of [INI encrypted compressed information file]
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------
}
var
tmpstream,instream:TFileStream;
FileSize:integer;
inifile:TINIFILE;
filename:string;
Begin
//Opening requires [encrypted compressed file]
tmpstream:=TFileStream.Create(vFile,fmOpenreadorfmShareExclusive);
try
//Write [original file stream] to the end of [temporary encrypted compressed file stream]
Target.Seek(0,soFromEnd);
Target.CopyFrom(tmpstream,0);
//Get the file path and generate [INI encrypted compressed information file]
filename:=ExtractFilePath(paramstr(0))+'tmp.in_';
inifile:=TInifile.Create(filename);
inifile.WriteString('file1','filename',ExtractFileName(vFile));
inifile.WriteString('file1','password',password);
inifile.WriteInteger('file1','filesize',Target.Size);
inifile.WriteDateTime('file1','fileDate',now());
inifile.WriteBool('file1','isjm',isjm);
inifile.Free;
//Read in [INI Encrypted Compressed Information File Stream]
instream:=TFileStream.Create(filename,fmOpenreadorfmShareExclusive);
try
//Continue to add [INI Encrypted Compressed Information File] at the end of [Temporary Encrypted Compressed File Stream]
instream.Position:=0;
Target.Seek(0,sofromend);
Target.CopyFrom(inistream,0);
//Calculate the size of the current [INI Encrypted Compressed Information File]
FileSize:=inistream.Size;
//Continue to add the SIZE information of [INI Encrypted Compressed Information File] at the end of [Temporary Encrypted File]
Target.WriteBuffer(FileSize,sizeof(FileSize));
Finally
instream.Free;
deletefile(filename);
end;
Finally
tmpstream.Free;
end;
end;
//*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** ***************
//Flow compression
procedures_stream(instream,outStream:TStream;ysbz:integer);
{
Instream: Encrypted file stream to be compressed
OutStream compression output file stream
ysbz: compression standard
}
var
ys:TCompressionStream;
Begin
//The flow pointer points to the head
inStream.Position:=0;
//Selecting compression standards
casesbzof
1:ys:=TCompressionStream.Create(clnone,OutStream);//Not compressed
2:ys:=TCompressionStream.Create(clFastest,OutStream);//Fast compression
3:ys:=TCompressionStream.Create(cldefault,OutStream);//Standard compression
4:ys:=TCompressionStream.Create(clmax,OutStream);//Maximum compression
else
ys:=TCompressionStream.Create(clFastest,OutStream);
end;
try
//Compression Stream
ys.CopyFrom(inStream,0);
Finally
ys.Free;
end;
end;
//*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** *********************
//Flow decompression
procedurejy_Stream(instream,outStream:TStream);
{
Instream: Original compressed stream file
outStream: Unzip the streaming file
}
var
jyl:TDeCompressionStream;
buf:array[1..512] ofbyte;
sjread:integer;
Begin
inStream.Position:=0;
jyl:=TDeCompressionStream.Create(inStream);
try
repeat
//Read the actual size
sjRead:=jyl.Read(buf,sizeof(buf));
ifsjread>0then
OutStream.Write(buf,sjRead);
until(sjRead=0);
Finally
jyl.Free;
end;
end;
//*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** ***************
//Realize related registration
procedureTmyzip.regzzz;
var
reg:TRegistry;
Begin
reg:=TRegistry.Create;
reg.RootKey:=HKEY_CLASSES_ROOT;
reg.OpenKey('.zzz',true);
reg.WriteString('','myzip');
reg.CloseKey;
reg.OpenKey('myzip/shell/open/command',true);
//Executable program used to open .zzz files
reg.WriteString('','"'+application.ExeName+'""%1"');
reg.CloseKey;
reg.OpenKey('myzip/DefaultIcon',true);
//Please the icon of the current executable program as the icon of the .zzz file
reg.WriteString('',''+application.ExeName+',0');
reg.Free;
//Refresh now
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
end;
//Compress files
procedureTmyzip.ys_file(infileName,outfileName:string;password:pass;isjm:boolean;ysbz:integer);
{
infileName://encrypted files need to be compressed
outfileName://compress the file generated after encryption
password://uncompress password
ysbz://compression standard
}
var
Instream:TMemoryStream;//Temporary stream after file encryption
outStream:TFileStream;//Compress output file stream
Begin
//Create [Temporary Stream after File Encryption]
Instream:=TMemoryStream.Create;
//File encryption
jm_file(infileName,instream,password,isjm);
//Create a compressed output file stream
outStream:=TFileStream.create(outFIleName,fmCreate);
try
//[Temporary stream after file encryption] Compression
ys_stream(instream,OutStream,ysbz);
Finally
OutStream.free;
enterstream.Free;
end;
end;
//Decompress the file
functionTmyzip.jy_file(infileName:string;password:pass=''):boolean;
var
inStream,instream,filestream_ok:TFileStream;
{
Instream://unzip file name
instream://INI temporary file stream
filestream_ok://unzip the OK file
}
outStream:tmemorystream;//Temporary memory stream
inifile:TINIFILE;//Temporary INI file
FileSize:integer;// SIZE of password file
resultvalue:boolean;//Return value
Begin
try
inStream:=TFileStream.create(inFIleName,fmOpenRead);
try
outStream:=tmemorystream.create;
try
jy_stream(insTream,OutStream);
//Generate temporary INI file
instream:=TFileStream.create(ExtractFilePath(paramstr(0))+'tmp.in_',fmCreate);
try
//Point to the INTEGER type variable position that stores the decoded information
OutStream.Seek(-sizeof(FileSize),sofromend);
//Read in variable information
OutStream.ReadBuffer(FileSize,sizeof(FileSize));
//Point to the decoded information location
OutStream.Seek(-(FileSize+sizeof(FileSize)),sofromend);
//Read the decoded information into the INI stream
instream.CopyFrom(OutStream,FileSize);
//Release INI file stream
instream.Free;
//Read the INI file information
inifile:=TINIFILE.Create(ExtractFilePath(paramstr(0))+'tmp.in_');
resultvalue:=inifile.ReadBool('file1','isjm',false);
ifresultvaluethen
Begin
ifinifile.ReadString('file1','password','')=trim(password)then
resultvalue:=true
else
resultvalue:=false;
end
else
resultvalue:=true;
ifresultvaluethen
Begin
filestream_ok:=TFileStream.create(ExtractFilePath(paramstr(1))+inifile.ReadString('file1','filename','wnhoo.zzz'),fmCreate);
try
OutStream.Position:=0;
filestream_ok.CopyFrom(OutStream,inifile.ReadInteger('file1','filesize',0));
Finally
filestream_ok.Free;
end;
end;
inifile.Free;
Finally
//Delete temporary INI file
deletefile(ExtractFilePath(paramstr(0))+'tmp.in_');
end;
//
Finally
OutStream.free;
end;
Finally
inStream.free;
end;
except
resultvalue:=false;
end;
result:=resultvalue;
end;
//Self-extract creation
procedureetmyzip.zjywj(varfilename:string);
var
myRes:TRsourceStream;//Temporarily store self-extracting EXE file
myfile:tfilestream;//Original file stream
xfilename:string;//temporary file name
file_ok:tmemorystream;//The memory stream of the generated file
filesize:integer;//original file size
Begin
ifFileExists(filename)then
Begin
//Create memory stream
file_ok:=tmemorystream.Create;
//Release the resource file--self-extract the EXE file
myRes:=TResourceStream.Create(Hinstance,'myzjy',Pchar('exefile'));
//Read the original file into memory
myfile:=tfilestream.Create(filename,fmOpenRead);
try
myres.Position:=0;
file_ok.CopyFrom(myres,0);
file_ok.Seek(0,sofromend);
myfile.Position:=0;
file_ok.CopyFrom(myfile,0);
file_ok.Seek(0,sofromend);
filesize:=myfile.Size;
file_ok.WriteBuffer(filesize,sizeof(filesize));
file_ok.Position:=0;
xfilename:=ChangeFileExt(filename,'.exe');
file_ok.SaveToFile(xfilename);
Finally
myfile.Free;
myres.Free;
file_ok.Free;
end;
DeleteFile(filename);
filename:=xfilename;
end;
end;
//############################################################################################################################# #####
destructorTmyzip.Destroy;
Begin
inheritedDestroy;
end;
end.
3. Conclusion
Delphi's new visual programming environment provides us with a convenient and fast Windows application development tool. For program developers, using Delphi to develop application software will undoubtedly greatly improve programming efficiency. In delphi, you can easily use streams to implement various data forms such as file processing, dynamic memory processing, network data processing, etc., and writing programs will greatly improve efficiency.
References:
1. DELPHI system help
2. Feng Zhiqiang. Application of compression flow and decompression flow in Delphi
3. Chen Jingtao. Talk about "flow" in Delphi programming