Хочу поделиться примером реализации обработки по шифрованию/расшифровке произвольных текстовых полей справочников. Требования перед разработкой я поставил следующие:
- Должен быть реализован функционал шифрования и расшифровки по паролю;
- Зашифрованные данные должны храниться в полях исходных данных, т.е. длина зашифрованного текста должна быть равной длине исходного текста, дополнительных таблиц быть не должно;
- Список полей для шифрования/расшифровки должен быть настраиваемым и не зависеть от конфигурации;
- Шифрование должно выполняться средствами платформы 1С без внешних компонент, com-объектов и т.д., чтобы исключить зависимость от ОС;
Решений на Инфостарте по шифрованию/расшифровки строк огромное множество (Защита и шифрование) - практически на любой вкус. Приведу наиболее интересные (на мой субъективный взгляд):
- Подсистема шифрования данных + пример реализации: решение Keystore для хранения паролей;
- Симметричное шифрование в 1С;
- Шифрование текста, хеш сумма;
- Хеширование данных с ключом по алгоритму SHA-1 штатными средствами 1С;
- Шифратор и дешифратор текста и файлов для 1С;
Однако, найти публикацию, отвечающую всем моим требованиям, так и не удалось. Из-за наличия требования №2 (о не превышении длиной зашифрованного текста длины исходного текста), в качестве метода шифрования был выбран шифр Виженера.
Да, по современным стандартам данный шифр является ненадежным и поддается взлому. Поэтому, чтобы повысить время на дешифровку текста, в базовый алгоритм были внесены следующие улучшения:
- Ключ для шифрования формируется на основании пароля, длина ключа шифрования равна длине шифруемого текста;
- Код каждого символа ключа шифрования равен коду соответсвующего символа пароля, смещенного на псевдо случайную величину А;
- Псевдо случайная величина А зависит от максимального кода среди символов пароля и длины кодируемой строки;
- Код каждого символа зашифрованной строки равен сумме кода соответствующего символа исходной строки, кода соответствующего символа ключа шифрования и псевдо-случайной величины В;
- Псевдо случайная величина В зависит от максимального кода среди символов ключа шифрования и длины кодируемой строки;
Для генерации псевдо случайных величин использовался встроенный объект платформы "ГенераторСлучайныхЧисел". Ниже приведны основные функции обработки:
- Функция ПолучитьМаксимальныйКодСимволаСтроки - получает максимальный код символа в переданной строке :
Функция ПолучитьМаксимальныйКодСимволаСтроки(СтрокаАнализа) ДлинаСтрокиАнализа = СтрДлина(СтрокаАнализа); МаксимальныйКодСимвола = 0; Для Счетчик = 1 По ДлинаСтрокиАнализа Цикл КодТекущегоСимвола = КодСимвола(СтрокаАнализа, Счетчик); Если КодТекущегоСимвола > МаксимальныйКодСимвола Тогда МаксимальныйКодСимвола = КодТекущегоСимвола; КонецЕсли; КонецЦикла; Возврат МаксимальныйКодСимвола; КонецФункции
- Функция ПолучитьКлючШифрования - получает по паролю ключ шифрования с учетом псевдо случайного смещения:
Функция ПолучитьКлючШифрования(лПароль, ДлинаКодируемойСтроки) лПароль_Длина = СтрДлина(лПароль); КлючШифрования = ""; ЧислоДляИнциализацииГенератораСлучаныхЧисел = ПолучитьМаксимальныйКодСимволаСтроки(лПароль_Длина); ЧислоДляИнциализацииГенератораСлучаныхЧисел = ЧислоДляИнциализацииГенератораСлучаныхЧисел + ДлинаКодируемойСтроки; ГенераторСлучаныхЧисел = Новый ГенераторСлучайныхЧисел(ЧислоДляИнциализацииГенератораСлучаныхЧисел); СчетчикПоПаролю = Неопределено; Для Счетчик = 1 По ДлинаКодируемойСтроки Цикл Если (СчетчикПоПаролю = Неопределено) ИЛИ (СчетчикПоПаролю > лПароль_Длина) Тогда СчетчикПоПаролю = 1; КонецЕсли; СлучайноеСмещение = ГенераторСлучаныхЧисел.СлучайноеЧисло(1, ЧислоДляИнциализацииГенератораСлучаныхЧисел); СимволПароля = Сред(лПароль, СчетчикПоПаролю, 1); КлючШифрования = КлючШифрования + Символ(КодСимвола(СимволПароля) + СлучайноеСмещение); СчетчикПоПаролю = СчетчикПоПаролю + 1; КонецЦикла; Возврат КлючШифрования; КонецФункции
- Функция ЗашифроватьСтроку - шифрует строку шифром Виженера по ключу шифрования с учетом псевдо случайного смещения:
Функция ЗашифроватьСтроку(КодируемаяСтрока, КлючШифрования) ДлинаКодируемойСтроки = СтрДлина(КодируемаяСтрока); ЧислоДляИнциализацииГенератораСлучаныхЧисел = ПолучитьМаксимальныйКодСимволаСтроки(КлючШифрования); ЧислоДляИнциализацииГенератораСлучаныхЧисел = ЧислоДляИнциализацииГенератораСлучаныхЧисел + ДлинаКодируемойСтроки; ГенераторСлучаныхЧисел = Новый ГенераторСлучайныхЧисел(ЧислоДляИнциализацииГенератораСлучаныхЧисел); ЗакодированнаяСтрока = ""; Для Счетчик = 1 ПО ДлинаКодируемойСтроки Цикл КодСимволаИсходнойСтроки = КодСимвола(КодируемаяСтрока, Счетчик); КодСимволаКлючаШифрования = КодСимвола(КлючШифрования, Счетчик); СлучайнаяСоставляющая = ГенераторСлучаныхЧисел.СлучайноеЧисло(1, ЧислоДляИнциализацииГенератораСлучаныхЧисел); КодЗакодированныгоСимвола = КодСимволаИсходнойСтроки + КодСимволаКлючаШифрования + СлучайнаяСоставляющая; ЗакодированнаяСтрока = ЗакодированнаяСтрока + Символ(КодЗакодированныгоСимвола); КонецЦикла; Возврат ЗакодированнаяСтрока; КонецФункции
- Функция РасшифроватьСтроку - расшифровывает строку по ключу шифрования с учетом псевдо случайного смещения:
Функция РасшифроватьСтроку(КодируемаяСтрока, КлючШифрования) ДлинаКодируемойСтроки = СтрДлина(КодируемаяСтрока); ЧислоДляИнциализацииГенератораСлучаныхЧисел = ПолучитьМаксимальныйКодСимволаСтроки(КлючШифрования); ЧислоДляИнциализацииГенератораСлучаныхЧисел = ЧислоДляИнциализацииГенератораСлучаныхЧисел + ДлинаКодируемойСтроки; ГенераторСлучаныхЧисел = Новый ГенераторСлучайныхЧисел(ЧислоДляИнциализацииГенератораСлучаныхЧисел); ЗакодированнаяСтрока = ""; Для Счетчик = 1 ПО ДлинаКодируемойСтроки Цикл КодСимволаКлючаШифрования = КодСимвола(КлючШифрования, Счетчик); КодЗакодированныгоСимвола = КодСимвола(КодируемаяСтрока, Счетчик); СлучайнаяСоставляющая = ГенераторСлучаныхЧисел.СлучайноеЧисло(1, ЧислоДляИнциализацииГенератораСлучаныхЧисел); КодСимволаИсходнойСтроки = КодЗакодированныгоСимвола - КодСимволаКлючаШифрования - СлучайнаяСоставляющая; ЗакодированнаяСтрока = ЗакодированнаяСтрока + Символ(КодСимволаИсходнойСтроки); КонецЦикла; Возврат ЗакодированнаяСтрока; КонецФункции
- Функция ЗашифроватьРасшифроватьПолеОбъекта - получает ключ шифрования по паролю и шифрует или расшифровывает строку в зависимости от входных параметров:
Процедура ЗашифроватьРасшифроватьПолеОбъекта(ЗначениеРеквизита, Пароль, ЗаписатьЭлемент, ЭтоШифрование) Если НЕ ПустаяСтрока(ЗначениеРеквизита) Тогда КлючШифрования = ПолучитьКлючШифрования(Пароль, СтрДлина(ЗначениеРеквизита)); Если ЭтоШифрование Тогда ЗначениеРеквизита = ЗашифроватьСтроку(ЗначениеРеквизита, КлючШифрования); Иначе ЗначениеРеквизита = РасшифроватьСтроку(ЗначениеРеквизита, КлючШифрования); КонецЕсли; Если НЕ ЗаписатьЭлемент Тогда ЗаписатьЭлемент = ИСТИНА; КонецЕсли; КонецЕсли; КонецПроцедуры
Фактическая реализация алгоритма в виде обработки в приложенном файле. Интерфейс обработки интуитивно понятен. Для выполнения шифрования (или расшифровки) необходимо выполнить несколько простых шагов:
- Выбрать поля данных в базе для обработки (при нажатии на гиперссылку с надписью "Обработать:" открывается отдельная форма с деревом справочников конфигурации со всеми текстовыми реквизитами и табличными частями с текстовыми реквизитами;
- Ввести пароль;
- Ввести подтверждение пароля;
- Нажать кнопку "Зашифровать" или "Расшифровать" в зависимости от требуемого действия.
В качестве примера работы алгоритма приложены скриншоты со справочником "Страны" до шифрования и после шифрования. На этом все, спасибо за внимание, надеюсь, кому-нибудь пригодится.
Конструктивная критика приветствуется!