//infostart.ru/
http://smbsec.ru/1cpredpriyatie/primer-assimetrichnogo-shifrovaniyarsa-1spredpriyatie-8.html
И так приступим…. Вся реализация будет описана на чистой конфигурации.
Первоначально научим 1С работать с пользователями.
Для этого нам понадобится:
- «Справочник.Пользователи»
(Код, Наименование (100), ПолноеНаименование - Строка 150,ИдентификаторПользователяИБ - Уникальный идентификатор)
Параметр сеанса - «ТекущийПользователь» (Справочник ссылка пользователи)
После добавления данных объектов конфигурации, создадим
общий модуль - «Работа с пользователями».
Добавим в него следующий код со вспомогательными процедурами и функциями.
//*********************************************************************************
Процедура ОпределитьТекущегоПользователя () Экспорт Если ПользователиИнформационнойБазы.ПолучитьПользователей().Количество()=0 Тогда ТекстСообщенияОбОшибке = "Пользователи информационной базы не определены!"; ВызватьИсключение ТекстСообщенияОбОшибке; Иначе ТекущийПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь(); ИдентификаторПользователяИБ = ТекущийПользовательИБ.УникальныйИдентификатор; ТекущийПользователь = Справочники.Пользователи.НайтиПоРеквизиту( "ИдентификаторПользователяИБ",ИдентификаторПользователяИБ); Если ТекущийПользователь.Пустая() Тогда НовыйПользователь = Справочники.Пользователи.СоздатьЭлемент(); НовыйПользователь.ИдентификаторПользователяИБ = ИдентификаторПользователяИБ; НовыйПользователь.Наименование = ТекущийПользовательИБ.Имя; НовыйПользователь.ПолноеНаименование = ТекущийПользовательИБ.ПолноеИмя; НовыйПользователь.Записать(); ТекущийПользователь = НовыйПользователь.Ссылка; КонецЕсли; ПараметрыСеанса.ТекущийПользователь = ТекущийПользователь; КонецЕсли; КонецПроцедуры //********************************************************************************* //********************************************************************************* Функция ТекущийПользователь () Экспорт Возврат ПараметрыСеанса.ТекущийПользователь; КонецФункции //********************************************************************************* //********************************************************************************* Функция ПолучитьПользователейИБ (ТолькоИдентификаторы) Экспорт Если ТолькоИдентификаторы = 1 Тогда Массив = новый Массив; Массив = ПользователиИнформационнойБазы.ПолучитьПользователей(); МассивИдентификаторв = Новый Массив; Для Каждого ЭлементМассива Из Массив Цикл МассивИдентификаторв.Добавить(ЭлементМассива.УникальныйИдентификатор); КонецЦикла; Возврат МассивИдентификаторв; Иначе Возврат ПользователиИнформационнойБазы.ПолучитьПользователей(); КонецЕсли; КонецФункции //********************************************************************************* //********************************************************************************* Функция ВернутьПользователйИзСправочника () Экспорт Массив = Новый Массив; Массив = ПолучитьПользователейИБ (1); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Пользователи.Ссылка, | Пользователи.ИдентификаторПользователяИБ |ИЗ | Справочник.Пользователи КАК Пользователи |ГДЕ | Пользователи.ИдентификаторПользователяИБ В(&Пользователи) | |УПОРЯДОЧИТЬ ПО | Пользователи.Наименование"; Запрос.УстановитьПараметр("Пользователи",Массив); Выборка = Запрос.Выполнить().Выбрать(); МассивПользователейИзСпр = Новый Массив; Пока Выборка.Следующий() Цикл Стр = Новый Структура ("Пользователь, УИД"); Стр.Вставить("Пользователь",Выборка.Ссылка); Стр.Вставить("УИД",Выборка.ИдентификаторПользователяИБ); МассивПользователейИзСпр.Добавить(Стр); КонецЦикла; Возврат МассивПользователейИзСпр; КонецФункции //********************************************************************************* //********************************************************************************* Функция ВернутьСтатусПользователя(УИДПользователяИБ) Экспорт Массив = Новый Массив; Для Каждого Элемент ИЗ ПолучитьСоединенияИнформационнойБазы() Цикл Массив.Добавить(Элемент.Пользователь.УникальныйИдентификатор); КонецЦикла; Если Массив.Найти(УИДПользователяИБ)<> Неопределено Тогда Возврат 1 Иначе Возврат 2 КонецЕсли; КонецФункции //*********************************************************************************
Создадим регистр сведений для сообщений
«Отправитель, Адресат» - СправочникСсылка.Пользователи
«Текст» - Строка
«Прочтено» - Булево
Так же создадим две строковые константы для хранения ключей шифрования:
Обе константы строковые неограниченно длинны.
Создадим еще один общий модуль для работы с RSAшифрованием.
Код модуля
//********************************************************************************************
//http://smbsec.ru/1cpredpriyatie/primer-assimetrichnogo-shifrovaniyarsa-1spredpriyatie-8.html
//Внимание! Приведенная информация распространяется исключительно в ознакомительных целях.
//Перед использованием данных материалов рекомендуется ознакомиться с ФЗ Российской Федерации
//от 4 мая 2011 г. N 99-ФЗ "О лицензировании отдельных видов деятельности".
//Обработка является примером работы с RSA из 1С:Предприятие
//и выполняет для примера шифрование и расшифрование текста.
//********************************************************************************************
Функция СтрокаВДвоичныйВид(ВходнаяСтрока) Экспорт
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Open();
Поток.Type = 2;
Поток.Charset = "utf-8";
Поток.WriteText(ВходнаяСтрока);
Поток.Position = 0;
Поток.Type = 1;
ДвоичныеДанные = Поток.Read(-1);
Поток.Close();
Поток = Неопределено;
Возврат ДвоичныеДанные;
КонецФункции
Функция ДвоичныеДанныеВстроку(ДвоичныеДанные) Экспорт
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Open();
Поток.Type = 1;
Поток.Write(ДвоичныеДанные);
Поток.Position = 0;
Поток.Type = 2;
Поток.Charset = "utf-8";
ВыхСтр = Поток.ReadText(-1);
Поток.Close();
Поток = Неопределено;
Возврат ВыхСтр;
КонецФункции
Функция ДвоичныеДанныеВBase64(bin) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Open();
Поток.Type = 1;
Поток.Write(bin);
Поток.SaveToFile(ИмяВременногоФайла, 1);
Поток.Close();
Поток = Неопределено;
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
УдалитьФайлы(ИмяВременногоФайла);
Возврат Base64Строка(ДвоичныеДанные);
КонецФункции
Функция Base64ВДвоичныеДанные(ВхСтрока) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
ДвоичныеДанные = Base64Значение(ВхСтрока);
ДвоичныеДанные.Записать(ИмяВременногоФайла);
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Open();
Поток.Type = 1;
Поток.LoadFromFile(ИмяВременногоФайла);
ДвоичныеДанные = Поток.Read(-1);
Поток.Close();
Поток = Неопределено;
УдалитьФайлы(ИмяВременногоФайла);
Возврат ДвоичныеДанные;
КонецФункции
Функция Зашифровать(СтрокаДляШифрования) Экспорт
ОбъектШифрования = Новый COMОбъект("System.Security.Cryptography.RSACryptoServiceProvider");
//Инициализация объект RSA, используя данные ключа из строки XML.
//http://msdn.microsoft.com/ru-ru/library/system.security.cryptography.rsa.fromxmlstring.aspx
ОбъектШифрования.FromXmlString(Константы.RSA_ПубличныйКлюч.Получить());
//преобразование строки для шифрования в двоичный вид
ИсхТекстДвоичн = СтрокаВДвоичныйВид(СтрокаДляШифрования);
//шифруем
ЗашифрованныйТекстДвоичн = ОбъектШифрования.Encrypt(ИсхТекстДвоичн, False);
//преобразование зашифрованных данных в Base64
ЗашифрованныйТекстСтр = ДвоичныеДанныеВBase64(ЗашифрованныйТекстДвоичн);
Возврат ЗашифрованныйТекстСтр;
КонецФункции
Функция Расшифровать(ЗашифрованнаяСтрока) Экспорт
ОбъектШифрования = Новый COMОбъект("System.Security.Cryptography.RSACryptoServiceProvider");
ОбъектШифрования.FromXmlString(Константы.RSA_ПубличныйИПриватныйКлюч.Получить());
ЗашифрованныйТекстДвоичн2 = Base64ВДвоичныеДанные(ЗашифрованнаяСтрока);
РасшифрованныйТекстДвоичн = ОбъектШифрования.Decrypt(ЗашифрованныйТекстДвоичн2, False);
//преобразование расшифрованных данных в строку
РасшифрованныйТекстСтр = ДвоичныеДанныеВстроку(РасшифрованныйТекстДвоичн);
Возврат РасшифрованныйТекстСтр;
ОбъектШифрования = Неопределено;
КонецФункции
Процедура ПроверитьRSAКлючи()Экспорт
//генерируем новый приватный и публичный ключи
//в рабочей версии ключи требуется раздать пользователям и хранить
Если (Константы.RSA_ПубличныйИПриватныйКлюч.Получить()="") И (Константы.RSA_ПубличныйКлюч.Получить()="") Тогда
RSA_Шифрование.RSAСоздатьКлючи("","");
КонецЕсли;
КонецПроцедуры
Процедура RSAСоздатьКлючи(КлючШифрования, КлючШифрованияИРасшифрования) Экспорт
//http://msdn.microsoft.com/ru-ru/library/system.security.cryptography.rsa.toxmlstring.aspx
ОбъектКриптографии = Новый COMОбъект("System.Security.Cryptography.RSACryptoServiceProvider");
КлючШифрования = ОбъектКриптографии.ToXmlString(False);
КлючШифрованияИРасшифрования = ОбъектКриптографии.ToXmlString(True);
Константы.RSA_ПубличныйИПриватныйКлюч.Установить(КлючШифрованияИРасшифрования);
Константы.RSA_ПубличныйКлюч.Установить(КлючШифрования);
ОбъектКриптографии = Неопределено;
КонецПроцедуры
На этом подготовительная часть закончилась. Переходим к созданию обработки по отправки и приему сообщений.
Модуль формы
//*********************************************************************************
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Обновить ();
RSA_Шифрование.ПроверитьRSAКлючи();
ПодключитьОбработчикОжидания ("Обновить",10);
КонецПроцедуры
//*********************************************************************************
//*********************************************************************************
&НаКлиенте
Процедура Обновить ()
Тз.Очистить();
Массив = Новый Массив;
Массив = РаботаСПользователями.ВернутьПользователйИзСправочника();
МассивСообщений = Новый Массив;
МассивСообщений = ВернутьНепрочитанныеСообщения (РаботаСПользователями.ТекущийПользователь());
Для Каждого ЭлементМассива ИЗ Массив Цикл
Если ЭлементМассива.Пользователь = РаботаСПользователями.ТекущийПользователь() Тогда
Продолжить
КонецЕсли;
СтрТЗ = ТЗ.Добавить();
СтрТз.Пользователь = ЭлементМассива.Пользователь;
Статус = РаботаСПользователями.ВернутьСтатусПользователя(ЭлементМассива.УИД);
Если Статус = 1 Тогда
СтрТЗ.Статус = "OnLine";
Иначе
СтрТЗ.Статус = "OffLine";
КонецЕсли;
Для Каждого Сообщение ИЗ МассивСообщений Цикл
Если Сообщение.Отправитель = ЭлементМассива.Пользователь Тогда
СтрТз.Сообщения = Сообщение.Количество;
КонецЕсли;
КонецЦикла
КонецЦикла;
ТЗ.Сортировать("Статус Убыв, Пользователь Возр");
КонецПроцедуры
//*********************************************************************************
//*********************************************************************************
&НаСервере
Функция ВернутьНепрочитанныеСообщения (Получатель)
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Сообщения.Период) КАК Количество,
| Сообщения.Отправитель
|ИЗ
| РегистрСведений.Сообщения КАК Сообщения
|ГДЕ
| Сообщения.Адресат = &Адресат
| И Сообщения.Прочтено = ЛОЖЬ
|
|СГРУППИРОВАТЬ ПО
| Сообщения.Отправитель" ;
Запрос.УстановитьПараметр("Адресат",Получатель);
Выборка = Запрос.Выполнить().Выбрать();
МассивСообщений = Новый Массив;
Пока Выборка.Следующий() Цикл
Ст = Новый Структура ("Отправитель,Количество");
Ст.Вставить("Отправитель",Выборка.Отправитель);
Ст.Вставить("Количество",Выборка.Количество);
МассивСообщений.Добавить(Ст);
КонецЦикла;
Возврат МассивСообщений;
КонецФункции
//*********************************************************************************
//*********************************************************************************
&НаКлиенте
Процедура ТЗВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Вставить содержимое обработчика.
СтандартнаяОбработка = Ложь;
Адресат = Элементы.ТЗ.ТекущиеДанные.Пользователь;
П = Новый Структура ("Адресат",Адресат);
ФормаСообщений = ОткрытьФормуМодально ("Обработка.Чат.Форма.ФормаОтправкиСообщения",П);
КонецПроцедуры
На данной форме поле сообщения - это поле HTMLдокумента, для того чтобы раскрасить наш чат.
Модуль формы:
//*********************************************************************************
&НаКлиенте
Процедура Ответить(Команда)
// Вставить содержимое обработчика.
Если
ПроверитьЗаполнение()Тогда
ТекПериод = ТекущаяДата ();
ТекАдресат = Адресат;
ТекОтправитель = РаботаСПользователями.ТекущийПользователь();
ТекТекст = Ответ;
ТекСтатус = Ложь;
Д = Новый Структура ("Период,Адресат,Отправитель,Текст,Прочтено",ТекПериод,ТекАдресат,ТекОтправитель,ТекТекст,ТекСтатус);
ЗаписатьОтвет (Д);
Закрыть();
КонецЕсли
КонецПроцедуры
//*********************************************************************************
//*********************************************************************************
&НаСервере
Процедура ЗаписатьОтвет (ДанныеДляЗаполнения)
МенеджерЗаписей = РегистрыСведений.Сообщения.СоздатьМенеджерЗаписи();
МенеджерЗаписей.Период = ДанныеДляЗаполнения.Период;
МенеджерЗаписей.Адресат = ДанныеДляЗаполнения.Адресат;
МенеджерЗаписей.Отправитель = ДанныеДляЗаполнения.Отправитель;
МенеджерЗаписей.Текст = RSA_Шифрование.Зашифровать(ДанныеДляЗаполнения.Текст);
МенеджерЗаписей.Прочтено = Ложь;
МенеджерЗаписей.Записать();
КонецПроцедуры
//*********************************************************************************
//*********************************************************************************
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//Для того чтобы получить логическую цепочку сообщений
//Заполним массив отправитель адресат
Адресат = Параметры.Адресат;
Массив = Новый Массив;
Массив.Добавить(Адресат);
Массив.Добавить(РаботаСпользователями.ТекущийПользователь());
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 10
| Сообщения.Текст,
| Сообщения.Период КАК Период,
| Сообщения.Отправитель,
| Сообщения.Адресат
|ИЗ
| РегистрСведений.Сообщения КАК Сообщения
|ГДЕ
| Сообщения.Отправитель В (&Отправитель)
| И Сообщения.Адресат В (&Адресат)
|
|УПОРЯДОЧИТЬ ПО
| Период Возр";
Запрос.УстановитьПараметр("Отправитель",Массив);
Запрос.УстановитьПараметр("Адресат",Массив);
Выборка = Запрос.Выполнить().Выбрать();
Текст = Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку("<!DOCTYPE html> <html>");
Пока Выборка.Следующий() Цикл
МенеджерЗаписи = РегистрыСведений.Сообщения.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерЗаписи,Выборка);
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Прочтено = Истина;
МенеджерЗаписи.Записать();
КонецЕсли;
Если Выборка.Отправитель = РаботаСПользователями.ТекущийПользователь() Тогда
Стр = "<font size=""3"" color=""red"" face=""Calibri"">""" +Строка(Выборка.Отправитель)+" "+Строка(Выборка.Период)+"</font>" + "<br>";
Текст.ДобавитьСтроку(Стр);
Стр = "<font size=""3"" color=""Black"" face=""Calibri"">""" +RSA_Шифрование.Расшифровать(Строка(Выборка.Текст))+"</font>" + "<br>";
Текст.ДобавитьСтроку(Стр);
Иначе
Стр = "<font size=""3"" color=""Blue"" face=""Calibri"">""" +Строка(Выборка.Отправитель)+" "+Строка(Выборка.Период)+"</font>" + "<br>";
Текст.ДобавитьСтроку(Стр);
Стр = "<font size=""3"" color=""Black"" face=""Calibri"">""" +RSA_Шифрование.Расшифровать(Строка(Выборка.Текст))+"</font>" + "<br>";
Текст.ДобавитьСтроку(Стр);
КонецЕсли;
КонецЦикла;
Текст.ДобавитьСтроку("</html>");
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("html");
Текст.Записать(ИмяВременногоФайла);
Сообщения = ИмяВременногоФайла;
КонецПроцедуры
//*********************************************************************************
Получается примерно следующее:
Регистр с сообщениями выглядит:
Как видно из скринов, сообщения зашифрованы нашими RSA Ключами.