Skip to content

Плагин Flutter для формирования электронной цифровой подписи с помощью алгоритмов ГОСТ по стандарту PKCS7 Cryptographic Message Syntax (CMS)

Notifications You must be signed in to change notification settings

MaximMonakhov/crypt_signature

Repository files navigation

Плагин Flutter для формирования электронной цифровой подписи с помощью алгоритмов ГОСТ по стандарту PKCS7 Cryptographic Message Syntax (CMS)

pub package

Описание

Плагин принимает сертификаты в формате PKCS12 .pfx

Поддерживаемые алгоритмы для Android: GOST R 34.10-2001, GOST R 34.10-2012, GOST R 34.10-2012 Strong

Поддерживаемые архитектуры для Android: arm64-v8a, armeabi-v7a

Поддерживаемые алгоритмы для iOS: GOST R 34.10-2012

⚠ Приватный ключ должен быть помечен как экспортируемый

Установка

Подключение плагина к Android проекту

  1. Скопировать .aar библиотеки из android/libs плагина к себе в проект в android\app\libs

  2. Добавить в build.gradle

minSdkVersion 24

buildTypes {
        release {
            shrinkResources false
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

packagingOptions {
    jniLibs {
        useLegacyPackaging = true
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: '*.aar')
}
  1. Создать файл proguard-rules.pro в android/app
-keep public class ru.CryptoPro.*

Библиотеки .aar указаны в плагине как compile-only, так как невозможно к .aar (коим является этот плагин) подключать другие .aar, для этого требуется скопировать их к себе в проект и подключить как implementation. Proguard используется, чтобы запретить обфускацию кода, которая происходить при выполнении релизной сборки.

Подключение плагина к iOS проекту

Добавить папки en.lproj, locale, ru.lproj и файлы kis_1, root.sto, config.ini, license.enc из ios/Resources плагина к себе в проект через Xcode (Add files to Runner...). Это нужно для того, чтобы эти файлы нашел КриптоПРО для проверки целостности. Это ресурсы копируются в папку с плагином, а КриптоПРО ищет их в корневой папке приложения.

Использование

Работать с плагином можно:

  • Используя собственный интерфейс плагина
  • Через классы по нужному типу подписи (MessageSignRequest, CMSMessageSignRequest, ...)
  • Напрямую через методы

Описание режимов работы:

  • MessageSignRequest
    • Высчитывает хэш от сообщения, подписывает его и возвращает сигнатуру в формате Base64.
  • CMSMessageSignRequest
    • Поддерживает detached/attached форматы PKCS7.
    1. При выборе сертификата пользователем, получает сообщение через функцию getMessage.
    2. Высчитывает хэш от полученного сообщения.
    3. Формирует PKCS7 и атрибуты подписи.
    4. Высчитывает хэш от атрибутов подписи.
    5. Подписывает этот хэш атрибутов.
    6. Вставляет сигнатуру в PKCS7 и возвращает его в формате Base64.
  • CMSHashSignRequest
    • Работает как и CMSMessageSignRequest, но не высчитывает хэш от первоначального сообщения.
    • External Digest.
    • При выборе сертификата пользователем, получает хэш для подписи через функцию getDigest.
  • CustomSignRequest
    • Создан для выполнения собственной логики ЭП.

Иными словами. CMSMessageSignRequest считает хэш сам, а CMSHashSignRequest получает его готовый извне.

Пример работы режимов:

  • MessageSignRequest
    Применяется, когда у проверяющего есть сертификат пользователя и он хочет только проверить ЭП. Например, аутентификация путем ЭП случайного набора байт.
  • CMSMessageSignRequest
    Применяется, когда у проверяющего нет информации о сертификате пользователя и дополнительной информации. Например, регистрация путем ЭП случайного набора байт.
  • CMSHashSignRequest
    Применяется, когда с сервера нецелесообразно передавать изначальное сообщение (из-за его большого размера к примеру). Тогда на выполнение ЭП передается уже готовый хэш от этого сообщения. Например, ЭП документов.

Использование через интерфейс

CryptSignature.interface

При вызове данного метода открывается экран с возможностью добавления/выбора/хранения сертификатов.


crypt signature example image

Методы плагина

  • Инициализировать провайдер
    CryptSignature.initCSP()
  • Установить новую лицензию
    CryptSignature.setLicense(String license)
  • Получить информацию о текущей лицензии
    CryptSignature.getLicense()
  • Добавить сертификат в хранилище
    CryptSignature.addCertificate(File file, String password)
  • Получить список сертификатов, добавленных пользователем
    CryptSignature.getCertificates()
  • Очистить список сертификатов
    CryptSignature.clear()
  • Вычислить хэш сообщения/документа
    CryptSignature.digest(Certificate certificate, String password, String message)
  • Вычислить подпись хэша
    CryptSignature.sign(Certificate certificate, String password, String digest)

Пример

Пример использования плагина через интерфейс

/// MessageSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
SignResult? result = await crypt.interface(context, MessageSignRequest("СООБЩЕНИЕ_В_BASE64"));
print(result?.signature); // Сигнатура в формате Base64
/// CMSMessageSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
Future<String> getMessage(Certificate certificate) async => message; // Callback для запроса на сервер с выбранным пользователем сертификатом для формирования сообщения
CMSSignResult? result = await crypt.interface(context, CMSMessageSignRequest(getMessage));
print(result?.pkcs7.encoded); // PKCS7 в формате Base64
/// CMSHashSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
Future<String> getDigest(Certificate certificate) async => digest; // Callback для запроса на сервер с выбранным пользователем сертификатом для формирования хэша
CMSSignResult? result = await crypt.interface(context, CMSHashSignRequest(getDigest));
print(result?.pkcs7.encoded); // PKCS7 в формате Base64

Пример использования плагина через SignRequest

Рекомендуется, если не пользуетесь интерфейсом. CMSSignRequest сам создаст PKCS7 и подпишет его атрибуты подписи.

/// MessageSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
// Получение файла .pfx и запрос пароля
MessageSignRequest request = MessageSignRequest("СООБЩЕНИЕ_В_BASE64");
SignResult result = await request.signer(certificate, password);
print(result.signature); // Сигнатура в формате Base64
/// CMSMessageSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
// Получение файла .pfx и запрос пароля
Certificate certificate = await crypt.addCertificate(file, password);
Future<String> getMessage(Certificate certificate) async => message; // Callback для запроса на сервер с выбранным пользователем сертификатом для формирования сообщения
CMSMessageSignRequest request = CMSMessageSignRequest(getMessage);
CMSSignResult result = await request.signer(certificate, password);
print(result.pkcs7.encoded); // PKCS7 в формате Base64
/// CMSHashSignRequest
CryptSignature crypt = await CryptSignature.getInstance();
// Получение файла .pfx и запрос пароля
Certificate certificate = await crypt.addCertificate(file, password);
Future<String> getDigest(Certificate certificate) async => digest; // Callback для запроса на сервер с выбранным пользователем сертификатом для формирования сообщения
CMSHashSignRequest request = CMSHashSignRequest(getDigest);
CMSSignResult result = await request.signer(certificate, password);
print(result.pkcs7.encoded); // PKCS7 в формате Base64

Пример использования плагина через методы

/// Стандартная подпись данных
CryptSignature crypt = await CryptSignature.getInstance();
// Получение файла .pfx и запрос пароля
Certificate certificate = await crypt.addCertificate(file, password);
// Получение сообщения для ЭП
DigestResult digestResult = await crypt.digest(certificate, password, message);
SignResult signResult = await crypt.sign(certificate, password, digestResult.digest);
print(signResult.signature);

В случае PKCS7 подписи, PKCS7 нужно будет сформировать самому и подписывать атрибуты подписи. Как пример можно посмотреть как работает Signer в CMSMessageSignRequest или CMSHashSignRequest.

Известные проблемы

  • Ошибка при вызове encode у PKCS7 второй раз после прикрепления сигнатуры. Возникает из-за того, что пакет ASN1 зачем-то кэширует результат первого кодирования без сигнатуры.
  • Отсутствует поддержка GOST R 34.10-2001, GOST R 34.10-2012 Strong для iOS

About

Плагин Flutter для формирования электронной цифровой подписи с помощью алгоритмов ГОСТ по стандарту PKCS7 Cryptographic Message Syntax (CMS)

Topics

Resources

Stars

Watchers

Forks