Описание параметров функции :
- АдресВХ - содержит зашифрованную информацию, в двух состояниях:
- 1. Строку адреса временного хранилища значений, типа "Двоичные данные"
- 2. Данные в виде "Двоичных данных"
- РасширениеФайла - расширение файла, который передан по параметру "АдресВХ"
- ВариантОбработки - вариант обработки, пока их два:
- 1. ZIP - алгоритм ищет в файле SGN заголовок ZIP файла
- 2. произвольный формат - алгоритм ищет начала SGN пакета
- УИДФормы - уникальный идентификатор формы, используется только если передали в качестве входных данных строку "временного хранилища значений"
- стрНастройки - структура с обязательными полями:
- "ИдентификаторСертификатаДешифровки" - идентификатор сертификата для дешифровки данных. Поле не обязательное для заполнения. (можно передать пустую строку)
- "ПарольСертификатаДешифровки" - пароль к закрытому ключу
- ТекстСообщения - возвращает описание ошибки.
- Отказ - флаг ошибки, если Истина, то была ошибка и данные не дишефрованы.
Функция ДешифроватьФайл(АдресВХ, РасширениеФайла, ВариантОбработки, УИДФормы=Неопределено, стрНастройки, ТекстСообщения, Отказ) Экспорт
АдресВХ_Дешиф = Неопределено;
Попытка
ИдентификаторСертификатаДешифровки = стрНастройки.ИдентификаторСертификатаДешифровки;
ПарольКЗакрытомуКлючу = стрНастройки.ПарольСертификатаДешифровки;
УказанСертификат = (ИдентификаторСертификатаДешифровки <> Неопределено И Не ПустаяСтрока(ИдентификаторСертификатаДешифровки));
Если УказанСертификат <> Истина Тогда
ИдентификаторСертификатаДешифровки = "<сертификат не указан>";
КонецЕсли;
//Инициализируем крипто...
МенеджерКриптографии = ПолучитьМенеджерКриптографии();
МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = ПарольКЗакрытомуКлючу;
//Файл PEM, это текстовый файл...
// 2. Читаем текстовый PEM-файл и переводим в двоичные данные
ЭтоДвоичныеДанные = (ТипЗнч(АдресВХ) = Тип("ДвоичныеДанные"));
Если ЭтоДвоичныеДанные = Истина Тогда
ДвоичныеДанныеФайла = АдресВХ;
Иначе
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресВХ);
КонецЕсли;
Если ВРег(РасширениеФайла) = "PEM" или ВРег(РасширениеФайла) = ".PEM" Тогда
Если УказанСертификат = Истина Тогда
Хран = МенеджерКриптографии.получитьХранилищеСертификатов();
Сертификаты = Хран.ПолучитьВсе();
Для каждого тСерт из Сертификаты Цикл
Если СтрЗаменить(Строка(тСерт.СерийныйНомер)," ","") = ИдентификаторСертификатаДешифровки Тогда
РасшифрованныеДанные = МенеджерКриптографии.Расшифровать(ДвоичныеДанныеФайла,тСерт);
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
РасшифрованныеДанные = МенеджерКриптографии.Расшифровать(ДвоичныеДанныеФайла);
КонецЕсли;
//Зашифрован либо старым, либо отстуствующим сертификатом...
// Либо вы в настройке не указали, что уже надо дешифроваывать новым сертификатом.
Если РасшифрованныеДанные = Неопределено Тогда
ТекстСообщения = "Не удалось дешифровать данные сертификатом: "+Строка(ИдентификаторСертификатаДешифровки);
Отказ = Истина;
Возврат АдресВХ_Дешиф;
КонецЕсли;
//Вариант, где мы получаем чистый ZIP архив, дедовским методом...
Если ВариантОбработки = Неопределено Тогда
ВариантОбработки = 2; //Для любого файла
КонецЕсли;
ДвоичныеДанныеФайлаЗИП = Неопределено;
Если ВариантОбработки = 1 Тогда //Чисто для ZIP архива!
// 2. Преобразуем бинарный массив в строку Base64
ДвоичныеДанныеПодписи = ПолучитьДвоичныеДанныеФайлаИзPEM(РасшифрованныеДанные);
ПолныйТекстBase64 = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанныеПодписи);
// Эталонная сигнатура начала ZIP-архива в формате Base64
СигнатураZIP = "UEsDBBQAAAA";
// 3. Ищем позицию начала архива в тексте
ПозицияНачала = СтрНайти(ПолныйТекстBase64, СигнатураZIP);
Если ПозицияНачала > 0 Тогда
// Вырезаем чистый Base64-текст архива, отбросив заголовок подписи УЦ
ЧистыйТекстZIP = Сред(ПолныйТекстBase64, ПозицияНачала);
// 4. Превращаем очищенную строку обратно в бинарный ZIP-архив
ДвоичныеДанныеФайлаЗИП = Base64Значение(ЧистыйТекстZIP);
Иначе
ТекстСообщения = "Критическая ошибка: Внутри сообщения не найдена сигнатура ZIP-архива. Сертификат: "+Строка(ИдентификаторСертификатаДешифровки)+
". В файле нет заголовка zip архива: UEsDBBQAAAA";
Отказ = Истина;
Возврат АдресВХ_Дешиф;
КонецЕсли;
Иначе
//Варитант универсальный...
// 1. Получаем чистые двоичные данные расшифрованного файла
ДвоичныеДанныеБинарник = ПолучитьДвоичныеДанныеФайлаИзPEM(РасшифрованныеДанные);
// 2. Превращаем весь бинарник в Base64-строку в памяти для быстрого поиска стыка
ТекстBase64 = Base64Строка(ДвоичныеДанныеБинарник);
ТекстBase64 = СтрЗаменить(ТекстBase64, Символы.ПС, "");
ТекстBase64 = СтрЗаменить(ТекстBase64, Символы.ВК, "");
// 3. Ищем универсальный стык заголовка КриптоПро (JIAE)
// или сигнатуру ZIP-архива (UEsDBB), если файлы всегда ZIP
ПозицияВТексте = СтрНайти(ТекстBase64, "JIAE");
Если ПозицияВТексте = 0 Тогда
// Если JIAE не найден, ищем явный заголовок ZIP
ПозицияВТексте = СтрНайти(ТекстBase64, "UEsDBB");
КонецЕсли;
Если ПозицияВТексте > 0 Тогда
// Вырезаем из Base64-строки ВСЁ, что идет ПОСЛЕ заголовка (чистый файл)
НашлиZIP = СтрНайти(ТекстBase64, "UEsDBB");
Если НашлиZIP > 0 Тогда
// Если искали ZIP — встаем ровно на начало ZIP
ПозицияНачалаДанных = СтрНайти(ТекстBase64, "UEsDBB");
Иначе
// Если нашли JIAE — отступаем метаданные длины Контура (обычно 8 символов Base64)
ПозицияНачалаДанных = ПозицияВТексте + 8;
КонецЕсли;
ЧистыйТекстBase64 = Сред(ТекстBase64, ПозицияНачалаДанных);
// 4. Декодируем чистый остаток обратно в ДвоичныеДанные.
// 1С сама сформирует правильный файл БЕЗ использования потоков и Перейти()
ДвоичныеДанныеФайлаЗИП = Base64Значение(ЧистыйТекстBase64);
Иначе
// Если маркеры вообще не найдены — отдаем как есть или пишем в лог
ДвоичныеДанныеФайлаЗИП = ДвоичныеДанныеБинарник;
КонецЕсли;
КонецЕсли;
Если ЭтоДвоичныеДанные = Истина Тогда
АдресВХ_Дешиф = ДвоичныеДанныеФайлаЗИП;
Иначе
АдресВХ_Дешиф = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайлаЗИП, УИДФормы);
КонецЕсли;
Иначе
//Просто, дешифрум...
РасшифрованныеДанные = Неопределено;
Если УказанСертификат = Истина Тогда
Хран = МенеджерКриптографии.получитьХранилищеСертификатов();
Сертификаты = Хран.ПолучитьВсе();
Для каждого тСерт из Сертификаты Цикл
Если СтрЗаменить(Строка(тСерт.СерийныйНомер)," ","") = ИдентификаторСертификатаДешифровки Тогда
РасшифрованныеДанные = МенеджерКриптографии.Расшифровать(ДвоичныеДанныеФайла,тСерт);
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
РасшифрованныеДанные = МенеджерКриптографии.Расшифровать(ДвоичныеДанныеФайла);
КонецЕсли;
Если РасшифрованныеДанные <> Неопределено Тогда
Если ЭтоДвоичныеДанные = Истина Тогда
АдресВХ_Дешиф = РасшифрованныеДанные;
Иначе
АдресВХ_Дешиф = ПоместитьВоВременноеХранилище(РасшифрованныеДанные, УИДФормы);
КонецЕсли;
Иначе
ТекстСообщения = "Не удалось дешифровать данные сертификатом: "+Строка(ИдентификаторСертификатаДешифровки);
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Исключение
ИнфОбОшибке = ИнформацияОбОшибке();
Описание_Кратко = КраткоеПредставлениеОшибки(ИнфОбОшибке);
Описание_Подроб = ПодробноеПредставлениеОшибки(ИнфОбОшибке);
ТекстСообщения = "Ошибка дешифровки данных: "+Описание_Кратко+"
|Подробно: "+Описание_Подроб;
Отказ = Истина;
КонецПопытки;
Возврат АдресВХ_Дешиф;
КонецФункции
Функция ДанныеКриптопровайдера() Экспорт
Криптопровайдер = Новый Структура();
Криптопровайдер.Вставить("Наименование", "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider");
Криптопровайдер.Вставить("ТипМодуляКриптографии", 80);
Возврат Криптопровайдер;
КонецФункции
Функция ПолучитьМенеджерКриптографии() Экспорт
Криптопровайдер = ДанныеКриптопровайдера();
МенеджерКриптографии = Новый МенеджерКриптографии(Криптопровайдер.Наименование,"",Криптопровайдер.ТипМодуляКриптографии);
Возврат МенеджерКриптографии;
КонецФункции
Функция ПолучитьДвоичныеДанныеФайлаИзPEM(ДвоичныеДанныеФайла_ПЕМ)
ДвоичныеДанныеФайла = Неопределено;
ПотокЧтения = ДвоичныеДанныеФайла_ПЕМ.ОткрытьПотокДляЧтения();
// 2. Читаем текстовый PEM-файл и переводим в двоичные данные
ТекстPEM = Новый ТекстовыйДокумент;
ТекстPEM.Прочитать(ПотокЧтения, КодировкаТекста.UTF8, Символы.ПС);
СтрокаPEM = ТекстPEM.ПолучитьТекст();
// Если внутри PEM есть заголовки (---BEGIN...---), очищаем их для Base64
СтрокаBase64 = СтрокаPEM;
СтрокаBase64 = СтрЗаменить(СтрокаBase64, "-----BEGIN CMS-----", "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, "-----END CMS-----", "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ПС, "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ВК, "");
ДвоичныеДанныеФайла = Base64Значение(СтрокаBase64);
Возврат ДвоичныеДанныеФайла;
КонецФункции
Функция ПолучитьПустуюСтруктуруНастройкиДешифровки()
ПараметрыСтруктуры = "ИдентификаторСертификатаДешифровки,ПарольСертификатаДешифровки,";
стрНастройки = Новый Структура(ПараметрыСтруктуры);
Возврат стрНастройки;
КонецФункции
Проверено на следующих конфигурациях и релизах:
- Бухгалтерия предприятия КОРП, редакция 3.0, релизы 3.0.199.13
Вступайте в нашу телеграмм-группу Инфостарт