Ошибка проверки цифровой подписи для доступа к веб-сервису

Мне нужно отправить цифровую подпись в качестве одного из параметров на внешний веб-сервис.

Шаги для создания согласно документации:

  1. Создать DOM представление XML данные
  2. Создать канонизированное представление DOM данные. Канонизированное представление должно следовать форме, описанной в http://www.w3.org/TR/2001/REC-xml-c14n-20010315;
  3. Создать подпись RSA шифрование SHA1 Дайджест канонизированного представления. Подпись зашифрована с использованием личного ключа Участника;
  4. Кодировать двоичную подпись в строку в кодировке base64
  5. Поместите строку подписи в SOAP сообщение ReqDigSig элемент;
  6. Сохраните данные XML, так как это может понадобиться позже для поддержки невозвращения представленных данных XML.

Я использовал следующий код:

private string SignXML(X509Certificate2 Cert, string data)
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.LoadXml(data);

        XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
        t.LoadInput(xmlDoc);
        Stream s = (Stream)t.GetOutput(typeof(Stream));

        SHA1 sha1 = SHA1.Create();
        byte[] hash = sha1.ComputeHash(s);


        RSACryptoServiceProvider rsaKey =
        (RSACryptoServiceProvider)Cert.PrivateKey;
        RSAParameters rsaPrivateParams = rsaKey.ExportParameters(true);
        rsaKey.ImportParameters(rsaPrivateParams);
        byte[] signature =  rsaKey.Encrypt(hash, false);

        return Convert.ToBase64String(signature);
    }

Но в ответе веб-службы говорится об ошибке проверки цифровой подписи.

приведенный выше код согласно описанию в документации? Как я могу проверить, действительна ли цифровая подпись? есть ли онлайн-инструмент?

[Сообщение отредактировано следующим образом] Я попытался использовать следующее. Я проверил подпись, и она вернула истину. Но терпит неудачу от конца веб-сервиса. В чем разница между методами signignature классов signData, signHash и rsaPKCsignatureformatter?

        var document = Encoding.UTF8.GetBytes(Reqdata);

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.LoadXml(Reqdata);

        //trial with XmlDsigC14NWithCommentsTransform class
        XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
        t.LoadInput(xmlDoc);
        Stream s = (Stream)t.GetOutput(typeof(Stream));

        //trial with SignedXML class
        SignedXml signedXml = new SignedXml(xmlDoc);
        signedXml.SignedInfo.CanonicalizationMethod =
        SignedXml.XmlDsigC14NWithCommentsTransformUrl;
        document = Encoding.UTF8.GetBytes(signedXml.ToString());

        byte[] hashedDocument;

        using (var sha1 = SHA1.Create())
        {
            //hashedDocument = sha1.ComputeHash(document);
            hashedDocument = sha1.ComputeHash(s);
        }

        var digitalSignature = new DigitalSignature();
        digitalSignature.AssignNewKey();

        byte[] signature = digitalSignature.SignData(hashedDocument);
        string finalsignature = Convert.ToBase64String(signature) ;
        byte[] finalSignveri = Convert.FromBase64String(finalsignature);
        bool verified = digitalSignature.VerifySignature(hashedDocument, finalSignveri);

и класс цифровой подписи выглядит следующим образом:

public class DigitalSignature
{
    private RSAParameters publicKey;
    private RSAParameters privateKey;

    public void AssignNewKey()
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.PersistKeyInCsp = false;
            publicKey = rsa.ExportParameters(false);
            privateKey = rsa.ExportParameters(true);
        }
    }

    public byte[] SignData(byte[] hashOfDataToSign)
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.PersistKeyInCsp = false;
            rsa.ImportParameters(privateKey);

            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
            rsaFormatter.SetHashAlgorithm("SHA1");

            return rsaFormatter.CreateSignature(hashOfDataToSign);
        }
    }

    public bool VerifySignature(byte[] hashOfDataToSign, byte[] signature)
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.ImportParameters(publicKey);

            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
            rsaDeformatter.SetHashAlgorithm("SHA1");

            return rsaDeformatter.VerifySignature(hashOfDataToSign, signature);
        }
    }   
}

Не могли бы вы дать мне знать, какие данные вы конкретно ищете в WSDL? Извините, я не могу предоставить полную информацию о wsdl здесь.

Возвращенная ошибка, я считаю, что пользователь обработан и заявляет "Ошибка проверки цифровой подписи"

[Redited]

Ниже приведен фрагмент кода, который генерирует цифровую подпись в Java. Это было отправлено третьей стороной для справки. Я не разработчик Java. Может ли кто-нибудь дать мне знать, соответствует ли написанный мной код C# Java-коду? Если нет, пожалуйста, дайте мне знать, где я иду не так.

private static String createDigitalSignature(Key key, byte[] data) {

    byte[] signature = null;

    try {
        // Initialize xml-security library
        org.apache.xml.security.Init.init();

        // Build DOM document from XML data
        DocumentBuilderFactory dfactory = DocumentBuilderFactory
                .newInstance();
        dfactory.setNamespaceAware(true);
        dfactory.setValidating(true);
        DocumentBuilder documentBuilder = dfactory.newDocumentBuilder();
        // This is to throw away all validation errors
        documentBuilder
                .setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
        Document doc = documentBuilder
                .parse(new ByteArrayInputStream(data));

        // Build canonicalized XML from document
        Canonicalizer c14n = Canonicalizer
                .getInstance("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
        byte[] canonBytes = c14n.canonicalizeSubtree(doc);

        // Initialize signing object with SHA1 digest and RSA encryption
        Signature rsa = Signature.getInstance("SHA1withRSA");

        // Set private key into signing object
        rsa.initSign((PrivateKey) key);

        // Generate signature
        rsa.update(canonBytes);
        signature = rsa.sign();
    } catch (Exception ex) {
        System.out.println("Exception occurred in createDigitalSignature: "
                + ex.toString());
        System.exit(-1);
    }

    // Base64 encode signature
    BASE64Encoder b64e = new BASE64Encoder();
    String signatureString = b64e.encode(signature);

    return signatureString;
}

1 ответ

На шаге 3 цифровая подпись не совсем совпадает с шифрованием дайджеста. Цифровая подпись RSA в формате pkcs#1 объединяет OID digestAlgorithm (идентификатор) со значением дайджеста. Значит вы генерируете и недействительную подпись.

Все языки программирования имеют метод для выполнения цифровой подписи, не имея дело с дайджестами и шифрами. Я не программист C#, но я думаю, что вы должны использовать RSACryptoServiceProvider.SignData

Используйте также VerifyData для проверки подписи

Другие вопросы по тегам