forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ и уроки (http://forum.boolean.name/forumdisplay.php?f=110)
-   -   создание системы шифрования файлов с распаковкой в память (http://forum.boolean.name/showthread.php?t=3758)

jimon 27.06.2007 16:07

создание системы шифрования файлов с распаковкой в память
 
немного теории

в общем большинство любительских систем делает распаковку в tmp файлы
потому что программа которая использует такую систему
не может грузить ресурсы из памяти

к примеру блиц3д, для того чтобы заставить
его грузить картинки из памяти, Maxus'у пришлось
извратится и переопределять функции чтения файла

такой метод не очень удобен при кроссплатформеных приложениях
но ето уже выходит за рамки етой статьи :)

и так немного теории :
в блицмаксе ето можно было сделать несколькими путями

1)переопределить фукнции чтения из файла
но ето слишком сложно для нас, и много кропотливой работы

2)написать свой модуль-загрузчик (типа pngloader.mod)
не универсально, можно шифровать только файлы которые
грузит загрузчик

3)использовать возможность загрузки ресурсов из потоков
вот ето мы и будем использовать

блицмакс позволяет в функцию чтения файла вместо
имени файла подовать поток ... и вообще там подоется url:Object
а Objectом может быть что угодно, хоть имя файла, хоть веб-сайт
и соответственно наш поток тоже можно туда подать

в общем алгоритм такой :
1) мы пишем функции кодировки\декодировки TStream
2) мы пишем простенькую функцию - враппер :)
3) потом делаем простенький пример как ето использовать

больше практики
я не буду описывать сами алгоритмы шифрования,
потому что их много и ето совершенно другая тема :)

остановимся на банальном
шифровка байта ето byte_code = byte + 10
разшифровка ето byte = byte_code - 10

метод "шифрования" банален, но потом вы можете сделать и свои методы

Шифрование Потока
так начнем с функции шифрования потока

напишем костяк функции :
Код:

Function CodeStream:TStream(in:TStream)

End Function

теперь создадим поток в который можно спокойно записывать
и так же спокойно читать из него

но как же его создать если поток всегда к чему то прикреплен
в блицмаксе есть такая полезная штука как TBank
ето можно сказать масив с неопределенным размером :)
и работает он по принципу стека .. но ето нам не важно
нам важно что :
1) принимает любой размер
2) к нему можно приципить поток

создадим наш поток вывода :)

Код:

Local bank:TBank = New TBank
Local out_stream:TStream = OpenStream(bank)

думаю все банально ясно .. :)

так идем дальше, для начала запишем какуето фразу
пусть ета фраза будет заголовком для нашого Pak Файла

Код:

out_stream.WriteString("Start_Pak")
потом при чтении мы будем сверятся с ней, и выдавать ошибку если заголовок не правилен

дальше запишем размер данных для шифрования
ето удобно и позволяет вычислить программерские ошибки если что

Код:

out_stream.WriteInt(in.Size())
теперь перейдем к самому интересному - будем шифровать входящий поток :)
Код:

While Not Eof(in)
out_stream.WriteByte( in.ReadByte() + 10 )
Wend

все банально просто и тормозно :)

теперь запишем конец файла (чтобы потом при чтении сверятся)
Код:

out_stream.WriteString("End_Pak")
"сбросим" на ноль потоки
Код:

out_stream.Seek(0)
in.Seek(0)

(ето вообще важно, их же потом тоже будут использовать ! )

и вернем поток из функции
Код:

Return out_stream
вот и все, наша функция шифрования потока закончена ! :)

Декодирование потока
если вы прочитали прошлый раздел, то все для вас довольно просто
теперь минимум обьяснений и больше кода

костяк функции : :)
Код:

Function DecodeStream:TStream(in:TStream)

Local bank:TBank = New TBank
Local out_stream:TStream = OpenStream(bank)

'.... сдесь будет наш последуйший код :)

out_stream.Seek(0)
in.Seek(0)

Return out_stream
End Function

теперь проверяем начальный заголовок и читаем сколько данных записано
Код:

Local Header$ = in.ReadString(9)
If Header <> "Start_Pak" Then RuntimeError "pak corrupt"

Local DataSize% = in.ReadInt()

если вам обломно щитать сколько букв в вашем заголовке
то пользуйтесь функциями ReadLine \ WriteLine для записи и чтения заголовка

теперь дешифруем сами данные файла
Код:

For Local dat% = 1 To DataSize
out_stream.WriteByte ( in.ReadByte() - 10 )
Next

используем 1 to DataSize потому что в блицмаксе for доходит до последнего значения ... :)

далее сверяем фразу в конце файла чтобы проверить что мы не ошибились
Код:

Local EndHeader$ = in.ReadString(7)
If EndHeader <> "End_Pak" Then RuntimeError "pak data corrupt"

вот и все
подведем итог : вот наши фукнции шифрования и дешифрования потока

Код:

Function CodeStream:TStream(in:TStream)

Local bank:TBank = New TBank
Local out_stream:TStream = OpenStream(bank)

out_stream.WriteString("Start_Pak")

out_stream.WriteInt(in.Size())

While Not Eof(in)
out_stream.WriteByte( in.ReadByte() + 10 )
Wend

out_stream.WriteString("End_Pak")

out_stream.Seek(0)
in.Seek(0)

Return out_stream
End Function

Function DecodeStream:TStream(in:TStream)

Local bank:TBank = New TBank
Local out_stream:TStream = OpenStream(bank)

Local Header$ = in.ReadString(9)
If Header <> "Start_Pak" Then RuntimeError "pak corrupt"

Local DataSize% = in.ReadInt()

For Local dat% = 1 To DataSize
out_stream.WriteByte ( in.ReadByte() - 10 )
Next

Local EndHeader$ = in.ReadString(7)
If EndHeader <> "End_Pak" Then RuntimeError "pak data corrupt"

out_stream.Seek(0)
in.Seek(0)

Return out_stream
End Function


Функции Работы с потоками

все довольно просто, и особой необходимости в таких функций нету
они нужны чтобы было меньше писанины :)

чтобы было понятнее, не сводил в одну строчку как обычно, а расписал по больше :)
Код:

Function ReadPakFile:TStream(filename$)
Local file:TStream = ReadFile(filename)

Local out:TStream = DecodeStream(file)

CloseFile(file)

Return out
End Function

и функция шифрования пак файла (полезная вещь однако :) )
Код:

Function WritePakFile(filename_in$,filename_out$)
Local file:TStream = ReadFile(filename_in)

Local file_out:TStream = WriteFile(filename_out)

Local out:TStream = CodeStream(file)

While Not Eof(out)
file_out.WriteByte(out.ReadByte())
Wend
               
CloseFile file_out
out.Close()
               
End Function

все довольно просто, и сделано так чтобы вам было понятно :)

пример использования

очень банально :)
Код:

WritePakFile("test.png","test.pak")

img:TImage = LoadImage(ReadPakFile("test.pak"))

вот и все :-)

алгоритм шифрования можно усложнить до безконечности
но целью статьи было просто показать как ето использовать в бмаксе :)
так что юзайте :)

ps. с вами был jimon :-)


Часовой пояс GMT +4, время: 20:39.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot