Русский
Русский
English
Статистика
Реклама

Криптопро

Как реализовать интеграцию с ЕСИА на Java без лишних проблем

04.12.2020 10:17:32 | Автор: admin
Долгое время основным способом идентификации граждан был обычный паспорт. Ситуация изменилась, когда в 2011 году по заказу Минкомсвязи была внедрена Единая система идентификации и аутентификации (ЕСИА), она позволила распознавать личность человека и получать о ней данные в режиме онлайн.

Благодаря внедрению ЕСИА государственные и коммерческие организации, разработчики и владельцы онлайн-сервисов получили возможность ускорить и сделать более безопасными операции, связанные с вводом и верификацией пользовательских данных. Русфинанс Банк также решил использовать потенциал системы и при доработке сервиса по оформлению кредита онлайн (банк специализируется на автокредитовании) реализовал интеграцию с платформой.

Сделать это оказалось не так просто. Нужно было выполнить ряд требований и процедур, решить технические трудности.

В данной статье мы постараемся рассказать про основные моменты и методические указания, которые важно знать тем, кто хочет самостоятельно реализовать интеграцию с ЕСИА, а также приведем фрагменты кода на языке Java, которые помогут преодолеть трудности при разработке (часть реализации опущена, но общая последовательность действий ясна).

Надеемся, наш опыт поможет Java-разработчикам (и не только) сэкономить массу времени при разработке и ознакомлении с методическими рекомендациями Минкомсвязи.



Зачем нам нужна интеграция с ЕСИА?


В связи с пандемией коронавируса количество офлайн сделок во многих направлениях кредитования начало сокращаться. Клиенты стали уходить в онлайн, и для нас было жизненно важно укрепить своё онлайн-присутствие на рынке автокредитования. В процессе доработки сервиса Автокредит (на Хабре уже есть статья про его разработку) мы решили сделать интерфейс заведения кредитных заявок на сайте банка максимально удобным и простым. Интеграция с ЕСИА стала ключевым моментом в решении этой задачи, поскольку позволила автоматически получить персональные данные клиента.



Для клиента такое решение также оказалось удобным, поскольку дало возможность использовать единый логин и пароль для регистрации и входа в сервис онлайн-одобрения заявок на приобретение автомобиля в кредит.

Кроме того, интеграция с ЕСИА позволила Русфинанс Банку:

  • сократить время заполнения онлайн-анкет;
  • уменьшить количество отказов пользователей при попытке заполнить большое количество полей вручную;
  • обеспечить поток более качественных, верифицированных клиентов.

Несмотря на то, что мы рассказываем об опыте нашего банка, информация может быть полезна не только финансовым организациям. Правительство рекомендует использовать платформу ЕСИА и для других видов онлайн-услуг (подробнее тут).

Что делать и как?


Сначала нам показалось, что в интеграции с ЕСИА нет ничего особенного с технической точки зрения стандартная задача, связанная с получением данных посредством REST API. Однако, при ближайшем рассмотрении стало понятно, что не всё так просто. Например, выяснилось, что у нас нет представления о том, как работать с сертификатами, необходимыми для подписи нескольких параметров. Пришлось тратить время и разбираться. Но обо всем по порядку.

Для начала важно было наметить план действий. Наш план включал следующие основные шаги:

  1. зарегистрироваться на технологическом портале ЕСИА;
  2. подать заявки на использование программных интерфейсов ЕСИА в тестовой и промышленной среде;
  3. самостоятельно разработать механизм взаимодействия с ЕСИА (в соответствии с действующим документом Методические рекомендации по использованию ЕСИА);
  4. протестировать работу механизма в тестовой и промышленной среде ЕСИА.

Обычно мы разрабатываем наши проекты на Java. Поэтому для программной реализации выбрали:

  • IntelliJ IDEA;
  • КриптоПро JCP (или КриптоПро Java CSP);
  • Java 8;
  • Apache HttpClient;
  • Lombok;
  • FasterXML/Jackson.

Получение URL для переадресации


Первый шаг это получение авторизационного кода. В нашем случае это делает отдельный сервис с переадресацией на страницу авторизации портала Госуслуг (расскажем об этом немного подробнее).

Сначала мы инициализируем переменные ESIA_AUTH_URL (адрес ЕСИА) и API_URL (адрес, на который происходит редирект в случае успешной авторизации). После этого создаем объект EsiaRequestParams, который содержит в своих полях параметры запроса к ЕСИА, и сформируем ссылку esiaAuthUri.

public Response loginByEsia() throws Exception {  final String ESIA_AUTH_URL = dao.getEsiaAuthUrl(); // Адрес ЕСИА  final String API_URL = dao.getApiUrl(); // Адрес, на который произойдет редирект с случае успешной авторизации  EsiaRequestParams requestDto = new EsiaRequestParams(API_URL);  URI esiaAuthUri = new URIBuilder(ESIA_AUTH_URL)          .addParameters(Arrays.asList(            new BasicNameValuePair(RequestEnum.CLIENT_ID.getParam(), requestDto.getClientId()),            new BasicNameValuePair(RequestEnum.SCOPE.getParam(), requestDto.getScope()),            new BasicNameValuePair(RequestEnum.RESPONSE_TYPE.getParam(), requestDto.getResponseType()),            new BasicNameValuePair(RequestEnum.STATE.getParam(), requestDto.getState()),            new BasicNameValuePair(RequestEnum.TIMESTAMP.getParam(), requestDto.getTimestamp()),            new BasicNameValuePair(RequestEnum.ACCESS_TYPE.getParam(), requestDto.getAccessType()),            new BasicNameValuePair(RequestEnum.REDIRECT_URI.getParam(), requestDto.getRedirectUri()),            new BasicNameValuePair(RequestEnum.CLIENT_SECRET.getParam(), requestDto.getClientSecret())          ))          .build();  return Response.temporaryRedirect(esiaAuthUri).build();}

Для наглядности покажем, как может выглядеть класс EsiaRequestParams:

public class EsiaRequestParams {  String clientId;  String scope;  String responseType;  String state;  String timestamp;  String accessType;  String redirectUri;  String clientSecret;  String code;  String error;  String grantType;  String tokenType;  public EsiaRequestParams(String apiUrl) throws Exception {    this.clientId = CLIENT_ID;    this.scope = Arrays.stream(ScopeEnum.values())            .map(ScopeEnum::getName)            .collect(Collectors.joining(" "));    responseType = RESPONSE_TYPE;    state = EsiaUtil.getState();    timestamp = EsiaUtil.getUrlTimestamp();    accessType = ACCESS_TYPE;    redirectUri = apiUrl + RESOURCE_URL + "/" + AUTH_REQUEST_ESIA;    clientSecret = EsiaUtil.generateClientSecret(String.join("", scope, timestamp, clientId, state));    grantType = GRANT_TYPE;    tokenType = TOKEN_TYPE;  }}

После этого нужно перенаправить пользователя на сервис аутентификации ЕСИА. Пользователь вводит свой логин-пароль, подтверждает доступ к данным для нашей системы. Далее ЕСИА отправляет онлайн-сервису ответ, в котором содержится код авторизации. Этот код понадобится для дальнейших запросов в ЕСИА.

Каждый запрос к ЕСИА имеет параметр client_secret, который представляет собой откреплённую электронную подпись в формате PKCS7 (Public Key Cryptography Standard). В нашем случае для подписи используется сертификат, который был получен удостоверяющим центром перед началом работ по интеграции с ЕСИА. Как работать с хранилищем ключей хорошо описано в этом цикле статей.

Для примера покажем, как выглядит хранилище ключей, предоставляемое компанией КриптоПро:



Вызов приватного и публичного ключей в этом случае будет выглядеть так:

KeyStore keyStore = KeyStore.getInstance("HDImageStore"); // Создание экземпляра хранилищаkeyStore.load(null, null);PrivateKey privateKey = (PrivateKey) keyStore.getKey(esiaKeyStoreParams.getName(), esiaKeyStoreParams.getValue().toCharArray()); // Получение приватного ключаX509Certificate certificate = (X509Certificate) keyStore.getCertificate(esiaKeyStoreParams.getName()); // Получение сертификата, он же  открытый ключ.

Где JCP.HD_STORE_NAME имя хранилища в КриптоПро, esiaKeyStoreParams.getName() имя контейнера и esiaKeyStoreParams.getValue().toCharArray() пароль контейнера.
В нашем случае не нужно загружать данные в хранилище методом load(), так как ключи уже будут там при указании имени этого хранилища.

Здесь важно помнить, что получения подписи в виде

final Signature signature = Signature.getInstance(SIGN_ALGORITHM, PROVIDER_NAME);signature.initSign(privateKey);signature.update(data);final byte[] sign = signature.sign();

нам недостаточно, так как ЕСИА требует откреплённую подпись формата PKCS7. Поэтому следует создать подпись формата PKCS7.

Пример нашего метода, возвращающего откреплённую подпись, выглядит следующим образом:

public String generateClientSecret(String rawClientSecret) throws Exception {    if (this.localCertificate == null || this.esiaCertificate == null) throw new RuntimeException("Signature creation is unavailable");    return CMS.cmsSign(rawClientSecret.getBytes(), localPrivateKey, localCertificate, true);  }

Здесь мы проверяем наличие нашего открытого ключа и открытого ключа ЕСИА. Так как метод cmsSign() может содержать конфиденциальную информацию, мы не будем его раскрывать.

Укажем лишь некоторые детали:

  • rawClientSecret.getBytes() байтовый массив scope, timestamp, clientId и state;
  • localPrivateKey приватный ключ из контейнера;
  • localCertificate публичный ключ из контейнера;
  • true булево значение параметра подписи открепленная или нет.

Пример создания подписи можно найти в java-библиотеке КриптоПро, там стандарт PKCS7 называется CMS. А также в руководстве программиста, которое лежит вместе с исходниками скаченной версии КриптоПро.

Получение токена


Следующий шаг получение маркера доступа (он же токен) в обмен на авторизационный код, который был получен в качестве параметра при успешной авторизации пользователя на портале Госуслуг.

Для получения каких-либо данных в ЕСИА нужно получить токен доступа. Для этого формируем запрос в ЕСИА. Основные поля запроса тут формируются аналогичным образом, в коде получается примерно следующее:

URI getTokenUri = new URIBuilder(ESIA_TOKEN_API_URL)        .addParameters(Arrays.asList(          new BasicNameValuePair(RequestEnum.CLIENT_ID.getParam(), requestDto.getClientId()),          new BasicNameValuePair(RequestEnum.CODE.getParam(), code),          new BasicNameValuePair(RequestEnum.GRANT_TYPE.getParam(), requestDto.getGrantType()),          new BasicNameValuePair(RequestEnum.CLIENT_SECRET.getParam(), requestDto.getClientSecret()),          new BasicNameValuePair(RequestEnum.STATE.getParam(), requestDto.getState()),          new BasicNameValuePair(RequestEnum.REDIRECT_URI.getParam(), requestDto.getRedirectUri()),          new BasicNameValuePair(RequestEnum.SCOPE.getParam(), requestDto.getScope()),          new BasicNameValuePair(RequestEnum.TIMESTAMP.getParam(), requestDto.getTimestamp()),          new BasicNameValuePair(RequestEnum.TOKEN_TYPE.getParam(), requestDto.getTokenType())        ))        .build();HttpUriRequest getTokenPostRequest = RequestBuilder.post()        .setUri(getTokenUri)        .setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")        .build();

Получив ответ, распарсим его и получим токен:

try (CloseableHttpResponse response = httpClient.execute(getTokenPostRequest)) {  HttpEntity tokenEntity = response.getEntity();  String tokenEntityString = EntityUtils.toString(tokenEntity);  tokenResponseDto = extractEsiaGetResponseTokenDto(tokenEntityString);}

Токен представляет собой строку, состоящую из трёх частей и разделённых точками: HEADER.PAYLOAD.SIGNATURE, где:

  • HEADER это заголовок, имеющий в себе свойства токена, в том числе алгоритм подписи;
  • PAYLOAD это информация о токене и субъекте, которую запрашиваем у Госуслуг;
  • Signature это подпись HEADER.PAYLOAD.

Валидация токена


Для того, чтобы убедиться, что мы получили ответ именно от Госуслуг, необходимо провалидировать токен, указав путь к сертификату (открытому ключу), который можно скачать с сайта Госуслуг. Передав в метод isEsiaSignatureValid() полученную строку (data) и подпись (dataSignature), можно получить результат валидации в виде булева значения.

public static boolean isEsiaSignatureValid(String data, String dataSignature) throws Exception {  InputStream inputStream = EsiaUtil.class.getClassLoader().getResourceAsStream(CERTIFICATE); // Публичный ключ ЕСИА, представленный как поток  CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); // Создание объекта фабрики с указанием стандарта открытого ключа X.509  X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(inputStream);  Signature signature = Signature.getInstance(certificate.getSigAlgName(), new JCP()); // Создание экземпляра класса Signature с указанием алгоритма подписи и провайдера JCP от КриптоПро  signature.initVerify(certificate.getPublicKey()); // Инициализация открытого ключа для верификации  signature.update(data.getBytes()); // Загрузка байтового массива строки, которую нужно верифицировать   return signature.verify(Base64.getUrlDecoder().decode(dataSignature));}

В соответствии с методическими указаниями необходимо проверять срок действия маркера. Если срок действия истек, то нужно создать новую ссылку с дополнительными параметрами и сделать запрос с помощью http-клиента:

URI refreshTokenUri = new URIBuilder(ESIA_TOKEN_API_URL)        .addParameters(Arrays.asList(                new BasicNameValuePair(RequestEnum.CLIENT_ID.getParam(), requestDto.getClientId()),                new BasicNameValuePair(RequestEnum.REFRESH_TOKEN.getParam(), tokenResponseDto.getRefreshToken()),                new BasicNameValuePair(RequestEnum.CODE.getParam(), code),                new BasicNameValuePair(RequestEnum.GRANT_TYPE.getParam(), EsiaConstants.REFRESH_GRANT_TYPE),                new BasicNameValuePair(RequestEnum.STATE.getParam(), requestDto.getState()),                new BasicNameValuePair(RequestEnum.SCOPE.getParam(), requestDto.getScope()),                new BasicNameValuePair(RequestEnum.TIMESTAMP.getParam(), requestDto.getTimestamp()),                new BasicNameValuePair(RequestEnum.TOKEN_TYPE.getParam(), requestDto.getTokenType()),                new BasicNameValuePair(RequestEnum.CLIENT_SECRET.getParam(), requestDto.getClientSecret()),                new BasicNameValuePair(RequestEnum.REDIRECT_URI.getParam(), requestDto.getRedirectUri())        ))        .build();

Получение данных пользователя


В нашем случае необходимо получить ФИО, дату рождения, паспортные данные и контакты.
Используем функциональный интерфейс, который поможет получать данные пользователя:

Function<String, String> esiaPersonDataFetcher = (fetchingUri) -> {  try {    URI getDataUri = new URIBuilder(fetchingUri).build();    HttpGet dataHttpGet = new HttpGet(getDataUri);       dataHttpGet.addHeader("Authorization", requestDto.getTokenType() + " " + tokenResponseDto.getAccessToken());    try (CloseableHttpResponse dataResponse = httpClient.execute(dataHttpGet)) {      HttpEntity dataEntity = dataResponse.getEntity();      return EntityUtils.toString(dataEntity);    }  } catch (Exception e) {    throw new UndeclaredThrowableException(e);  }};

Получение данных пользователя:

String personDataEntityString = esiaPersonDataFetcher.apply(ESIA_REST_API_URL + "/prns/" + esiaAccountId);

Получение контактов выглядит уже не таким очевидным, как получение данных пользователя. Для начала следует получить список ссылок на контакты:

String contactsListEntityString = esiaPersonDataFetcher.apply(ESIA_REST_API_URL + "/prns/" + esiaAccountId + "/ctts");EsiaListDto esiaListDto = objectMapper.readValue(contactsListEntityString, EsiaListDto.class);

Десериализуем этот список и получим объект esiaListDto. Поля из методички ЕСИА могут различаться, поэтому стоит проверить опытным путем.

Далее необходимо перейти по каждой ссылке из списка, чтобы получить каждый контакт пользователя. Выглядеть это будет следующим образом:

for (String contactUrl : esiaListDto.getElementUrls()) {  String contactEntityString = esiaPersonDataFetcher.apply(contactUrl);  EsiaContactDto esiaContactDto = objectMapper.readValue(contactEntityString, EsiaContactDto.class);}

С получением списка документов та же ситуация. Вначале получаем список ссылок на документы:

String documentsListEntityString = esiaPersonDataFetcher.apply(ESIA_REST_API_URL + "/prns/" + esiaAccountId + "/docs");

Затем десериализуем его:

EsiaListDto esiaDocumentsListDto = objectMapper.readValue(documentsListEntityString, EsiaListDto.class);Переходим по каждой ссылке и получаем документы:for (String documentUrl : esiaDocumentsListDto.getElementUrls()) {  String documentEntityString = esiaPersonDataFetcher.apply(documentUrl);  EsiaDocumentDto esiaDocumentDto = objectMapper.readValue(documentEntityString, EsiaDocumentDto.class);}

Что теперь делать со всеми этими данными?


Мы можем сделать парсинг данных и получать объекты с требуемыми полями. Здесь каждый разработчик может оформлять классы как ему необходимо, в соответствии с техническим заданием.

Пример получения объекта с необходимыми полями:

final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);String personDataEntityString = esiaPersonDataFetcher.apply(ESIA_REST_API_URL + "/prns/" + esiaAccountId);EsiaPersonDto esiaPersonDto = objectMapper.readValue(personDataEntityString, EsiaPersonDto.class);

Заполняем объект esiaPersonDto необходимыми данными, например, контактами:

for (String contactUrl : esiaListDto.getElementUrls()) {  String contactEntityString = esiaPersonDataFetcher.apply(contactUrl);  EsiaContactDto esiaContactDto = objectMapper.readValue(contactEntityString, EsiaContactDto.class); // Десериализация контакта  if (esiaContactDto.getType() == null) continue;  switch (esiaContactDto.getType().toUpperCase()) {    case EsiaContactDto.MBT: // Если это номер мобильного телефона, то заполним поле mobilePhone      esiaPersonDto.setMobilePhone(esiaContactDto.getValue());      break;    case EsiaContactDto.EML: // Если это адрес электронной почты, то заполним поле email      esiaPersonDto.setEmail(esiaContactDto.getValue());  }}

Класс EsiaPersonDto выглядит следующим образом:

@Data@FieldNameConstants(prefix = "")public class EsiaPersonDto {  private String firstName;  private String lastName;  private String middleName;  private String birthDate;  private String birthPlace;  private Boolean trusted;  // тип учетной записи - подтверждена (true) / не подтверждена (false)  private String status;    // статус УЗ - Registered (зарегистрирована) /Deleted (удалена)  // Назначение полей непонятно, но они есть при запросе /prns/{oid}  private List<String> stateFacts;  private String citizenship;  private Long updatedOn;  private Boolean verifying;  @JsonProperty("rIdDoc")  private Integer documentId;  private Boolean containsUpCfmCode;  @JsonProperty("eTag")  private String tag;  // ----------------------------------------  private String mobilePhone;  private String email;  @javax.validation.constraints.Pattern(regexp = "(\\d{2})\\s(\\d{2})")  private String docSerial;  @javax.validation.constraints.Pattern(regexp = "(\\d{6})")  private String docNumber;  private String docIssueDate;  @javax.validation.constraints.Pattern(regexp = "([0-9]{3})\\-([0-9]{3})")  private String docDepartmentCode;  private String docDepartment;  @javax.validation.constraints.Pattern(regexp = "\\d{14}")  @JsonProperty("snils")  private String pensionFundCertificateNumber;  @javax.validation.constraints.Pattern(regexp = "\\d{12}")  @JsonProperty("inn")  private String taxPayerNumber;  @JsonIgnore  @javax.validation.constraints.Pattern(regexp = "\\d{2}")  private String taxPayerCertificateSeries;  @JsonIgnore  @javax.validation.constraints.Pattern(regexp = "\\d{10}")  private String taxPayerCertificateNumber;}

Работа по усовершенствованию сервиса будет продолжаться, ведь ЕСИА не стоит на месте.
Подробнее..

На пути к вершине Магма и Кузнечик на Эльбрусе

17.06.2021 16:13:58 | Автор: admin

В последнее время всё чаще появляются статьи о производительности российских процессоров Эльбрус на различных задачах. Тема криптографии пока что остаётся за кадром, хотя в разное время были упоминания то о высоких возможностях Эльбруса (некий ГОСТ лучше в 9 раз на Эльбрус-4С, чем на Intel Core i7-2600), то о плохой оптимизации компилятора и, соответственно, крайне низкой скорости реализованных алгоритмов (Кузнечик в 100 раз медленнее, чем на Intel?). Предлагаю наконец разобраться, что может Эльбрус, на примере двух ГОСТ алгоритмов симметричного шифрования.

Чтобы статья не вышла слишком большой, будем считать, что читатель имеет общее представление об архитектурах процессоров, в том числе знает об Эльбрусе. Если же нет, на сайте разработчика (компании МЦСТ) есть отличное руководство по программированию и книга об архитектуре в целом. Именно с этих материалов и началось моё знакомство с Эльбрусами. Также отмечу, что в современных процессорах очень много различных механизмов и особенностей, так что в статье буду касаться только тех, которые, на мой взгляд, важны при реализации выбранных алгоритмов.

Что может предложить архитектура Эльбрус

Для выполнения арифметических операций у Эльбруса есть 6 АЛУ (арифметико-логических устройств), способных выполнять операции параллельно. Начиная с версии 5 архитектуры появилась поддержка упакованных (SIMD) инструкций над 128-битными регистрами.

Для хранения промежуточных результатов присутствует большой регистровый файл: суммарно в процедуре можно использовать более 200 (64-битных) регистров общего назначения. Для SIMD вычислений используются те же самые регистры, а не отдельные, как это часто бывает. Соответственно, с 5 версии архитектуры все регистры стали 128-битными.

Задачу симметричного шифрования можно отнести к потоковой обработке массива данных. Для таких ситуаций в Эльбрусе есть механизм асинхронной подкачки данных из памяти APB (Array Prefetch Buffer). Использование этого механизма позволяет вовремя подгружать данные из памяти, не теряя время на кэш-промахи.

Выбор реализаций

Хорошим подходом было бы взять несколько известных реализаций, оптимизировать их под Эльбрус и посмотреть на результаты. Но, с другой стороны, мы говорим о процессоре общего назначения, поэтому можно сэкономить силы и время, предположив, что лучшие результаты можно ожидать от подходов, которые являются самыми быстрыми на других архитектурах.

Правда, о производительности ГОСТ алгоритмов обычно говорят только в контексте семейства x86-64, другие архитектуры мало кого интересуют. Но это не беда: мне показалось, что при знании команд ассемблера x86-64 ознакомиться с набором целочисленных и логических инструкций Эльбруса проще, чем, скажем, с ARM-овым. То есть прослеживаются определённые параллели, особенно, в области SIMD инструкций, и даже прямые аналоги. В остальном, конечно, у них нет ничего общего.

Итак, для Магмы известна эффективная реализация режимов, допускающих параллельную обработку блоков, то есть когда несколько блоков могут шифроваться независимо друг от друга. Это, например, режимы ECB, CTR, MGM. При этом скорость конкурирует с AES, для которого на x86-64 есть аппаратная поддержка. Реализация заточена именно под параллельную обработку, в случае последовательной (режимы с зацеплением) используются другие подходы. Мне интересно добиться максимальной скорости, поэтому я ограничился только случаем параллельной обработки.

С Кузнечиком немного проще: лучшие результаты что при последовательной, что при параллельной обработке даёт одна и та же реализация её и берём.

Тестовые машины

То же самое в текстовом виде

Процессор

Версия арх-ры

Кол-во ядер

Тактовая частота

L1d

L1i

L2

L3

Эльбрус-4С

E2Kv3

4

0.75 ГГц

4 x 64 КБ

4 x 128 КБ

4 x 2 МБ

Нет

Эльбрус-1С+

E2Kv4

1

0.985 ГГц

1 x 64 КБ

1 x 128 КБ

1 x 2 МБ

Нет

Эльбрус-8С

E2Kv4

8

1.2 ГГц

8 x 64 КБ

8 x 128 КБ

8 x 512 КБ

16 МБ

Эльбрус-8СВ

E2Kv5

8

1.55 ГГц

8 x 64 КБ

8 x 128 КБ

8 x 512 КБ

16 МБ

Эльбрус-2С3

E2Kv6

2

2 ГГц

2 x 64 КБ

2 x 128 КБ

2 x 2 МБ

Нет

Эльбрус-16С

E2Kv6

16

2 ГГц

16 x 64 КБ

16 x 128 КБ

8 x 1 МБ

32 МБ

Магма

В случае x86-64 быстрая реализация Магмы опирается на использование расширений AVX и AVX2. При этом учитывается наличие в процессоре нескольких АЛУ и возможность параллельного исполнения до 3 векторных инструкций за один такт. Естественно, планирование параллельного исполнения остаётся на откуп процессора.

В случае же Эльбруса есть возможность явно распланировать параллельное исполнение. Опуская некоторые детали, можно считать, что на 3 и 4 поколении возможно исполнить 6 целочисленных векторных операций над 64-битными регистрами, а начиная с 5 поколения 4 векторных операции уже над 128-битными регистрами.

Для Эльбруса я написал собственную реализацию Магмы. Она использует те же идеи, что и исходная под x86-64, но при этом адаптирована под другой набор инструкций. Рассматривал перспективу написания на ассемблере и даже пробовал, но довольно быстро осознал, что ассемблер у Эльбруса достаточно сложный в плане программирования на нём (например, есть много нюансов по размерам задержек и зависимостям инструкций, которые тяжело учесть вручную). При этом оптимизирующий компилятор делает свою работу действительно хорошо: переставляет инструкции в рамках большого окна и при подборе опций компиляции выдаёт плотность кода, которая не отличается от теоретических оценок на количество инструкций и тактов. Так что я остановился на реализации на языке Си с использованием intrinsic функций для доступа к некоторым инструкциям процессора.

Для измерения скорости был выбран режим ECB. Обычно именно он (или даже его упрощения) используется при сравнении производительности, а скорость других режимов можно оценить на базе полученных результатов, отличия несущественны. Речь идёт о реализации базового алгоритма шифрования, поэтому накладные расходы от смены ключа также не учитываются. Объём данных для замера порядка 1 ГБ. Естественно, шифрование на одном ядре. Для многоядерной машины можно умножить результат на количество ядер и получить близкую к реальности оценку скорости. По крайней мере, во всех сравнениях я видел именно такую зависимость. Полученные результаты в таблице ниже:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

Производительность

Эльбрус-4С

116 МБ/с

137 МБ/с

5.2 такт/байт

Эльбрус-1С+

151 МБ/с

179 МБ/с

5.2 такт/байт

Эльбрус-8С

185 МБ/с

220 МБ/с

5.2 такт/байт

Эльбрус-8СВ

402 МБ/с

520 МБ/с

2.8 такт/байт

Эльбрус-2С3

669 МБ/с

670 МБ/с

2.8 такт/байт

Эльбрус-16С

671 МБ/с

672 МБ/с

2.8 такт/байт

Здесь под выровненными данными подразумевается выравнивание по границе 8 байтов для E2Kv3/E2Kv4 и 16 байтов для E2Kv5/E2Kv6. При наличии такого выравнивания (на версиях до 6) работает механизм APB и данные для шифрования эффективно подкачиваются из памяти. При этом с версии 6 APB уже не требует выравнивания данных, поэтому при любом расположении данных достигается максимальная скорость. Для невыровненных данных на предыдущих версиях архитектуры я не провёл достаточно исследований, так что значения в этом столбце таблицы можно считать нижней границей.

Для сравнения приведу результаты из статьи с описанием базовой реализации на Intel Core i3-7100 @ 3.9 ГГц. При использовании AVX 458 МБ/с, 8.1 такт/байт; AVX2 1030 МБ/с, 3.6 такт/байт. Так что по абсолютной скорости Эльбрус достаточно близок к современным процессорам Intel (это при значительной разнице в тактовой частоте!) и превосходит x86-64 с AVX в тактах более чем в 1.5 раза (для 3 и 4 поколения), а x86-64 с AVX2 в 1.3 раза (для 5 поколения).

Кузнечик

По сравнению с Магмой, структура Кузнечика является более сложной. Несмотря на то, что удалось декомпозировать нелинейное преобразование S, техники реализации, основанные на широком использовании SIMD-инструкций, пока что отстают от "классической" реализации со склеенным LS (линейным и нелинейным) преобразованием и таблицей предвычислений размером 64 КБ (упоминается в статье под именами с LS или более простое описание на Хабре).

В случае x86-64 Кузнечик эффективнее всего реализуется с использованием AVX-инструкций (удобно работать со 128-битными регистрами, так как длина блока и размер значений в таблице равны в точности 128 битам). При этом для вычислений адресов в таблице не удаётся воспользоваться эффективной адресацией Scale-Index-Base-Displacement (именование из статьи), так как в качестве Scale нужно значение 16, а максимально возможное 8. На Эльбрусе можно ожидать конкурирующих результатов за счёт большого кэша L1d (64 КБ) и наличия 4 АЛУ, обеспечивающих произвольный доступ к памяти (насколько мне известно, у абсолютного большинства процессоров x86-64 2 порта для загрузки данных).

Как и в случае с Магмой, для Кузнечика я написал отдельную реализацию на Си под Эльбрус, чтобы добиться максимальных результатов. Начиная с 5 версии архитектуры я явным образом использовал тип __v2di (см. e2kintrin.h в составе компилятора), чтобы быть уверенным, что получится использовать регистры как 128-битные.

Техника замера скорости полностью совпадает с уже описанным случаем Магмы, так что повторяться не буду. Только напомню, на всякий случай, что речь идёт о скорости на одном ядре. Почему-то у многих это вызывало вопросы и ещё чаще удивление.

Итак, в случае строго последовательной обработки данных:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

Производительность

Эльбрус-4С

52 МБ/с

69 МБ/с

10.4 такт/байт

Эльбрус-1С+

63 МБ/с

90 МБ/с

10.4 такт/байт

Эльбрус-8С

80 МБ/с

110 МБ/с

10.4 такт/байт

Эльбрус-8СВ

95 МБ/с

150 МБ/с

9.9 такт/байт

Эльбрус-2С3

170 МБ/с

171 МБ/с

11 такт/байт

Эльбрус-16С

171 МБ/с

172 МБ/с

11 такт/байт

Для сравнения результаты из статьи (лучшие из опубликованных) на Intel Core i7-6700 @ 4 ГГц 170МБ/с, 22.4 такт/байт. В отличие от Магмы, можно говорить о сопоставимой абсолютной скорости и преимуществе в тактах более чем в 2 раза.

В таблице заметен интересный момент: результаты ощутимо колеблются среди последних 3 версий Эльбруса. Такое поведение я заметил буквально недавно и начал обсуждение с коллегами из МЦСТ, так что есть надежда, что результаты удастся немного улучшить при доработке компилятора.

С параллельной обработкой ситуация намного интереснее:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

Производительность

Эльбрус-4С

78 МБ/с

83 МБ/с

8.6 такт/байт

Эльбрус-1С+

102 МБ/с

108 МБ/с

8.7 такт/байт

Эльбрус-8С

126 МБ/с

133 МБ/с

8.6 такт/байт

Эльбрус-8СВ

248 МБ/с

291 МБ/с

5.1 такт/байт

Эльбрус-2С3

453 МБ/с

454 МБ/с

4.2 такт/байт

Эльбрус-16С

454 МБ/с

455 МБ/с

4.2 такт/байт

И традиционное сравнение с Intel Core i7-6700 @ 4 ГГц: на нём достигается 360 МБ/с, 10.6 такт/байт. В отличие от случая последовательной обработки, у E2Kv3 и E2Kv4 преимущество Эльбруса не такое большое, предположительно из-за того, что реализация обработки нескольких блоков вместе обладает более высокой степенью параллельности и планировщику на x86-64 легче справиться с выявлением независимых операций. А вот появление у 5 поколения Эльбруса 128-битных регистров и загрузок из памяти позволяет ему сохранить преимущество в тактах более чем в 2 раза.

Сравнивать E2Kv6 с i7-6700 оказалось несолидно, поэтому я взял ассемблерную реализацию режима ECB и провёл собственный замер. В статье с описанием результатов на i7-6700 данные шифруются на месте, без работы с памятью, поэтому у честного режима ECB результат чуточку хуже: на самом мощном из доступных мне процессоров Intel Core i7-9700K @ 4.7 ГГц вышло 411 МБ/с, 10.9 такт/байт. Эльбрус оказался быстрее, обеспечивая преимущество в тактах в 2.5 раза.

Заключение

На основании полученных результатов я делаю вывод, что Эльбрус обладает отличными возможностями для высокопроизводительной реализации шифрования данных, несмотря на отсутствие в выпущенных версиях архитектуры какой-либо аппаратной поддержки криптографических операций.

За время изучения архитектуры Эльбруса у меня сложилось впечатление, что многие полезные инструкции исторически добавлялись для обеспечения работы двоичного транслятора, но ситуация изменилась с 5 версии: Эльбрус начал больше развиваться собственным путём. Эту положительную динамику невозможно не отметить.

С другой стороны, сложившаяся похожесть ряда инструкций упрощает разработку и оптимизацию под Эльбрус. Можно сказать, что эта статья предлагает простой способ портирования и оптимизации алгоритмов под Эльбрус: достаточно взять хорошо зарекомендовавший себя на Intel/AMD алгоритм и немного адаптировать его под Эльбрус. Я искренне верю, что в результате практически любой алгоритм должен работать по крайней мере не хуже, чем в разницу тактовых частот.

Если немного поразбираться и осторожно писать код на Си, компилятор прекрасно справляется с задачей оптимизации и не оставляет человеку шансов написать на ассемблере более эффективный код.

P.S.

Эта статья написана по мотивам моего устного доклада на конференции РусКрипто. По ссылке можно найти презентацию, которая является краткой выжимкой с основными результатами на тот момент. К моменту же написания статьи удалось улучшить некоторые результаты, а также проверить реализации на новом поколении процессоров.

Несмотря на то, что для получения описанных результатов мне удалось разобраться с Эльбрусом на основании только открытой информации и документации к компилятору, я хочу выразить благодарность сотрудникам МЦСТ, в особенности, Александру Трушу, за ответы на периодически возникавшие у меня вопросы и, конечно, за предоставление удалённого доступа к новым процессорам.

Подробнее..

Рутокен ЭЦП 2.0 3000, COVID-19, УЦ Росреестра и операции с Росреестом онлайн ver. 2.0

01.09.2020 16:17:46 | Автор: admin
Привет, хабровчане!

К написанию данной статьи меня подтолкнули сразу несколько вещей:
  1. Должок перед компанией Актив, которая любезно предоставила мне их новый крипто-токен Рутокен ЭЦП 2.0 модификации 3000. Nastya_d, тэгну вас, т.к. вы последняя, кто постил от лица компании
  2. COVID-19, который перевел работу Росреестра в режим только по предварительной записи с хронической невозможностью туда записаться
  3. Изменения в законодательстве, которые были приняты после череды прошлогодних скандалов, связанных с применением электронной подписи
  4. Обновление Росреестра по части проведения электронных сделок и подачи каких-либо иных электронных заявлений


Так что, наверное, так и пойдем. Кому что-то не интересно, можете переходить на интересный заголовок.

Рутокен ЭЦП 2.0 3000



Факты


Новый токен под старым брендом. Вроде какая-то добавка 3000 в конце и вообще не понятно о чем это. А между тем перед нами принципиально новый носитель ключевой информации. С классическим Рутокен ЭЦП 2.0 его объединяет пожалуй лишь то, что он может быть с ним совместим, и по прежнему на нём можно хранить неизвлекамые закрытые ключи, криптографические операции с которыми происходят прямо в контроллере девайса, а закрытые ключи никогда не покидают его пределов.

А в чем же разница? Пожалуй, отличия четыре:
  1. Это функциональный ключевой носитель (ФКН), работающий по протоколу (на самом деле метапротоколу) SESPAKE, что дает нам защиту канала между драйвером и контроллером от прослушивания
  2. Многократное ускорение при работе с токеном, на котором есть несколько ключей с сертификатами
  3. Невозможность работы в режиме ФКН через PKCS#11
  4. Отсутствие режима работы без КриптоПро


Давайте теперь по порядку.

ФКН с SESPAKE дает возможность защитить канал обмена между драйвером/криптопровайдером и контроллером хранилища. Раньше подобный перехват был возможен, и любой любитель Wireshark с установленным USBcap мог лицезреть открытые PIN-коды при работе с классическим Рутокен ЭЦП 2.0, которые транслируются в APDU командах контролера, что потенциально даёт вектор атаки по подслушиванию PIN'а и дальнейшему подписыванию всего и вся без взаимодействия с пользователем. И хотя формально закрытые ключи всё равно остаются неизвлекаемыми, это может перестать быть принципиальным моментом.

Ускорение. Уж не знаю как и почему, но если у вас было несколько сертификатов на одном токене Рутокен ЭЦП 2.0, то тормоза были обеспечены. Особенно при попытке софта перебрать все сертификаты или найти контейнер с нужным. Ваш покорный слуга хватал лично ситуации, когда в некоторых системах ЭДО дешифрация маленького документа занимала более минуты. Всё кончилось тем, что Тензор в своих плагинах даже запретил использование аппаратных токенов совместно с КриптоПро 5-й версии, чем вызвал много подозрений. Теперь всё не так, я даже не замечаю разницы между тем, когда на токене был один сертификат, и теперь, когда их четыре (Тензор при этом всё равно не работает с аппаратными ключами в версиях плагинов где-то с осени 2019 года).

Режим PKCS#11 это возможность использовать библиотеку производителя, которая реализует стандартное API PKCS#11 по работе с ним (напрямую без КриптоПровайдера). Под Windows применяется мало, т.к. Windows Crypto API является доминирующим способом. Под Linux похоже увы, если не брать гипотетическую возможность установить КриптоПро под Linux и использовать его. КриптоПро под Linux представляет собой по сути реализацию Windows Crypto API, то есть ни одна традиционная софтина под Linux это не поддерживала и не будет поддерживать. Скорее это возможность для разработчиков пилить госзаказ и разрабатывать соответствующие серверные продукты под Linux с возможность криптографии ГОСТ. О применении в Linux Desktop речи не идет. Тем не менее Рутокен поставляет свою библиотеку PKCS#11 для старого Рутокен ЭЦП 2.0 и мне даже удавалось как-то подружить её с плагином ГосУслуг для аутентификации по электронной подписи. С ФКН возможности такой, как я понимаю нет, но возможно компания Актив меня поправит.

Отсутствие режима работы без КриптоПро. Скорее всего это связано с предыдущим пунктом. Но на практике сложилась некоторая путаница при использовании Рутокен ЭЦП 2.0. Почему-то мало кто знает, что Рутокен ЭЦП 2.0 умеет прекрасно работать с КриптоПро 5-й версии. Возможно, из-за того, что он появился задолго до КриптоПро 5. В результате, различные участники рынка наработали кастомные решения, которые позволяют работать с Рутокен ЭЦП 2.0 без КриптоПро. Это приводило к достаточно серьезным трудностям в диагностике проблем на сайтах. Ты говоришь, что у тебя КриптоПро и Рутокен ЭЦП 2.0, а тебе говорят, что Рутокен ЭЦП 2.0 не работает через КриптоПро. С 3000-м альтернативы, похоже, никакой нет. Только КриптоПро 5. Хорошо это или плохо время покажет.

Картинки


Если вы используете КриптоПро 5-й версии, то поддержка идет из коробки. Отличия для пользователя минимальны. Создание ключевого контейнера:


В отличие от тупого носителя у вас теперь есть выбор в каком режиме вырабатывать ключевую пару. Верхний новый режим ФКН, внизу старый режим Рутокен ЭЦП 2.0 с поддержкой PKCS#11, посередине режим тупого токена, в котором всю работу делает криптопровайдер.

При создании первого контейнера в режиме ФКН КриптоПро попросит задать PUK-код и пароль:



В результате получим ключевую пару, которую можно посмотреть через Панель управления Рутокен:


Резюме


Рутокен ЭЦП 2.0 3000 стал для меня долгожданной заменой для ранее использованного функционального ключевого носителя из АПК КриптоПро Рутокен CSP 3.6, который умел только старые ГОСТы. Тем не менее, я очень расстраиваюсь, что для работы с этим всем добром приходится держать виртуалку с виндой. Было бы здорово, если бы Рутокен раскрыл описание своей реализации протокола SESPAKE. Думаю, что прикрутить стандартные линуксовые библиотеки для работы с этим токеном можно будет будет без особых проблем.

COVID-19 и РосРеестр


Пандемия нехорошим образом сказалась на возможности работы с РосРеестром. Не знаю как других регионах, но в Питере случилась прямо какая-то вакханалия. С одной стороны, МФЦ полностью перешли на работу по предварительной записи (сейчас вышли, но по услугам РосРеестра продолжают оставаться). С другой стороны, записаться на это стало возможным только в первые минуты начала дня после 9:00 и где-то на 2-3 недели вперед. СМИ сообщали, что риелторы бронировали всё под себя, а потом продавали свою очередь но так как запись была именная, то помимо покупки очереди приходилось ещё и оформлять доверку на такого дельца, потому что кроме него никто пойти по очереди не мог.

Альтернативой этому стали нотариусы, которые могут в электронном виде отправлять документы на регистрацию сделки в Росреестр, но они берут очень дорого за нотариальное удостоверение сделки. Другая альтернатива ДомКлик от Сбербанка: если покупатель покупает в ипотеку, то ДомКлик позволяет зарегистрировать всё электронно (даже с небольшой выгодой по процентной ставке).

Покупатель нашелся по ипотеке, и дружно решили оформляться через ДомКлик. Но не тут-то было. Недвижимость оказалась старой, и регистрация прав была осуществлена в 1995 году. Если вы регистрировали свои права до 31.01.1998, то нужно:
  • либо заранее внести заявление о регистрации ранее возникших прав (требует уплаты госпошлины)
  • либо такое заявление подать одновременно со сделкой, тогда это бесплатно


Однако ДомКлик такие заявления подавать не умеет. Нотариусы тоже за это не берутся по неизвестным мне причинам, которые я не выяснял. Сделка оказалась под угрозой, так как МФЦ предложил запись аж на 23 сентября.

И тут выхожу я весь в белом и говорю: А давайте сделаем это в электронном виде сами?

Изменения в законодательстве


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

После череды скандалов(раз, два, три), прокатившихся в 2019 году, связанных с регистрацией прав на недвижимость и создания ЮЛ с использованием электронной подписи, были приняты некоторые изменения в законе. Вкратце: теперь по дефолту использовать ЭП для сделок по недвижимости можно только в том случае, если сертификат ЭП выдан удостоверяющим центром Росреестра, а точнее его дочки ФГБУ Кадастровая палата. Вы можете этот дефолт отменить, явно указав, что хотите это делать с сертификатом любого УЦ. Однако, для этого вам необходимо подать заявление в Росреестр через МФЦ, а для этого предварительно записаться на 2-3 недели вперед (смотри выше) то есть никакого выигрыша по времени.

Что ж? УЦ Росреестра оказывается единственной альтернативой. Начинаем изучать. УЦ располагается по ссылке. Нажимаем Сколько стоит?. 2200 рублей с записью на токен. 700 рублей Предоставляется в электронном виде личность удостоверяется в офисе. Опаньки! В электронном виде, это означает, что работают по схеме с запросом на сертификат. То есть можно самым правильным способом сгенерировать пару у себя на рабочем месте, отправить им запрос, а в офисе только пройти процедуру удостоверения личности то чем и должен заниматься УЦ.

Регистрируемся, заводим все данные в профиль. Жмем Отправить запрос. Сайт делает автоматическую диагностику установленного ПО: всё удовлетворяет необходимым требованиям, т.к. используются только общепринятые плагины к браузеру, а не так как у Тензора. Генерируем пару в режиме ФКН на нашем новом Рутокен ЭЦП 2.0 3000. Ждем. Через несколько минут приходят на электронную почту письма о дальнейших действия. Сказано, ждать документа на оплату. Где-то через полчаса приходит квитанция на оплату с QR-кодом. Платеж в бюджет, поэтому используется УИН. Оплачиваем 700 рублей через онлайн-банк. Ещё через 20 минут, заявка переходит в состояние оплачено. Связка Банк<->ГИС ГМП<->Росреестр работает быстрее чем платежи по реквизитам счета, но конкретная скорость может зависеть от выбранного банка. Звоним по указанному в письме телефону для записи на время для удостоверения личности номерки есть даже на сегодня. Бегом в офис кадастровой палаты. И вот результат в 14:00 этим вопросом озадачились. В 16:00 прошли процедуру удостоверения личности и пока ехали домой, выпустились сертификаты. Процедура достаточно тщательная, помимо всех документальных проверок, также производят фотографирование. Сертификаты, к слову, на 15 месяцев, а не как обычно на год.

Резюме


Несмотря на то, что Росреестр остался фактическим монолистом на рынке ЭП для сделок по недвижимости, работает четко. До этого я пользовался УЦ Тензор, где физлицу можно получить сертификат ЭП за 500 рублей. Но скорость работы, факт того, что не нужно ставить дополнительный софт, как у Тензора, сертификат на 15 месяцев всё это даёт мне основание похвалить впервые за много лет Росреестр. 200 рублей переплаты относительно Тензора того стоят, ИМХО.

Обновление Росреестра по части проведения электронных сделок



В предыдущей статье на эту тему мы рассматривали оформление сделок с помощью основного портала Росреестра (не доступен в момент написания). Вначале я решил пойти по проторенной тропе, но очень быстро упёрся в то, что введенный кадастровый номер помещения не валидируется, хотя введен абсолютно правильно. Анализ HTML-кода показал, что в валидатор вставлен костыль, который отвергает большинство кадастровых номеров по первой группе цифр, которая обозначает регион. Все регионы кроме шести штук (16, 26, 47, 61, 63 и 76) оказались таким образом как бы забаненными. Нигде об этом естественно не написано. Хотелось разбомбить.

Однако я быстро вспомнил, что аналогичный функционал, но с другим интерфейсом был представлен в личном кабинете гражданина в Росреестре (авторизация через ЕСИА), который мне не удалось протестить в прошлой статье. Сходил туда и беглый осмотр показал, что для Питера никаких ограничений нет. Значит будем делать так.
О возможных причинах такого поведения Росреестра
В настоящий момент в Росреестре идет активная миграция на новую информационную систему ФГИС ЕГРН. Миграция происходит по регионам. Возможно, что старый интерфейс для электронных заявлений не предназначен для работы с ФГИС ЕГРН. А новый, который в личном кабинете, предназначен.


Переходим на вкладку Услуги и сервисы и выбираем нужную услугу:


Далее нас ждет несколько шагов по заполнению заявления (в зависимости от выбранной услуги):


На первом шаге необходимо просто согласиться и поставить галочку.

Далее, к сожалению, скриншоты не публикую, так как в них содержится много персональных данных.

На втором шаге необходимо проверить и заполнить данные заявителя. Данные подтягиваются из ЕСИА, но если у вас профиль заполнен не полностью, то что-то придется дописать. Также Росреестр плохо подтягивает из ЕСИА адреса проживания и регистрации скорее всего вам придется указать их вручную. Также отмечу, что на данном шаге есть возможность добавить других заявителей. Это необходимо сделать, если у квартиры несколько собственников.

На третьем шаге указываются (в данном случае) данные о собственности (реквизиты помещения, доли и т.д.).

Четвертый шаг самый сложный. Тут необходимо загрузить все документы. Начиная со сканов паспорта, которые каждый заявитель заверяет своей электронной подписью, заканчивая договорами и прочими документами, которые должны заверяться электронными подписями тех, кто их подписывает. Например, договор, должен быть подписан всеми сторонами сделки. Кроме того, может понадобиться документ, который у вас есть только в бумажном виде или от стороны, которая в сделке не участвует например, согласие супруга. Тут можно прибегнуть к нотариусу нотариусы умеют сканить документы и своей электронной подписью подписывать сканы и факт того, что получившийся электронный документ полностью тождественен документу на бумажном носителе. Возможно, если весь документ составляет сам нотариус, то он может сразу сделать его электронным со своей подписью без вывода на бумагу не поверял работают ли так нотариусы на практике.

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

На последнем (пятом) шаге, вам предстоит повторно проверить состав поданного заявления, подписать его и отправить. Перед отправкой вас спросят о желании составить второе заявление в этом же пакете документов. Если вы регистрируете сделку (переход прав), а не просто регистрацию прав, то это необходимо сделать. Причем первое заявление должно подаваться текущими собственниками помещения, а второе от имени тех, кому право переходит. В оба заявления нужно прицепить договор, подписанный всеми сторонами сделки.

Резюме


В казалось бы безвыходной ситуации нашелся выход. Всё потому что гики это не образ жизни, а стремление к неизведанному. Прошлый мой опыт, сотканный из просто желания попробовать неизведанное, обернулся реальной пользой.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru