Skip to content

Repository files navigation

@mmskazak/crypto-pro-plus

CI

📦 Современная обёртка над CryptoPro CAdES plugin
Позволяет удобно работать с сертификатами, получать информацию, подписывать данные (attached/detached) и добавлять метку времени — всё на async/await.


🚀 Установка

npm install @mmskazak/crypto-pro-plus

⚠️ Требуется установленный CryptoPro CSP и плагин cadesplugin.


🧠 Возможности

  • 🔍 Проверка версии плагина
  • 📋 Получение списка сертификатов
  • 🧾 Получение информации по сертификату
  • ✍️ Detached/Attached подпись (CAdES-BES)
  • ⏱ Подпись с меткой времени (CAdES-T)
  • 👥 Множественные подписи (коллективные, последовательные)
  • 🛡️ Контрподписи (заверение подписей)
  • ✅ Проверка валидности цифровых подписей (включая множественные подписи)
  • 🔐 Создание хешей (SHA-1/256/384/512, ГОСТ Р 34.11-94/2012-256/2012-512)
  • ✍️ Подпись хешей любых алгоритмов (detached с поддержкой меток времени)
  • 🔄 Конвертация Unicode-строк в корректный base64

🏗 Модульная структура

Библиотека полностью организована по модульному принципу. Каждый модуль отвечает за свою область функциональности:

crypto-pro-plus/
├── src/
│   ├── common.js           # Общие функции (pluginVersion, openCertificateStore)
│   ├── certificates.js     # Работа с сертификатами
│   ├── signing.js          # Подпись данных (attached/detached)
│   ├── multiple-signing.js # Множественные подписи (коллективные, последовательные)
│   ├── hashing.js          # Создание хешей
│   ├── hash-signing.js     # Подпись хешей
│   ├── verification.js     # Проверка подписей
│   ├── countersigning.js   # Контрподписи
│   └── utils.js            # Утилиты (toBase64Unicode)
├── cadesplugin-wrapper.js
└── cadesplugin_api.js

Импорт модулей

// Работа с сертификатами
import { getCertificates, getCertificateInfo } from '@mmskazak/crypto-pro-plus/certificates';

// Подпись данных
import { signBase64Detached } from '@mmskazak/crypto-pro-plus/signing';

// Создание хешей
import { createSHA256Hash, createGost2012_256Hash } from '@mmskazak/crypto-pro-plus/hashing';

// Подпись хешей
import { signSHA256HashDetached } from '@mmskazak/crypto-pro-plus/hash-signing';

// Проверка подписей
import { verifyDetachedSignature } from '@mmskazak/crypto-pro-plus/verification';

// Множественные подписи
import { coSignBase64, createCollectiveSignature, createSequentialSignature } from '@mmskazak/crypto-pro-plus/multiple-signing';

// Контрподписи
import { counterSign } from '@mmskazak/crypto-pro-plus/countersigning';

// Утилиты
import { toBase64Unicode } from '@mmskazak/crypto-pro-plus/utils';

// Общие функции
import { pluginVersion } from '@mmskazak/crypto-pro-plus/common';

📘 Примеры

✅ Проверка плагина

import { pluginVersion } from '@mmskazak/crypto-pro-plus/common';
import { countCertificates } from '@mmskazak/crypto-pro-plus/certificates';

try {
  const version = await pluginVersion();
  console.log("Версия плагина:", version);

  const count = await countCertificates();
  console.log("Сертификатов найдено:", count);
} catch (error) {
  // Плагин не установлен, хранилище недоступно и т.п.
  console.error("Плагин КриптоПро недоступен:", error.message);
}

📜 Получение всех сертификатов

import { getCertificates } from '@mmskazak/crypto-pro-plus/certificates';

const certs = await getCertificates();
certs.forEach(cert => {
  console.log(cert.subjectName, cert.thumbprint, cert.validToDate);
});

📄 Информация по сертификату

import { getCertificateByThumbprint, getCertificateInfo } from '@mmskazak/crypto-pro-plus/certificates';

const cert = await getCertificateByThumbprint("DA9142...");
const info = await getCertificateInfo(cert);
console.log(info);

✍️ Detached-подпись (без метки)

import { signBase64Detached } from '@mmskazak/crypto-pro-plus/signing';
import { toBase64Unicode } from '@mmskazak/crypto-pro-plus/utils';

const data = toBase64Unicode("Данные для подписи");
const signature = await signBase64Detached(data, "DA9142...");
console.log(signature);

⏱ Detached-подпись с меткой времени

import { signBase64DetachedWithTimestamp } from '@mmskazak/crypto-pro-plus/signing';

const signature = await signBase64DetachedWithTimestamp(data, "DA9142...", "http://testca.cryptopro.ru/tsp/");
console.log(signature);

📎 Attached-подпись (встроенная)

import { signBase64Attached } from '@mmskazak/crypto-pro-plus/signing';

const signature = await signBase64Attached(data, "DA9142...");
console.log(signature);

📎⏱ Attached-подпись с меткой времени

import { signBase64AttachedWithTimestamp } from '@mmskazak/crypto-pro-plus/signing';

const signature = await signBase64AttachedWithTimestamp(data, "DA9142...", "http://testca.cryptopro.ru/tsp/");
console.log(signature);

🎯 Подпись с выбором сертификата

import { signWithCertificateSelection } from '@mmskazak/crypto-pro-plus/signing';
import { toBase64Unicode } from '@mmskazak/crypto-pro-plus/utils';

const data = toBase64Unicode("Важный документ");

// Пользователю покажется диалог выбора сертификата
const result = await signWithCertificateSelection(
  data, 
  true, // isDetached
  "http://testca.cryptopro.ru/tsp/" // опционально TSP
);

console.log('Подпись:', result.signature);
console.log('Сертификат:', result.certificateInfo.subjectName);
console.log('Предупреждения:', result.certificateInfo.warnings);

🛡️ Безопасное подписание с проверкой

import { signWithValidation, validateCertificateForSigning } from '@mmskazak/crypto-pro-plus/signing';

// Сначала проверим сертификат
const validation = await validateCertificateForSigning("DA9142...");
if (!validation.isValid) {
  console.error('Сертификат недействителен:', validation.reason);
  return;
}

// Подписываем с проверкой
try {
  const result = await signWithValidation(data, "DA9142...", true);
  console.log('Подпись создана:', result.signature);
} catch (error) {
  console.error('Ошибка подписания:', error.message);
}

🔐 Создание хешей

import { 
  createGost2012_256Hash,
  createSHA256Hash,
  createSHA512Hash,
  createHash
} from '@mmskazak/crypto-pro-plus/hashing';
import { toBase64Unicode } from '@mmskazak/crypto-pro-plus/utils';

const data = toBase64Unicode("Данные для хеширования");

// ГОСТ Р 34.11-2012 256 бит
const gost256Hash = await createGost2012_256Hash(data);

// SHA-256
const sha256Hash = await createSHA256Hash(data);

// SHA-512  
const sha512Hash = await createSHA512Hash(data);

// Универсальная функция с любым алгоритмом
import { cadesplugin } from '@mmskazak/crypto-pro-plus/cadesplugin-wrapper';
const customHash = await createHash(data, cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_384);

✍️ Подпись хешей (detached)

import { 
  signGost2012_256HashDetached,
  signSHA256HashDetached,
  signHashDetached
} from '@mmskazak/crypto-pro-plus/hash-signing';

// Подпись ГОСТ-хеша
const gost256Signature = await signGost2012_256HashDetached(gost256Hash, "DA9142...");

// Подпись SHA-256 хеша
const sha256Signature = await signSHA256HashDetached(sha256Hash, "DA9142...");

// Универсальная функция
import { cadesplugin } from '@mmskazak/crypto-pro-plus/cadesplugin-wrapper';
const customSignature = await signHashDetached(
  customHash, 
  "DA9142...", 
  cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_384
);

✍️⏱ Подпись хешей с меткой времени

import { 
  signGost2012_256HashDetachedWithTimestamp,
  signSHA256HashDetachedWithTimestamp,
  signHashDetachedWithTimestamp
} from '@mmskazak/crypto-pro-plus/hash-signing';

// ГОСТ с меткой времени
const gost256Signature = await signGost2012_256HashDetachedWithTimestamp(
  gost256Hash, 
  "DA9142...", 
  "http://testca.cryptopro.ru/tsp/"
);

// SHA-256 с меткой времени
const sha256Signature = await signSHA256HashDetachedWithTimestamp(
  sha256Hash, 
  "DA9142...", 
  "http://testca.cryptopro.ru/tsp/"
);

// Универсальная функция с меткой времени
import { cadesplugin } from '@mmskazak/crypto-pro-plus/cadesplugin-wrapper';
const customSignature = await signHashDetachedWithTimestamp(
  customHash, 
  "DA9142...", 
  cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_384,
  "http://testca.cryptopro.ru/tsp/"
);

✅ Проверка подписей

import { 
  verifyDetachedSignature, 
  verifyAttachedSignature,
  verifyTimestampedSignature,
  getSignersInfo 
} from '@mmskazak/crypto-pro-plus/verification';

// Проверка detached подписи
const isValidDetached = await verifyDetachedSignature(originalData, signature);
console.log('Detached подпись валидна:', isValidDetached);

// Проверка attached подписи
const attachedResult = await verifyAttachedSignature(signedMessage);
console.log('Attached подпись валидна:', attachedResult.isValid);
if (attachedResult.isValid) {
  console.log('Извлеченные данные:', attachedResult.content);
}

// Проверка подписи с меткой времени
const timestampResult = await verifyTimestampedSignature(originalData, signature, true);
console.log('Подпись с меткой времени валидна:', timestampResult.isValid);
if (timestampResult.timestampInfo) {
  console.log('Время подписи:', timestampResult.timestampInfo.signingTime);
}

// Получение информации о всех подписчиках (может быть несколько!)
const signersInfo = await getSignersInfo(signature, true, originalData);
console.log(`Найдено подписчиков: ${signersInfo.length}`);

signersInfo.forEach((signer, index) => {
  console.log(`\n--- Подписчик ${index + 1} ---`);
  console.log('Имя:', signer.subjectName);
  console.log('Издатель сертификата:', signer.issuerName);
  console.log('Отпечаток сертификата:', signer.thumbprint);
  console.log('Время подписи:', signer.signingTime);
  console.log('Сертификат действителен с:', signer.validFromDate);
  console.log('Сертификат действителен до:', signer.validToDate);
});

👥 Множественные подписи

import { 
  coSignBase64,
  coSignBase64WithTimestamp,
  createMultipleSignature,
  createSequentialSignature 
} from '@mmskazak/crypto-pro-plus/multiple-signing';

// Добавление соподписи к существующей подписи
const coSignedData = await coSignBase64(
  originalData,
  existingSignature,
  secondSignerThumbprint,
  true // isDetached
);

// Создание коллективной подписи сразу несколькими подписчиками
const thumbprints = ["cert1_thumbprint", "cert2_thumbprint", "cert3_thumbprint"];
// Коллективная подпись (все подписывают исходные данные одновременно)
const collectiveSignature = await createCollectiveSignature(
  originalData,
  thumbprints,
  true, // isDetached
  "http://testca.cryptopro.ru/tsp/" // опционально TSP для всех
);

// Последовательная подпись (цепочка: каждый подписывает результат предыдущего)
const signers = [
  { thumbprint: "manager_cert", tspUrl: "http://testca.cryptopro.ru/tsp/" },
  { thumbprint: "director_cert", tspUrl: "http://testca.cryptopro.ru/tsp/" },
  { thumbprint: "accountant_cert" } // без TSP
];

const sequentialResult = await createSequentialSignature(originalData, signers, true);
console.log('Финальная подпись:', sequentialResult.signature);
console.log('История подписания:', sequentialResult.history);

🛡️ Контрподписи (заверение подписей)

import { 
  counterSign,
  counterSignBySigner,
  counterSignAll,
  getCounterSignersInfo
} from '@mmskazak/crypto-pro-plus/countersigning';

// Создание контрподписи (заверение первого подписчика)
const counterSignedData = await counterSign(
  existingSignature,
  notaryThumbprint,
  "http://testca.cryptopro.ru/tsp/" // опционально
);

// Контрподпись конкретного подписчика (по индексу)
const counterSignedSpecific = await counterSignBySigner(
  existingSignature,
  notaryThumbprint,
  2, // индекс подписчика
  "http://testca.cryptopro.ru/tsp/"
);

// Контрподпись всех подписчиков
const counterSignedAll = await counterSignAll(
  existingSignature,
  notaryThumbprint,
  "http://testca.cryptopro.ru/tsp/"
);

// Получение информации о контрподписях
const counterSignersInfo = await getCounterSignersInfo(signature, originalData, true);
counterSignersInfo.forEach(info => {
  console.log(`Подписчик: ${info.signerName}`);
  info.counterSignatures.forEach(cs => {
    console.log(`  Заверил: ${cs.counterSignerName} в ${cs.counterSigningTime}`);
  });
});

🔐 Поддерживаемые алгоритмы хеширования

Алгоритм Константа Функции
SHA-1 CADESCOM_HASH_ALGORITHM_SHA1 createSHA1Hash, signSHA1HashDetached*
SHA-256 CADESCOM_HASH_ALGORITHM_SHA_256 createSHA256Hash, signSHA256HashDetached*
SHA-384 CADESCOM_HASH_ALGORITHM_SHA_384 createSHA384Hash, signSHA384HashDetached*
SHA-512 CADESCOM_HASH_ALGORITHM_SHA_512 createSHA512Hash, signSHA512HashDetached*
ГОСТ Р 34.11-94 CADESCOM_HASH_ALGORITHM_CP_GOST_3411 createGost94Hash, signGost94HashDetached*
ГОСТ Р 34.11-2012 256 CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256 createGost2012_256Hash, signGost2012_256HashDetached*
ГОСТ Р 34.11-2012 512 CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_512 createGost2012_512Hash, signGost2012_512HashDetached*

Примечание: * означает, что доступны варианты как без метки времени, так и с меткой времени (WithTimestamp)


🪵 Логирование

По умолчанию библиотека пишет диагностические сообщения через console (debug/info/warn/error). Это поведение можно подменить своим логгером или отключить полностью:

import { setLogger } from '@mmskazak/crypto-pro-plus/logger';

// Свой логгер (например, обёртка над winston/pino) — можно переопределить только часть методов
setLogger({
  error: (...args) => myLogger.error(...args),
});

// Полностью отключить вывод
setLogger(null);

// Вернуть логирование в console
setLogger();

📌 API

Обработка ошибок: функции получения данных (pluginVersion, countCertificates, getCertificates и т.п.) и функции подписания выбрасывают исключение, если что-то пошло не так (плагин недоступен, сертификат не найден и т.д.) — оборачивайте вызовы в try/catch. Функции проверки/валидации (verify*, validateCertificateForSigning, getSignersInfo, getCounterSignersInfo) исключений не бросают — они возвращают структурированный результат (false/{ isValid: false }/[]), потому что невалидная подпись или сертификат — ожидаемый результат проверки, а не ошибка.

Метод Описание
pluginVersion() Возвращает версию установленного плагина
countCertificates() Считает количество сертификатов в личном хранилище
getCertificates() Получает список сертификатов с SubjectName, Thumbprint, сроками и объектом
getCertificateByThumbprint(thumbprint) Возвращает объект сертификата по отпечатку
getCertificateInfo(cert) Возвращает подробную информацию о сертификате
selectCertificateFromDialog(title) Показывает диалог выбора сертификата пользователю
getValidCertificates() Получает список всех действующих сертификатов
validateCertificateForSigning(thumbprint) Проверяет может ли сертификат использоваться для подписания
signBase64Detached(dataBase64, thumbprint) Detached-подпись без метки времени (CAdES-BES)
signBase64DetachedWithTimestamp(dataBase64, thumbprint, tspUrl) Detached-подпись с меткой времени (CAdES-T)
signBase64Attached(dataBase64, thumbprint) Attached-подпись без метки времени (CAdES-BES)
signBase64AttachedWithTimestamp(dataBase64, thumbprint, tspUrl) Attached-подпись с меткой времени (CAdES-T)
signWithCertificateSelection(dataBase64, isDetached, tspUrl) Подпись с выбором сертификата через диалог
signWithValidation(dataBase64, thumbprint, isDetached, tspUrl) Безопасное подписание с проверкой сертификата
Функции хеширования
createHash(dataBase64, algorithm) Универсальная функция создания хеша с любым алгоритмом
createGost2012_256Hash(dataBase64) Создает ГОСТ-хеш данных (ГОСТ Р 34.11-2012 256 бит)
createSHA1Hash(dataBase64) Создает SHA-1 хеш данных
createSHA256Hash(dataBase64) Создает SHA-256 хеш данных
createSHA384Hash(dataBase64) Создает SHA-384 хеш данных
createSHA512Hash(dataBase64) Создает SHA-512 хеш данных
createGost2012_512Hash(dataBase64) Создает ГОСТ Р 34.11-2012 512 бит хеш данных
createGost94Hash(dataBase64) Создает ГОСТ Р 34.11-94 хеш данных
Функции подписи хешей
signHashDetached(hashBase64, thumbprint, algorithm) Универсальная detached-подпись хеша без метки времени
signHashDetachedWithTimestamp(hashBase64, thumbprint, algorithm, tspUrl) Универсальная detached-подпись хеша с меткой времени
signGost2012_256HashDetached(hashBase64, thumbprint) Detached-подпись ГОСТ 2012-256 хеша без метки времени (CAdES-BES)
signGost2012_256HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись ГОСТ 2012-256 хеша с меткой времени (CAdES-T)
signSHA1HashDetached(hashBase64, thumbprint) Detached-подпись SHA-1 хеша без метки времени
signSHA1HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись SHA-1 хеша с меткой времени
signSHA256HashDetached(hashBase64, thumbprint) Detached-подпись SHA-256 хеша без метки времени
signSHA256HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись SHA-256 хеша с меткой времени
signSHA384HashDetached(hashBase64, thumbprint) Detached-подпись SHA-384 хеша без метки времени
signSHA384HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись SHA-384 хеша с меткой времени
signSHA512HashDetached(hashBase64, thumbprint) Detached-подпись SHA-512 хеша без метки времени
signSHA512HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись SHA-512 хеша с меткой времени
signGost2012_512HashDetached(hashBase64, thumbprint) Detached-подпись ГОСТ 2012-512 хеша без метки времени
signGost2012_512HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись ГОСТ 2012-512 хеша с меткой времени
signGost94HashDetached(hashBase64, thumbprint) Detached-подпись ГОСТ-94 хеша без метки времени
signGost94HashDetachedWithTimestamp(hashBase64, thumbprint, tspUrl) Detached-подпись ГОСТ-94 хеша с меткой времени
Функции множественных подписей
coSignBase64(dataBase64, existingSignature, thumbprint, isDetached) Добавляет соподпись к существующей подписи
coSignBase64WithTimestamp(dataBase64, existingSignature, thumbprint, tspUrl, isDetached) Добавляет соподпись с меткой времени
createCollectiveSignature(dataBase64, thumbprints, isDetached, tspUrl) Создает коллективную подпись (все подписывают исходные данные)
createSequentialSignature(dataBase64, signers, isDetached) Создает последовательную подпись (цепочка подписей)
createMultipleSignature(dataBase64, thumbprints, isDetached, tspUrl) Алиас для createCollectiveSignature (обратная совместимость)
Функции проверки подписей
verifyDetachedSignature(dataBase64, signatureBase64) Проверяет detached подпись CAdES
verifyAttachedSignature(signatureBase64) Проверяет attached подпись CAdES
verifyTimestampedSignature(dataBase64, signatureBase64, isDetached) Проверяет подпись с меткой времени CAdES-T
getSignersInfo(signatureBase64, isDetached, dataBase64) Получает информацию о всех подписчиках (поддержка множественных подписей)
verifySignature(signatureBase64, options) Универсальная функция проверки подписи
Функции контрподписей
counterSign(existingSignature, thumbprint, tspUrl) Создает контрподпись (заверение подписи)
counterSignBySigner(existingSignature, thumbprint, signerIndex, tspUrl) Контрподпись конкретного подписчика
counterSignAll(existingSignature, thumbprint, tspUrl) Контрподпись всех подписчиков
getCounterSignersInfo(signatureBase64, dataBase64, isDetached) Получает информацию о контрподписях
Утилиты
toBase64Unicode(str) Кодирует строку в корректный base64 с поддержкой Unicode

🧪 Разработка

npm install     # установка зависимостей
npm test        # запуск тестов (Vitest, мок cadesplugin — реальный плагин не нужен)
npm run lint    # проверка стиля кода
npm run format  # автоформатирование (Prettier)

CI (GitHub Actions) прогоняет lint и test на Node 20.x/22.x при каждом push в master и на каждый pull request.


🧑‍💻 Автор

Михаил Мельников — github.com/mmskazak


📜 Лицензия

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages