Подписать отправляемый XML с помощью ЭЦП

Я нашел вот эту инструкцию, но не могу его реализовать на C#.

Необходимо выполнить следующие действия:

  1. Создать XML, используя XSD схему для подписываемых данных (Схему можно получить перейдя по ссылке http://esf.gov.kz:8080/esf-web/ws/EsfXsdService?wsdl);
  2. Убрать XML заголовок (строку вида <?xml version="1.0"?>)
  3. Убрать все символы между XML тэгами (включая пробелы, табуляции и символы перевода строки);
  4. Подписываемые данные должны начинаться с тега <invoice> и заканчиваться тегом </invoice>, исключая неймспейсы и префиксы.
    Пример:
<invoice>
  <date>04.08.2016</date>
  <invoiceType>ORDINARY_INVOICE</invoiceType>
  <num>11111111111111121</num>
  <operatorFullname>Идрисов Кайрат Ерикович</operatorFullname>
  <signatureType>COMPANY</signatureType>
  <customers>
      <customer>
          <address>г.Астана, ул. Мира д 24 кв 12</address>
          <name>ТОО "АСЕМ-2"</name>
          <statuses>
              <status>NONRESIDENT</status>
          </statuses>
      </customer>
  </customers>
  <productSet>
      <currencyCode>KZT</currencyCode>
      <product>
          <description>цемент</description>
          <ndsAmount>0</ndsAmount>
          <priceWithTax>2500</priceWithTax>
          <priceWithoutTax>2500</priceWithoutTax>
          <quantity>5</quantity>
          <turnoverSize>2500</turnoverSize>
          <unitNomenclature>тонна</unitNomenclature>
          <unitPrice>500</unitPrice>
      </product>
      <product>
          <description>доставка</description>
          <ndsAmount>0</ndsAmount>
          <priceWithTax>8000</priceWithTax>
          <priceWithoutTax>8000</priceWithoutTax>
          <quantity>1</quantity>
          <turnoverSize>8000</turnoverSize>
          <unitNomenclature>услуга</unitNomenclature>
          <unitPrice>8000</unitPrice>
      </product>
      <totalExciseAmount>0</totalExciseAmount>
      <totalNdsAmount>0</totalNdsAmount>
      <totalPriceWithTax>10500</totalPriceWithTax>
      <totalPriceWithoutTax>10500</totalPriceWithoutTax>
      <totalTurnoverSize>10500</totalTurnoverSize>
  </productSet>
  <sellers>
      <seller>
          <bank>аТФ БАНК</bank>
          <bik>KZKS456J</bik>
          <iik>KZ012565854HG456253658FG</iik>
          <kbe>19</kbe>
          <name>ИП"Кайрат"</name>
          <statuses>
              <status>EXPORTER</status>
          </statuses>
          <tin>123456789011</tin>
      </seller>
  </sellers>
  <turnoverDate>20.07.2016</turnoverDate>
</invoice>

Для формирования ЭЦП для ЭСФ, Вам необходимо скачать комплект разработчика SDK по адресу http://kgd.gov.kz/ru/content/api-interfeys-1

  1. Используя локальный сервис(generateSignature в SDK) получить подпись для нужного ЭСФ.
  2. Подписать ЭСФ полученной от локального сервиса подписью.

Если Вы хотите реализовать генерацию подписи программным путем, просим выполнить следующие пункты:

  1. Полученную в результате выполнения шагов 2-4 канонизированную строку необходимо подписать закрытым ключом:
byte[] signature = sign(data.getBytes(StandardCharsets.UTF_8), privateKey);
  1. Полученный в результате подписания байтовый массив, т.е. подпись, необходимо преобразовать в base64-строку:
String signatureBase64Type = Base64.getEncoder().encodeToString(byte[] signature);
  1. Вставить полученную подпись(signatureBase64Type) в теги запроса веб-сервиса.

ВАЖНО! Уважаемые разработчики, обратите внимание на реализацию шагов 7 и 8 в вашей системе, так как в большинстве случаев причиной проблемы было именно отсутствие преобразования байтового массива в base64-строку.

Верификацию полученной подписи можете осуществить следующим образом:

X509Certificate cert = сертификат подписи пользователя;
Signature s = Signature.getInstance(cert.getPublicKey().getAlgorithm());
s.initVerify(cert.getPublicKey());
s.update(invoiceXmlString.getBytes(StandardCharsets.UTF_8));                    
boolean signatureVerificationResult = s.verify(Base64.getDecoder().decode(signature));

пока что нашел кода для получения certificate

// получение данные для certificate
try
{
    X509Certificate2 cert = new X509Certificate2("key path.p12", "password", X509KeyStorageFlags.PersistKeySet);
    byte[] signature = cert.GetRawCertData();
    
    String signatureBase64Type = Convert.ToBase64String(signature);
    Console.WriteLine(signatureBase64Type);
} 
catch (CryptographicException ex)
{
    Console.WriteLine("Ошибка: {0}", ex.Message);
}

как я могу получить код для signature ?


Ответы (1 шт):

Автор решения: Yakov
  1. Для начала пойми в каком виде / формате / контейнере у тебя хранится сертификат/открытый/закрытый ключи?
  2. Есть весь сертификат или только открытая его часть? Обычно открытая часть передается вместе с подписью.
  3. Тебе нужно только проверять подпись или подписывать тоже необходимо?
  4. Какой используется крипто-провайдер. RSA или что-то другое? если нужна совместимость с Java ( а исходники в описании на ней приведены ) то смотри в сторону сборки Org.BouncyCastle для .NET, я с ее помощью пробовал реализовать RSA256 для авторизации JWT в Google FCM, более ничего в дотнете с PEM-форматом сертификата нормально не работало.
→ Ссылка