Понедельник, 13.04.2026, 22:41
Rudoysecurity
Приветствую Вас Гость | RSS
Главная Каталог статей Регистрация Вход
Меню сайта

Категории раздела
Статьи администратора [5]
Статьи, опубликованные администрацией сайта

Мини-чат

Наш опрос
Ваше отношение к программе "Рейнджер"
Всего ответов: 93

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Вход в портал

Главная » Статьи » Статьи администратора » Статьи администратора

Типичные ошибки реализации XOR-шифрования (гаммирования) и одноразового блокнота в Delphi

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

Введение

В криптографических реализациях на Delphi, особенно при работе с XOR-шифрованием и одноразовым блокнотом, программисты часто допускают систематические ошибки, коренящиеся в непонимании фундаментального различия между текстовыми (String) и бинарными (TBytes) данными и их представлениями в бинарных строк (Binary string). Это исследование анализирует типичные ошибки, их причины, последствия и предоставляет практические рекомендации для корректной реализации .

1. Криптографические основы: XOR-шифрование и одноразовый блокнот

1.1 XOR-шифрование

XOR-шифрование — это аддитивный шифр, использующий операцию исключающего ИЛИ (XOR) между открытым текстом и ключом. Алгоритм основан на свойствах операции XOR: A⊕0=A, A⊕A=0, A⊕B=B⊕A, (A⊕B)⊕C=A⊕(B⊕C). При использовании повторяющегося ключа этот метод уязвим для частотного анализа, но с полностью случайным ключом, равным по длине сообщению и использованным однократно, он превращается в теоретически невзламываемый одноразовый блокнот .

1.2 Одноразовый блокнот (OTP)

Одноразовый блокнот — это криптографический метод, обеспечивающий абсолютную секретность при соблюдении четырёх условий:

  1. Ключ должен быть не короче открытого текста

  2. Ключ должен быть действительно случайным (truly random)

  3. Ключ никогда не должен повторно использоваться (даже частично)

  4. Ключ должен оставаться полностью секретным для всех, кроме законных участников обмена

Нарушение любого из этих условий делает систему уязвимой. Математически доказано, что при соблюдении всех условий OTP обеспечивает совершенную секретность .

2. Типы данных в Delphi: фундаментальное различие

2.1 String (UnicodeString в современных версиях)

В Delphi 2009 и выше тип String представляет собой UnicodeString с кодировкой UTF-16. Каждый символ занимает 2 байта (16 бит), что обеспечивает поддержку всех языков мира, включая кириллицу. Однако это текстовый тип, предназначенный для хранения символов, а не произвольных бинарных данных. Путаницу дополнительно вносят руководящие документы, спецификации, стандарты по алгоритмам шифрования - в криптографии под понятием "строка" понимается Binary string (символьное представление массива байтов в виде 1 и 0), а в языках программирования  String - буквально "строка" - текстовая строка символов.

Внутреннее представление:

  • Хранит символы в кодировке UTF-16LE (Little Endian)

  • Автоматически управляет памятью и кодировками

  • Индексация начинается с 1

  • Функция Length() возвращает количество символов, а не байтов

2.2 TBytes (бинарные данные)

TBytes — это динамический массив байтов (array of Byte), предназначенный для хранения произвольных бинарных данных без преобразований кодировок. Это правильный выбор для криптографических операций, работы с файлами, сетевыми протоколами и другими бинарными форматами. Для визуализации бинарных данных используют "двоичные строки" (Binary string).

Ключевые характеристики:

  • Не выполняет автоматических преобразований кодировок

  • Сохраняет все байтовые значения (0-255) без изменений

  • Индексация начинается с 0

  • Length() возвращает количество байтов

2.3 Преобразования между типами

Для корректного преобразования необходимо явно указывать кодировку:

delphi

// String → TBytes
var
 Bytes: TBytes;
 Text: string;
begin
 Bytes := TEncoding.UTF8.GetBytes(Text); // Для UTF-8
 Bytes := TEncoding.Unicode.GetBytes(Text); // Для UTF-16
end;

// TBytes → String
var
 Text: string;
 Bytes: TBytes;
begin
 Text := TEncoding.UTF8.GetString(Bytes);
 Text := TEncoding.Unicode.GetString(Bytes);
end;

Прямое приведение типов string(MyBytes) или TBytes(MyString) без учёта кодировки приводит к искажению данных и является распространённой ошибкой .

3. Систематизация типичных ошибок

3.1 Категория 1: Ошибки выбора типа данных для хранения зашифрованных данных

Проблема: Использование String вместо TBytes для результатов шифрования.

Конкретные ошибки:

  • Хранение шифротекста в переменных типа String

  • Возврат String из функций шифрования вместо TBytes

  • Использование TStringList.Text для объединения бинарных данных (добавляет символы перевода строк)

Пример некорректного кода:

delphi

function EncryptXOR(Text, Key: String): String; // Ошибка: возвращает String
var
 i: Integer;
begin
 Result := '';
 for i := 1 to Length(Text) do
 Result := Result + Chr(Ord(Text[i]) xor Ord(Key[1 + ((i-1) mod Length(Key))]));
end;

Проблемы:

  1. Результат XOR может содержать байт 0, который интерпретируется как конец строки

  2. Автоматические преобразования кодировок искажают данные

  3. Невозможно корректно сохранить или передать бинарные данные

Решение: Всегда использовать TBytes для криптографических данных .

3.2 Категория 2: Ошибки преобразования между текстовыми и бинарными представлениями

Проблема: Неправильные преобразования между String и TBytes без учёта кодировки.

Конкретные ошибки:

  • Прямое приведение типов: MyString := string(MyBytes)

  • Использование BytesOf()/StringOf() без учёта кодировки UTF-16

  • Смешивание TEncoding.UTF8 и TEncoding.Unicode при работе с одним набором данных

Пример: Приведение TBytes к String без нулевого терминатора приводит к чтению случайных данных из памяти .

Решение: Всегда явно указывать кодировку при преобразованиях:

delphi

// Правильное преобразование
Bytes := TEncoding.UTF8.GetBytes(Text);
Text := TEncoding.UTF8.GetString(Bytes);

3.3 Категория 3: Ошибки обработки нулевых байтов

Проблема: При операции XOR вероятность получения байта 0 составляет 1/256. В строковых типах нулевой байт интерпретируется как конец строки.

Конкретные ошибки:

  • Отображение зашифрованных данных в TMemo или других текстовых контролах

  • Использование строковых функций (Length()Copy()Pos()) для обработки шифротекста

  • Логирование бинарных данных как строк без предварительного кодирования (Base64, Hex)

Пример: Если szOriginal[i] == szKey[i], результат XOR будет 0, создавая ложный терминатор строки .

Решение: Для хранения и отображения использовать кодировки Base64 или Hex:

delphi

// Кодирование в Base64 для отображения/передачи
function BytesToBase64(const Bytes: TBytes): string;
begin
 Result := TNetEncoding.Base64.EncodeBytesToString(Bytes);
end;

3.4 Категория 4: Ошибки работы с кодировками и Unicode

Проблема: В UnicodeString каждый символ занимает 2+ байта, а криптографические алгоритмы работают с байтами.

Конкретные ошибки:

  • Шифрование String напрямую без преобразования в TBytes

  • Неправильный расчет размеров: j := Length(Str) даёт символы, а нужно байты

  • Использование AnsiString в Unicode-версиях Delphi для “совместимости”

Пример ошибки с Unicode:

delphi

// Некорректно для Unicode
for i := 1 to Length(Text) do // Length возвращает символы, не байты
 ByteValue := Ord(Text[i]); // Ord от Char возвращает код символа, а не байт

Решение: Всегда работать с байтами внутри алгоритмов шифрования:

delphi

function XorEncrypt(const Data, Key: TBytes): TBytes;
var
 i: Integer;
begin
 SetLength(Result, Length(Data));
 for i := 0 to High(Data) do
 Result[i] := Data[i] xor Key[i mod Length(Key)];
end;

3.5 Категория 5: Ошибки обработки ключей

Проблема: Ключи — это бинарные данные, а не текст. Текстовые пароли должны преобразовываться в бинарные ключи.

Конкретные ошибки:

  • Хранение ключей в переменных типа String

  • Использование текстовых ключей разной длины

  • Отсутствие преобразования текстовых паролей в бинарные ключи фиксированной длины

  • Повторное использование ключей в одноразовом блокноте

Критическая ошибка: Повторное использование ключа в OTP полностью компрометирует безопасность, позволяя восстановить ключ при наличии нескольких зашифрованных сообщений .

Решение: Использовать Key Derivation Function (KDF) для преобразования паролей:

delphi

// Пример использования PBKDF2 для получения ключа из пароля
function DeriveKey(const Password: string; Salt: TBytes; KeyLength: Integer): TBytes;
begin
 // Использовать PBKDF2 или аналогичную функцию
end;

3.6 Категория 6: Ошибки реализации побайтовых операций

Проблема: Неправильные индексные вычисления и приведение типов при побайтовых операциях.

Конкретные ошибки:

  • Индексация: в String начинается с 1, в TBytes — с 0

  • Операции над Char (2 байта) вместо Byte (1 байт)

  • Неправильное использование Ord() и Chr() для байтовых значений

Пример некорректного кода:

delphi

// Несколько ошибок в одном примере
function XorStrings(Str1, Str2: UTF8String): UTF8String;
var
 i: Integer;
 Ci: Char;
begin
 for i := 0 to Length(Str1) - 1 do
 begin
 Ci := Char(Ord(Str1) xor Ord(Str2)); // Ошибка: Ord от всей строки
 Result := Result + Ci;
 end;
end;

Решение: Единообразно работать с индексами от 0:

delphi

// Корректная реализация
function XorBytes(const Data, Key: TBytes): TBytes;
var
 i: Integer;
begin
 SetLength(Result, Length(Data));
 for i := 0 to High(Data) do
 Result[i] := Data[i] xor Key[i mod Length(Key)];
end;

3.7 Категория 7: Ошибки взаимодействия с внешними системами

Проблема: Шифрованные данные передаются между системами с разными представлениями строк.

Конкретные ошибки:

  • Отправка бинарных данных как текст через HTTP/JSON без кодирования

  • Несовпадение кодировок по умолчанию в Delphi, PHP, JavaScript

  • Ожидание текстового представления там, где нужны бинарные данные

Пример проблемы Delphi-PHP: Разное поведение при XOR-операциях из-за различий в обработке строк и кодировок .

Решение: Использовать Base64 для межсистемного взаимодействия:

delphi

// Delphi → PHP совместимость
function EncryptForPHP(const Text, Key: string): string;
var
 DataBytes, KeyBytes, EncryptedBytes: TBytes;
begin
 DataBytes := TEncoding.UTF8.GetBytes(Text);
 KeyBytes := TEncoding.UTF8.GetBytes(Key);
 EncryptedBytes := XorBytes(DataBytes, KeyBytes);
 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedBytes);
end;

4. Практические рекомендации

4.1 Общие принципы

  1. Всегда использовать TBytes для криптографических данных — ключи, шифротекст, открытый текст

  2. Явно указывать кодировки при преобразованиях — TEncoding.UTF8 для текста

  3. Работать только с байтами внутри алгоритмов — преобразовывать в TBytes на входе и обратно на выходе

  4. Использовать Base64 или Hex для хранения и передачи — кодировать бинарные данные для логов, БД, сетевой передачи

  5. Тестировать с нулевыми байтами и Unicode-символами — включать в тестовые данные байт 0 и символы за пределами ASCII

4.2 Корректная архитектура функции шифрования

delphi

// Правильная сигнатура функций
function XorEncrypt(const Data, Key: TBytes): TBytes; overload;
function XorEncrypt(const Text, Key: string): string; overload;

// Реализация
function XorEncrypt(const Data, Key: TBytes): TBytes;
var
 i: Integer;
begin
 if Length(Key) = 0 then
 raise Exception.Create('Key cannot be empty');
 
 SetLength(Result, Length(Data));
 for i := 0 to High(Data) do
 Result[i] := Data[i] xor Key[i mod Length(Key)];
end;

function XorEncrypt(const Text, Key: string): string;
var
 DataBytes, KeyBytes, EncryptedBytes: TBytes;
begin
 // Явное преобразование с указанием кодировки
 DataBytes := TEncoding.UTF8.GetBytes(Text);
 KeyBytes := TEncoding.UTF8.GetBytes(Key);
 
 EncryptedBytes := XorEncrypt(DataBytes, KeyBytes);
 
 // Кодирование в Base64 для безопасного возврата как строки
 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedBytes);
end;

4.3 *Учебная демонстрационная реализация одноразового блокнота в Delphi 

delphi

type
 TOneTimePad = class
 private
 FKey: TBytes;
 FUsed: Boolean;
 public
 constructor Create(KeyLength: Integer);
 function Encrypt(const Data: TBytes): TBytes;
 function Decrypt(const Data: TBytes): TBytes;
 property Used: Boolean read FUsed;
 end;

constructor TOneTimePad.Create(KeyLength: Integer);
begin
 SetLength(FKey, KeyLength);
 // Генерация действительно случайного ключа
 RandomBytes(FKey[0], KeyLength);
 FUsed := False;
end;

function TOneTimePad.Encrypt(const Data: TBytes): TBytes;
begin
 if FUsed then
 raise Exception.Create('Key already used');
 
 if Length(Data) > Length(FKey) then
 raise Exception.Create('Data longer than key');
 
 Result := XorEncrypt(Data, FKey);
 FUsed := True;
end;

5. Проверка актуальности на 2026 год

Анализ современных источников подтверждает, что основные принципы работы с бинарными данными в Delphi остаются неизменными. Рекомендации по использованию TBytes для криптографических операций актуальны для всех современных версий Delphi, включая Alexandria и более поздние. Проблемы с нулевыми байтами и неправильной интерпретацией бинарных данных как строковых продолжают быть распространёнными ошибками даже в 2026 году .

Ключевые изменения в современных версиях Delphi:

  • Улучшенная поддержка кодировок через класс TEncoding

  • Расширенные возможности работы с TBytes в RTL

  • Более строгая типизация, помогающая избегать некоторых ошибок приведения типов

Заключение

Типичные ошибки программистов на Delphi при реализации XOR-шифрования и одноразового блокнота коренятся в фундаментальной путанице между текстовыми (String) и бинарными (TBytes) данными. Криптографические алгоритмы работают с байтами, а не с символами, и любое некорректное преобразование между этими представлениями приводит к искажению данных и нарушению безопасности.

Ключевые выводы:

  1. Всегда используйте TBytes для хранения и обработки криптографических данных

  2. Явно указывайте кодировки при преобразовании между строками и байтами

  3. Помните о проблеме нулевых байтов и используйте Base64/Hex для хранения и передачи

  4. Для одноразового блокнота соблюдайте все четыре условия безопасности

  5. Тестируйте реализации с разнообразными данными, включая нулевые байты и Unicode-символы

Соблюдение этих принципов позволит избежать распространённых ошибок и создавать корректные, безопасные криптографические реализации на Delphi.

*Учебная демонстрационная реализация - не соответствует принципам, изложенными В.А. Котельниковым в "Основные положения автоматической зашифровки" и К. Шенноном в "Теория связи в секретных системах" (One-Time Pad Cipher)

Категория: Статьи администратора | Добавил: Rudoysecurity (13.02.2026) | Автор: Rudoysecurity
Просмотров: 66 | Рейтинг: 5.0/2
Всего комментариев: 0
avatar
Новости ГСПИ

Вход в почту
Логин:
Пароль:
(что это)

Поиск

Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • ООО Аспект-С
  • Кадровое агентство
  • Рекламное агентство
  • ИКЦ Эксперт
  • Rudoysecurity
  • Центр сертификации

  • Система авторегистрации в каталогах, статьи про раскрутку сайтов, web дизайн, flash, photoshop, хостинг, рассылки; форум, баннерная сеть, каталог сайтов, услуги продвижения и рекламы сайтов ROBOKASSA
    Copyright Rudoysecurity ©2009 - 2026 Бесплатный конструктор сайтовuCoz