Ошибка проверки цифровой подписи для доступа к веб-сервису
Мне нужно отправить цифровую подпись в качестве одного из параметров на внешний веб-сервис.
Шаги для создания согласно документации:
- Создать
DOM
представлениеXML
данные - Создать канонизированное представление
DOM
данные. Канонизированное представление должно следовать форме, описанной в http://www.w3.org/TR/2001/REC-xml-c14n-20010315; - Создать подпись
RSA
шифрованиеSHA1
Дайджест канонизированного представления. Подпись зашифрована с использованием личного ключа Участника; - Кодировать двоичную подпись в строку в кодировке base64
- Поместите строку подписи в
SOAP
сообщениеReqDigSig
элемент; - Сохраните данные 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 для проверки подписи