c# Подпись запроса в формате PKCS#7 detached signature в формате urlSafeBase64

Помогите, пожалуйста, разобраться.

Задача: требуется "подпись запроса в формате PKCS#7 detached signature в формате urlSafeBase64 в кодировке UTF-8 – подписанный не ранее, чем за 24 часа (86400 с) параметр UUID сертификатом организации, на сотрудника которой был выдан (сформирован) идентификационный ключ".

Я установила КриптоПро .NET и КриптоПро .NET SDK. Нашла примеры - .NET SDK\Examples\simple.zip\CMS\cs\DetachedSignature.cs Полностью взяла код из этого файла, но у меня ничего не работает.

public static byte[] MainMethod(string[] args, String msg)
{
    try
    {
        ClearLog();
 
        // Проверка корректности переданных параметров.
        if (args.Length < 1)
        {
            Log(string.Format("CMS.DetachedSignature <cert-subject>"));
            return Array.Empty<byte>();
        }
 
        String signerName = args[0];
 
        // Исходное сообщение.
        //const String msg = "Это сообщение, которое будет подписано.";
 
        Log(string.Format("{0}Исходное сообщение (длина {1}): {2}  ",
            Environment.NewLine, msg.Length, msg));
 
        // Переводим исходное сообщение в массив байтов.
        Encoding unicode = Encoding.UTF8;
        byte[] msgBytes = unicode.GetBytes(msg);
 
        Log(string.Format("{0}{0}------------------------------",
            Environment.NewLine));
        Log(string.Format(" Поиск сертификата            "));
        Log(string.Format("------------------------------{0}",
            Environment.NewLine));
 
        // Получаем сертификат ключа подписи;
        // он будет использоваться для получения 
        // секретного ключа подписи.
        X509Certificate2 signerCert = GetSignerCert(signerName);
 
        Log(string.Format("{0}{0}------------------------------",
            Environment.NewLine));
        Log(string.Format(" На стороне отправителя"));
        Log(string.Format("------------------------------{0}",
            Environment.NewLine));
 
        byte[] encodedSignature = SignMsg(msgBytes, signerCert);
        File.WriteAllBytes("signature.bin", encodedSignature);
 
        Log(string.Format("{0}{0}------------------------------",
            Environment.NewLine));
        Log(string.Format(" На стороне получателя  "));
        Log(string.Format("------------------------------{0}",
            Environment.NewLine));
 
        // При проверка detached подписи передаем и само сообщение
        if (VerifyMsg(msgBytes, encodedSignature))
        {
            Log(string.Format("{0}Сообщение проверено.",
                Environment.NewLine));
        }
        else
        {
            Log(string.Format("{0}Ошибка при проверке сообщения.",
                Environment.NewLine));
        }
 
        return encodedSignature;
    }
    catch (Exception)
    {
        return new byte[0];
    }
}
 
// Открываем хранилище 'My' и ищем сертификат
// для подписи сообщения. 
private static X509Certificate2 GetSignerCert(string signerName)
{
    // Открываем хранилище My.
    X509Store storeMy = new X509Store(StoreName.My,
        StoreLocation.CurrentUser);
    storeMy.Open(OpenFlags.ReadOnly);
 
    // Отображаем сертификаты для удобства работы
    // с примером.
    Log(string.Format("Найдены сертификаты следующих субъектов " +
        "в хранилище {0}:", storeMy.Name));
    foreach (X509Certificate2 cert in storeMy.Certificates)
    {
        Log(string.Format("\t{0}", cert.SubjectName.Name));
    }
 
    // Ищем сертификат для подписи.
    X509Certificate2Collection certColl =
        storeMy.Certificates.Find(X509FindType.FindBySubjectName,
        signerName, false);
    Log(string.Format(
        "Найдено {0} сертификат(ов) в хранилище {1} для субъекта {2}",
        certColl.Count, storeMy.Name, signerName));
 
    // Проверяем, что нашли требуемый сертификат
    if (certColl.Count == 0)
    {
        Log(string.Format(
            "Сертификат для данного примера не найден " +
            "в хранилище. Выберите другой сертификат для подписи. "));
        return null;
    }
 
    storeMy.Close();
 
    // Если найдено более одного сертификата,
    // возвращаем первый попавщийся.
    return certColl[0];
}
 
// Подписываем сообщение секретным ключем.
private static byte[] SignMsg(
    Byte[] msg,
    X509Certificate2 signerCert)
{
    // Создаем объект ContentInfo по сообщению.
    // Это необходимо для создания объекта SignedCms.
    ContentInfo contentInfo = new ContentInfo(msg);
 
    // Создаем объект SignedCms по только что созданному
    // объекту ContentInfo.
    // SubjectIdentifierType установлен по умолчанию в 
    // IssuerAndSerialNumber.
    // Свойство Detached устанавливаем явно в true, таким 
    // образом сообщение будет отделено от подписи.
    SignedCms signedCms = new SignedCms(contentInfo, true);
 
    // Определяем подписывающего, объектом CmsSigner.
    CmsSigner cmsSigner = new CmsSigner(signerCert);
 
    // Подписываем CMS/PKCS #7 сообение.
    Log(string.Format("Вычисляем подпись сообщения для субъекта " +
        "{0} ... ", signerCert.SubjectName.Name));
    signedCms.ComputeSignature(cmsSigner);
    Log(string.Format("Успешно."));
 
    // Кодируем CMS/PKCS #7 подпись сообщения.
    return signedCms.Encode();
}
 
// Проверяем SignedCms сообщение и возвращаем Boolean
// значение определяющее результат проверки.
private static bool VerifyMsg(Byte[] msg,
    byte[] encodedSignature)
{
    // Создаем объект ContentInfo по сообщению.
    // Это необходимо для создания объекта SignedCms.
    ContentInfo contentInfo = new ContentInfo(msg);
 
    // Создаем SignedCms для декодирования и проверки.
    SignedCms signedCms = new SignedCms(contentInfo, true);
 
    // Декодируем подпись
    signedCms.Decode(encodedSignature);
 
    // Перехватываем криптографические исключения, для 
    // возврата о false значения при некорректности подписи.
    try
    {
        // Проверяем подпись. В данном примере не 
        // проверяется корректность сертификата подписавшего.
        // В рабочем коде, скорее всего потребуется построение
        // и проверка корректности цепочки сертификата.
        Log(string.Format("Проверка подписи сообщения ... "));
        signedCms.CheckSignature(true);
        Log(string.Format("Успешно."));
    }
    catch (System.Security.Cryptography.CryptographicException e)
    {
        Log(string.Format("Функция VerifyMsg возбудила исключение:  {0}",
            e.Message));
        Log(string.Format("Проверка PKCS #7 сообщения завершилась " +
            "неудачно. Возможно сообщене, подпись, или " +
            "соподписи модифицированы в процессе передачи или хранения. " +
            "Подписавший или соподписавшие возможно не те " +
            "за кого себя выдают. Достоверность и/или целостность " +
            "сообщения не гарантируется. "));
        return false;
    }
 
    return true;
}

Ошибка падает в методе SignMsg на строчке

signedCms.ComputeSignature(cmsSigner);

Текст ошибки:

System.Security.Cryptography.CryptographicException: 'Could not determine signature algorithm for the signer certificate.'

This exception was originally thrown at this call stack: System.Security.Cryptography.Pkcs.CmsSigner.Sign(System.ReadOnlyMemory, string, bool, out System.Security.Cryptography.X509Certificates.X509Certificate2Collection) System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(System.Security.Cry ptography.Pkcs.CmsSigner, bool) System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(System.Security.Cry ptography.Pkcs.CmsSigner) Samples.CMS.DetachedSignature.SignMsg(byte[], System.Security.Cryptography.X509Certificates.X509Certificate2) in DetachedSignature.cs Samples.CMS.DetachedSignature.MainMethod(string[], string) in DetachedSignature.cs

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


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