Прежде, чем начнется техническая часть статьи, предлагаю Вам немного развлечься и поиграть в старую игру “Найди N-цать отличий”. Вот две картинки.
Первая
Вторая
Задание: найдите 10 различий в этих картинках :) ' '
Собственно, даже если бы я дал Вам сравнить 2 картинки по-проще, то все-равно невооруженным глазом определить различия было бы практически невозможно. А различаются картинки тем, что в первой записан текст, который гласит: “Привет от webdelphi.ru”. Причем записан этот текст кусками по всей картинке.
Спрашивается: а нафига мне это надо?
Я не дизайнер и не художник, так что картинки мне защищать авторским правом явно не светит. Просто решил немного разобраться для себя с вопросами по работе с нетипизированными файлами. Вот и получилась небольшая программка, которая пишет в jpg-файл произвольные данные таким образом, чтобы минимально видоизменять первоначальное изображение. Где эту программу сможете использовать Вы я не имею понятия, но буду очень признателен, если Вы поделитесь со мной способами её применения.
А теперь, собственно, разберемся как эта программа действует. Во-первых JPEG как и любой другой формат файлов не является беспорядочным набором байт, а имеет чёткую спецификацию. В соответствие с которой, файл имеет свой заголовок и, в зависимости от файла один или несколько JPG-потоков, причем в файле может присутствовать: 1 поток (сама картинка) 2 потока (картинка и миниатюра), в случае 3-х потоков уже следует задуматься над тем, чтобы “почистить” картинку, т.к. обычно третьим потоком идет бесполезная инфа, записаная фотошопом и пр.
Так вот, если не нарушать заголовка, то в картинку в принципе, можно записать сколь угодно дополнительных данных. Например, моя программа действует следующим образом:
- Открывается файл с картинкой и из него копируется заголовок в новый файл
- Следом за заголовком вписывается ключ для расшифровки вписываемого текста
- Далее, в зависимости от потребностей, в файл с определенными промежутками вписываются части текста.
- Новый файл сохраняется с новым именем.
Теперь более детально, а точнее на языке Delphi. Во-первых, ключ представлен следующим образом:
type TCryptoKey = record Step : byte; //шаг записи строки length : word; //длина части строки для записи TextLength: integer; //общая длина строки TextParts: byte; //количество частей текста end;
Зная ключ, можно без проблем восстановить все части текста и склеить их в первоначальный вид.
Сама процедура записи текста в картинку реализована следующим образом:
procedure PictCrypt(SourceFile, TargetFile: TFileName; CryptoKey:TCryptoKey; Text:String); var FS, FT: File; i,j,part:integer; buf2: byte; doWT: boolean; //флаг разрешения записи текста ch:string[1]; begin //получаем частитекста для шифровки TextParts:=GetTextParts(Text, CryptoKey); doWT:=false; AssignFile(FS,SourceFile); AssignFile(FT, TargetFile); Reset(FS,1); Rewrite(FT,1); for I := 0 to FileSize(FS)-1 do begin if i=jpg_header+1 then begin //записываем в файл ключик BlockWrite(FT, CryptoKey,Sizeof(CryptoKey)); doWT:=true; part:=0; //элемент массива строк с которого начать писать end; if (doWT)and ((FilePos(FT) mod CryptoKey.Step)=0)and(part<=Length(TextParts)-1) then begin for j:=1 to Length(TextParts[part]) do begin ch:=(copy(TextParts[part],1,1)); delete(TextParts[part],1,1); BlockWrite(FT, ch ,sizeof(Ch)); end; part:=part+1; end; BlockRead(FS, buf2, Sizeof(buf2)); BlockWrite(FT, buf2,Sizeof(buf2)); end; CloseFile(FT); CloseFile(FS); end;
После того, как текст записан в картинку, его можно прочитать обратной функцией:
function PictDeCrypt(SourceFile: TFileName):string; var i,j,k:integer; buf: TCryptoKey; FS: File; pt: string[1]; begin AssignFile(FS,SourceFile); reset(FS,1); for I := 0 to FileSize(FS)-1 do begin Seek(FS,jpg_header+1); //смещаемся на позицию начала ключа BlockRead(FS, buf,Sizeof(buf)); CryptoKey:=buf; //восстанавливаем длины подстрок, записаных в файле LengthTextParts:=GetLengths(CryptoKey); end; for I:=FilePos(FS) to FileSize(FS)-1 do begin Seek(FS, i); if ((i mod CryptoKey.Step)=0) then begin if i>=jpg_header+sizeof(buf)+1 then begin for k:=0 to Length(LengthTextParts)-1 do begin for j:=1 to LengthTextParts[k] do begin BlockRead(FS, pt ,Sizeof(pt)); Result:=Result+pt; end; Seek(FS,FilePos(FS)+CryptoKey.Step-sizeof(pt)); end; break; end; end; end; CloseFile(FS); end;
При этом, вначале расшифровки по известному ключу восстанавливаются длины кусков текста, записаных в картинке. Восcтановление длин оcуществляется в функции:
function GetLengths(CryptoKey: TCryptoKey):TLengthTextParts;
var i:integer;
begin
//восстанавливаем длины частей текста записаных в картинку
SetLength(Result, CryptoKey.TextParts);
for I:=1 to CryptoKey.TextParts-1 do
Result[i-1]:=CryptoKey.length;
{в последнюю часть дописываем остаток}
Result[Length(Result)-1]:=CryptoKey.length+(CryptoKey.TextLength-CryptoKey.length*CryptoKey.TextParts);
end;
Сама программа выглядит следующим образом:
Все достаточно просто: грузим картинку, пишем текст для записи, определяем количество чачтей, на которые следует разбить текст, определяем ключ и шифруем.
В итоге, после записи текста программа проверит своб работу и выведет в закладке “Техническая часть” проверяемые данные:
Если результат проверки Вас устраивает (текст читается без потерь) значит все замечательно, иначе процедуру записи следует повторить, изменив данные, например количество частей текста или размер самой строки. По предварительным данным, в картинку можно записывать до 1500 символов текста, но при этом на картинке появляется “рябь”.
Так как сейчас я предоставляю Вам только наброски программы или, выражаясь более официально, бетта-версию :), то надеюсь на Ваше участие в развитии программы, указание ошибок, недочетов и пр. Кстати, я не первый, кто додумался до такого. Помню где-то год назад попадалась мне на глаза статья с подобным алгоритмом шифрования текста, но хоть убейте не могу её отыскать в Интернете, видимо администратор этого сайта не в курсе, что такое раскрутка веб сайта. Буду благодарен, если поделитесь ссылочкой на эту статью.
Кстати, если кто-то заинтересуется самим алгоритмом, то в принципе можно организовать запись любых данных, например массивов чисел и пр.
Файл для загрузки: CryptoPict.zip
Мой блог находят по следующим фразам
- IHTMLElement
- HttpQueryInfo
- работа с microsoft agent
- программа слова облаком
- Как сохранить stringgrid в OOCalc
- информация о запущенном процессе delphi
Мой блог находят по следующим фразам
- pascal HttpQueryInfo
- delphi ribboncombobox
- delphi excel заливка в ячеек
- Help Update 1 for RAD Studio, Delphi & C++Builder 2010
- lazarus memo русские буквы
- примеры регулярных выражений Delphi
Related posts:












14 Aug 2009 в 11:45 am
Помню где-то год назад попадалась мне на глаза статья с подобным алгоритмом шифрования текста, но хоть убейте не могу её отыскать в Интернете.
Есть md5, думаю ты и так об этом знаешь)
Кстати говоря, есть программы, которые позволяют внести (записать) внутрь картинки мультемедиа файл (например музыку).
14 Aug 2009 в 9:18 pm
Знаю, что есть, но самому-то написать интереснее :)
22 Sep 2009 в 11:31 am
Сори. Но как сохранить зашифрованную картинку? У меня не получается.
22 Sep 2009 в 9:29 pm
В статье процедура procedure PictCrypt(SourceFile, TargetFile: TFileName; CryptoKey:TCryptoKey; Text:String);
как раз и записывает в TargetFille зашифрованную картинку.
06 Nov 2009 в 5:23 pm
Этот код можно использовать в виде зашиты логотипов или рекламы. Типо есть прога в ней используется файл картинки с логотипом фирмы, в файле зашифрован код. А пользователь не может взять и заменить картинку своей со своим логотипом так как в ней нет кода, и прога отказывается запускатся. :)
07 Nov 2009 в 1:39 pm
Логично :)