Мне нужно отправить цифровую подпись в качестве одного из параметров на внешний веб-сервис.
Шаги для создания в соответствии с документацией:
- Создайте
DOM
представлениеXML
данных - Создайте канонизированное представление данных
DOM
. Канонизированное представление должно соответствовать форме, описанной в http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments; - Создайте подпись
RSA
для шифрованияSHA1
дайджеста канонизированного представления. Подпись шифруется с использованием закрытого ключа Участника; - Закодируйте двоичную подпись в строку в кодировке base64.
- Поместите строку Signature в элемент
SOAP
messageReqDigSig
; - Сохраните 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);
}
Но ответ от веб-сервиса говорит об ошибке проверки цифровой подписи.
приведенный выше код соответствует описанию в документации? Как я могу проверить, действительна ли цифровая подпись? есть ли какой-нибудь онлайн-инструмент?
[Сообщение отредактировано следующим образом] Я пытался использовать следующее. Я проверил подпись, и она возвращает true. Но не работает с конца веб-сервиса. В чем разница между методами signData, signHash и createsignature классов 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.
Возвращаемая ошибка, я полагаю, обработана пользователем и указывает «Ошибка проверки цифровой подписи».
[Отредактировано]
Ниже вы найдете фрагмент кода, который генерирует цифровую подпись в java. Это было отправлено третьей стороной для справки. Я не java-разработчик. Может ли кто-нибудь сообщить мне, соответствует ли код С#, который я написал, коду 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;
}