Ключевое слово в защите информации
ключевое слово
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Марк  
#1 Оставлено : 23 ноября 2014 г. 11:09:14(UTC)
Марк

Статус: Новичок

Группы: Участники
Зарегистрирован: 23.11.2014(UTC)
Сообщений: 4
Российская Федерация

У меня есть вот такой нехитрый работающий пример подписи строки на C#:
Код:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

namespace Test1
{
  class Program
  {

    [StructLayout(LayoutKind.Sequential)]
    struct CRYPTOAPI_BLOB
    {
      public Int32 cbData;
      public IntPtr pbData;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct CRYPT_ALGORITHM_IDENTIFIER
    {
      [MarshalAs(UnmanagedType.LPStr)]
      public String pszObjId;
      public CRYPTOAPI_BLOB Parameters;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct CRYPT_SIGN_MESSAGE_PARA
    {
      public Int32 cbSize;
      public Int32 dwMsgEncodingType;
      public IntPtr pSigningCert;
      public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
      public IntPtr pvHashAuxInfo;
      public Int32 cMsgCert;
      public IntPtr rgpMsgCert;
      public Int32 cMsgCrl;
      public IntPtr rgpMsgCrl;
      public Int32 cAuthAttr;
      public IntPtr rgAuthAttr;
      public Int32 cUnauthAttr;
      public IntPtr rgUnauthAttr;
      public Int32 dwFlags;
      public Int32 dwInnerContentType;
    }

    [DllImport("Crypt32.dll", SetLastError = true)]
    static extern Boolean CryptSignMessage(
      ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
      Boolean fDetachedSignature,
      Int32 cToBeSigned,
      IntPtr[] rgpbToBeSigned,
      Int32[] rgcbToBeSigned,
      Byte[] pbSignedBlob,
      ref Int32 pcbSignedBlob
    );

    const Int32 X509_ASN_ENCODING = 0x00000001;
    const Int32 PKCS_7_ASN_ENCODING = 0x00010000;
    const string szOID_CP_GOST_R3411 = "1.2.643.2.2.9";

    //Отпечаток известного нам сертификата
    const string CertThumbprint = "D55E8BC8037937D1A836F8A0524E56B1C49AD281";
    const string StringForSign = "Some Data"; //Данные для подписи
    static void Main()
    {
      X509Store MyStore = new X509Store(StoreLocation.CurrentUser);
      MyStore.Open(OpenFlags.ReadOnly);
      try
      {
        foreach (X509Certificate2 MyCert in MyStore.Certificates)
        {
          if (MyCert.Thumbprint == CertThumbprint) //Нашли нужный
          {
            CRYPT_SIGN_MESSAGE_PARA MySignContext = new CRYPT_SIGN_MESSAGE_PARA();
            MySignContext.cbSize = Marshal.SizeOf(typeof(CRYPT_SIGN_MESSAGE_PARA));
            MySignContext.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
            MySignContext.pSigningCert = MyCert.Handle;
            MySignContext.HashAlgorithm.pszObjId = szOID_CP_GOST_R3411;
            IntPtr[] BuffToSign = new IntPtr[1] { Marshal.StringToHGlobalAnsi(StringForSign) };
            try
            {
              int SignedLen = 4096;
              byte[] Result = new byte[SignedLen];
              int[] bufferLen = new int[1] { StringForSign.Length };
              if (CryptSignMessage(ref MySignContext, true, 1, BuffToSign, bufferLen, Result, ref SignedLen))
              {
                Array.Resize(ref Result, SignedLen);
                for (int i = 0; i < Result.Length; i++)
                {
                  Console.Write("{0:X2} ", Result[i]);
                  if ((i+1) % 26 == 0)
                    Console.WriteLine();
                }
                Console.Write("\nLength = {0}", Result.Length);
                Console.Write("\nPress any key to exit:  ");
                Console.ReadKey();
              }
              else
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            finally
            {
              Marshal.FreeHGlobal(BuffToSign[0]);
            }
            break;
          }
        }
      }
      finally
      {
        MyStore.Close();
      }
    }
  }
}

Подскажите, как повторить это средствами браузерного плагина (интересует коротенький примерчик на JavaScript). Главное, чтобы совпало значение подписи, преобразования в BASE64 и т.д. если нужно это понятно. На основе примеров, тех что в документации, не могу добиться совпадения. Вероятно, чего-то недопонимаю.
Вложение(я):
Program.cs.zip (2kb) загружен 9 раз(а).

У Вас нет прав для просмотра или загрузки вложений. Попробуйте зарегистрироваться.
Offline Андрей Писарев  
#2 Оставлено : 23 ноября 2014 г. 14:40:57(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 14,190
Мужчина
Российская Федерация

Сказал «Спасибо»: 621 раз
Поблагодарили: 2397 раз в 1886 постах
Техническую поддержку оказываем тут
Наша база знаний
Offline Андрей Писарев  
#3 Оставлено : 23 ноября 2014 г. 14:44:06(UTC)
Андрей *

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 26.07.2011(UTC)
Сообщений: 14,190
Мужчина
Российская Федерация

Сказал «Спасибо»: 621 раз
Поблагодарили: 2397 раз в 1886 постах
За такое ...
Код:
  int SignedLen = 4096;
              byte[] Result = new byte[SignedLen]; 


Позвольте поинтересоваться, где "такому" учат?
Техническую поддержку оказываем тут
Наша база знаний
Offline Марк  
#4 Оставлено : 23 ноября 2014 г. 16:49:41(UTC)
Марк

Статус: Новичок

Группы: Участники
Зарегистрирован: 23.11.2014(UTC)
Сообщений: 4
Российская Федерация

> Так и должно быть, так как в создании ЭЦП по алгоритму ГОСТ Р 34.11/34.10-2001 используется случайное число.
Вопрос не в том, что результат какждый раз разный. А в том, что при проверке подписи результаты не бьются. Я наверно не правильно выразился.
> Позвольте поинтересоваться, где "такому" учат?
А в чём криминал? Выделяем заведомо бОльший буфер, реальная длина которого затем пересчитывается в вызове CryptSignMessage(), после чего обрезаем лишнее.
Да, можно было бы сначала тем же вызовом спросить нужную длину, и её выделить. Но вопрос же не об этом совсем (было бы 2 вызова с обращением к носителю, а это ничуть не быстрее).
Offline Марк  
#5 Оставлено : 27 ноября 2014 г. 7:00:11(UTC)
Марк

Статус: Новичок

Группы: Участники
Зарегистрирован: 23.11.2014(UTC)
Сообщений: 4
Российская Федерация

Народ, я понимаю, что видимо сильно туплю. Но подскажите хоть направление какое-то. Вот делаю к примеру так:
Код:

function TestClick() {
  var CADESCOM_HASH_ALGORITHM_CP_GOST_3411 = 100;
  var CADESCOM_BASE64_TO_BINARY = 1;
  var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
  var CADES_BES = 1;
  var CADESCOM_CADES_DEFAULT = 0;

  var oSigner = CreateObject("CAdESCOM.CPSigner");
  oSigner.Options = 0;
  var oSignedData = CreateObject("CAdESCOM.CadesSignedData");
  oSignedData.Content = "Some Data";
  var sSignedData = oSignedData.SignCades(oSigner, CADES_BES);
  document.getElementById("EpText").value = sSignedData;
}

Получается какой-то результат. Когда я его декодирую из BASE64, то длина у него 2881 байт. А в том моём примере 1044 байта - понятно, что верификация подписи не сойдётся в таком случае никак, это что-то совсем разное. Что и как мне правильно вызвать?
Offline Kirill Sobolev  
#6 Оставлено : 27 ноября 2014 г. 11:06:10(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,733
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Цитата:
Получается какой-то результат. Когда я его декодирую из BASE64, то длина у него 2881 байт. А в том моём примере 1044 байта - понятно, что верификация подписи не сойдётся в таком случае никак, это что-то совсем разное. Что и как мне правильно вызвать?

При вызове плагина в подпись автоматически добавляется сертификат подписанта, в случае же вызова CryptSignMessage надо правильно заполнить CRYPT_SIGN_MESSAGE_PARA:rgpMsgCert.
Это и дает разницу в размере, но не является причиной того, что подпись не проверяется.
Техническую поддержку оказываем тут
Наша база знаний
Offline Марк  
#7 Оставлено : 27 ноября 2014 г. 17:03:57(UTC)
Марк

Статус: Новичок

Группы: Участники
Зарегистрирован: 23.11.2014(UTC)
Сообщений: 4
Российская Федерация

Т.е. верно ли я понимаю из ваших слов, что применительно к моему примеру, первые 1044 байта это будет подпись, а следом идёт что-то вроде аналога свойства RawData для объекта класса X509Certificate2 ? Или там какая-то другая структура будет в том массиве, что возвращается? (содержимое сертификата подписанта мне как раз тоже понадобится, теперь только бы правильно отделить одно от другого...)
Offline Kirill Sobolev  
#8 Оставлено : 28 ноября 2014 г. 9:37:23(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,733
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Цитата:
Т.е. верно ли я понимаю из ваших слов, что применительно к моему примеру, первые 1044 байта это будет подпись, а следом идёт что-то вроде аналога свойства RawData для объекта класса X509Certificate2 ? Или там какая-то другая структура будет в том массиве, что возвращается? (содержимое сертификата подписанта мне как раз тоже понадобится, теперь только бы правильно отделить одно от другого...)

Другая структура.
Техническую поддержку оказываем тут
Наша база знаний
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.