В процессе разработки конфигураций и внешних обработок на платформе 1С:Предприятие 7.7 часто возникает необходимость защитить конфиденциальные сведения: пароли подключения к внешним базам, учетные данные API или внешние файлы настроек. Разберем особенности реализации криптографических механизмов в среде 1С 7.7, изучим готовые алгоритмы на встроенном языке и проанализируем альтернативные способы защиты информации.
Прежде чем приступать к программной реализации, выясним ключевые архитектурные ограничения платформы 1С 7.7:
XOR, AND, OR, битовых сдвигов). Для их выполнения приходится подключать системный COM-объект MSScriptControl.ScriptControl с языком VBScript или использовать сторонние библиотеки.Симв(0)), строка обрезается. Поэтому зашифрованный бинарный поток необходимо обязательно упаковывать в безопасный формат (например, шестнадцатеричный вид — Hex).Рассмотрим реализацию симметричного шифрования на основе псевдослучайных перестановок (S-блока) и побайтовой операции XOR. Для выполнения логического сложения по модулю 2 используется MSScriptControl.ScriptControl.
Разберем базовую функцию преобразования строки по ключу:
// Функция шифрует или дешифрует набор символов с помощью S-Блока, сформированного на основе ключа.
// Строчка - Строка. Набор символов для преобразования.
// Ключ - Строка. Набор символов для формирования S-Блока.
Функция СтрКодироватьСтрокуВнутр(Строчка, Ключ) Экспорт
Перем масТемп[254], масSБлок[254];
Перем чисДлинаКлюча, чисДлинаТекста, х, у, чисТемп, ЧисБайт, Ответ, ч;
Перем Shell_funcXOR;
Shell_funcXOR = СоздатьОбъект("MSScriptControl.ScriptControl");
Shell_funcXOR.Language = "VBScript";
Shell_funcXOR.AddCode("function intXOR(x, y) | intXOR = x xor y |end function");
// Инициализация данных для формирования S-Блока
чисДлинаКлюча = СтрДлина(Ключ);
у = 0;
Для х = 1 По 254 Цикл
у = у + 1;
у = ?(у > чисДлинаКлюча, 1, у);
масТемп[х] = КодСимв(Сред(Ключ, у, 1));
масSБлок[х] = х - 1;
КонецЦикла;
// Формирование S-Блока
у = 0;
Для х = 1 По 254 Цикл
у = (у + масТемп[х] + масSБлок[х]) % 254 + 1;
чисТемп = масSБлок[х];
масSБлок[х] = масSБлок[у];
масSБлок[у] = чисТемп;
КонецЦикла;
// Преобразование исходного текста
чисДлинаТекста = СтрДлина(Строчка);
у = 0;
ч = 0;
Ответ = "";
Для х = 1 По чисДлинаТекста Цикл
чисБайт = КодСимв(Сред(Строчка, х, 1));
у = (у + 1) % 254 + 1;
ч = (ч + масSБлок[у]) % 254 + 1;
чисТемп = масSБлок[у];
масSБлок[у] = масSБлок[ч];
масSБлок[ч] = чисТемп;
чисТемп = масSБлок[(масSБлок[у] + масSБлок[ч]) % 254 + 1];
чисБайт = Число(Shell_funcXOR.Run("intXOR", чисБайт, чисТемп));
Ответ = Ответ + Симв(чисБайт);
КонецЦикла;
Возврат Ответ;
КонецФункции
Поскольку результат битового шифрования может содержать непечатные и нулевые символы, обязательно преобразуем результат в шестнадцатеричную строку (Hex) и обратно:
// Конвертирует строку в её шестнадцатеричное представление
Функция СтрКонвертироватьВШестнадцатиричнуюСтроку(Строчка) Экспорт
Перем Результат, ДлинаСтроки, Номер, Символ, Цифра;
ДлинаСтроки = СтрДлина(Строчка);
Результат = "";
Для Номер = 1 По ДлинаСтроки Цикл
Символ = КодСимв(Сред(Строчка, Номер, 1));
Цифра = Цел(Символ / 16);
Результат = Результат + ?(Цифра < 10, Строка(Цифра), Симв(КодСимв("A") + Цифра - 10));
Цифра = Цел(Символ % 16);
Результат = Результат + ?(Цифра < 10, Строка(Цифра), Симв(КодСимв("A") + Цифра - 10));
КонецЦикла;
Возврат Результат;
КонецФункции
// Конвертирует строку из шестнадцатеричного представления в исходную строку
Функция СтрКонвертироватьИзШестнадцатиричнойСтроки(Строчка) Экспорт
Перем Результат, ДлинаСтроки, Номер, Символ, Цифра;
ДлинаСтроки = Цел(СтрДлина(Строчка) / 2);
Результат = "";
Для Номер = 1 По ДлинаСтроки Цикл
Символ = КодСимв(Сред(Строчка, Номер * 2 - 1, 1));
Символ = ?(Символ < КодСимв("A"), Символ - КодСимв("0"), Символ - КодСимв("A") + 10);
Цифра = 16 * Символ;
Символ = КодСимв(Сред(Строчка, Номер * 2, 1));
Символ = ?(Символ < КодСимв("A"), Символ - КодСимв("0"), Символ - КодСимв("A") + 10);
Цифра = Цифра + Символ;
Результат = Результат + Симв(Цифра);
КонецЦикла;
Возврат Результат;
КонецФункции
Для предотвращения частотного анализа коротких строк (например, паролей) добавим автоматическое дополнение строки солью до минимальной заданной длины:
// Функция шифрует строку на основе ключа с добавлением соли
Функция СтрКодироватьСтроку(Знач Строчка, Ключ, МинимальнаяДлина = 20) Экспорт
Перем Соль;
Соль = _GetPerformanceCounter % 1000;
Строчка = Формат(СтрДлина(Строчка), "Ч04") + Строчка;
Пока СтрДлина(Строчка) < МинимальнаяДлина Цикл
Строчка = Строчка + СокрЛП(_IdToStr(Соль));
Соль = (Соль * Соль) % 1000;
КонецЦикла;
Возврат СтрКонвертироватьВШестнадцатиричнуюСтроку(СтрКодироватьСтрокуВнутр(Строчка, Ключ));
КонецФункции
// Функция расшифровывает шестнадцатеричную строку
Функция СтрРаскодироватьСтроку(Строчка, Ключ) Экспорт
Перем Результат;
Результат = СтрКодироватьСтрокуВнутр(СтрКонвертироватьИзШестнадцатиричнойСтроки(Строчка), Ключ);
Возврат Сред(Результат, 5, Число(Лев(Результат, 4)));
КонецФункции
Если требуется шифровать большие текстовые файлы или целые массивы данных, возможностей чистого встроенного языка 1С 7.7 будет недостаточно по скорости. В таких случаях применяются следующие методы:
WScript.Shell (метод Exec()) и считывать результат напрямую из потока standard output (StdOut).