Я пытаюсь создать SOAP-сообщение с подписью (алгоритм российского ГОСТ34.10-2001) на Java для некоторых государственных служб. Дело в том, что сервис мне говорит, что Подпись недействительна и я не вижу, где я ошибся. Контейнер ключей, из которого я читаю закрытый ключ и сертификат, действителен. Где что-то идет не так? Я понимаю, что мой вопрос довольно специфичен, но я все же надеюсь, что кто-то может указать мне путь.
update1:небольшое обновление: тело сообщения содержит несколько узлов и значений кириллицы (utf)-8 update2: Итак, я прочитал этот вопрос и попытался получить PrivateKey таким же образом и получил это исключение: java.lang.IllegalArgumentException: закрытый ключ алгоритм не соответствует алгоритму открытого ключа в сертификате конечного объекта
Вот код:
Здесь я маршалирую классы в тело SOAP:
try {
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage sm = mf.createMessage();
SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope envelope = sp.getEnvelope();
QName bodyId = new QName("http://ws.unisoft/", "SendFullULRequest");
SOAPBody sb = (SOAPBody) envelope.getBody();
SOAPHeader sh = (SOAPHeader) envelope.getHeader();
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(FullULRq.class);
javax.xml.bind.Marshaller marshaller = jaxbCtx.createMarshaller();
marshaller.marshal(new JAXBElement<FullULRq>(bodyId, FullULRq.class, fulr),
sm.getSOAPBody());
sm.saveChanges();
Затем я вычисляю значение дайджеста:
ReferenceType rt2 = new ReferenceType();
rt2.setURI("#body");
////Пункт 7
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(sm.getSOAPBody());
Result outputTarget = new StreamResult(outputStream);
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.transform(xmlSource, outputTarget);
Init.init();
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
final ByteArrayInputStream is = new ByteArrayInputStream(canon.canonicalize(outputStream.toByteArray()));
rt2.setDigestValue(computeDigestWithStream(is));
} catch (Exception e) {
e.printStackTrace();
}
С помощью этого метода:
public static byte[] computeDigestWithStream(ByteArrayInputStream stream) throws Exception {
final MessageDigest digest =
MessageDigest.getInstance("GOST3411");
// processing data
final DigestInputStream digestStream =
new DigestInputStream(stream, digest);
while (digestStream.available() != 0) {
digestStream.read();
}
И, наконец, я генерирую подпись из блока (в котором элемент присутствует):
ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
Source xmlSource2 = new DOMSource(sm.getSOAPBody());
Result outputTarget2 = new StreamResult(outputStream2);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.transform(xmlSource2, outputTarget2);
Init.init();
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
InputStream is2 = new ByteArrayInputStream(outputStream2.toByteArray());
byte[] bb = canon.canonicalize(outputStream2.toByteArray());
byte[] signval = sign("CryptoProSignature", key, bb);
Метод знака():
public static byte[] sign(String algorithmName, PrivateKey privateKey, byte[] data) throws Exception {
final Signature sig = Signature.getInstance(algorithmName);
sig.initSign(privateKey);
sig.update(data);
return sig.sign();
}
И если это уместно, вот как я читаю privateKey из контейнера:
KeyStore ks = KeyStore.getInstance("FloppyStore");
String passwd = "*";
String kalias = null;
ks.load(null, null);
Enumeration enum1 = ks.aliases();
for (; enum1.hasMoreElements();) {
String tAlias = (String) enum1.nextElement();
if (ks.isKeyEntry(tAlias)) {
kalias = tAlias;
}
System.out.println(tAlias);
}
PrivateKey key = (PrivateKey) ks.getKey(kalias, passwd.toCharArray());
Спасибо!
keytool -list Path_to_your_Floppystore.jks
ваш закрытый ключ? Сохраняли ли вы пароль для хранилища ключей и закрытого ключа одинаковыми (рекомендуется -›)? Почему бы не использовать библиотеку WSS4J для ваших целей? - person Aydin K.   schedule 13.04.2012