Вопросы по Java XML Digital Signature

Мне нужно подписать цифровой документ XML. Данное требование заключается в том, что входные данные представляют собой файл XML и закрытый ключ. Для подписи следует использовать SHA256/RSA-2048, а подпись должна быть Enveloping. Я придумал следующий метод, чтобы сделать это. При тестировании KeyPair генерируется с использованием класса KeyPairGenerator с RSA в качестве алгоритма и размером ключа, равным 2048. Переданный входной поток является объектом FileInputStream, а выходной поток - объектом FileOutputStream. Кажется, что метод работает нормально.

public void sign(InputStream inputStream, OutputStream outputStream, KeyPair kp) throws Exception {
    XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

    Reference ref = fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null));

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(inputStream);
    XMLStructure content = new DOMStructure(doc.getDocumentElement());
    XMLObject obj = fac.newXMLObject(Collections.singletonList(content), "object", null, null);

    SignatureMethod signatureMethod = fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
    CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec)null);

    SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(ref));

    KeyInfoFactory kif = fac.getKeyInfoFactory();
    KeyValue kv = kif.newKeyValue(kp.getPublic());

    KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

    XMLSignature signature = fac.newXMLSignature(si, ki, Collections.singletonList(obj), null, null);

    DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc);

    signature.sign(dsc);

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    trans.transform(new DOMSource(doc), new StreamResult(outputStream));       
}

У меня есть несколько вопросов:

  1. Я не указал в коде, что RSA должен использоваться в подписи, так как он узнал? Также я понимаю, что в шифровании есть также режим и заполнение. Опять же, они также не указаны, так что бы они были?

  2. Я действительно не знаю, как работает канонизация XML. CanonicalizationMethod.INCLUSIVE и CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS выдают одинаковый вывод (оба имеют одно и то же значение DigestValue). Что означают эти разные методы?

  3. Сообщение в конверте в теге объекта выглядит точно так же, как и содержимое входного XML-файла. Предполагается, что конвертованное сообщение совпадает с исходным XML или это канонизированная версия? Я знаю, что канонизированная версия используется в дайджесте, но не уверена, должна ли обернутая версия быть канонизированной или нет. В моем исходном XML-файле есть тег комментариев, но тег комментариев всегда будет присутствовать в выходных данных, независимо от того, добавлю я INCLUSIVE или INCLUSIVE_WITH_COMMENTS.

  4. Требуется ли вообще открытый ключ? Требование, данное мне, состояло в том, что закрытый ключ является вводом, но я не уверен, стоит ли мне также спрашивать об открытом ключе. Похоже, что открытый ключ требуется для объекта KeyValue.

Заранее спасибо.

1 ответ

Решение

1) Алгоритм подписи выводится из URI, который вы используете с newSignatureMethod (" http://www.w3.org/2001/04/xmldsig-more")

2) Вы не указываете какой-либо алгоритм канонизации для ссылки в newReference. Следовательно, по умолчанию (Canonical XML без комментариев) используется перед вычислением значения дайджеста ваших данных XML. Ваш canonicalizationMethod используется с SignedInfo: элемент SignedInfo будет канонизирован с этим алгоритмом перед вычислением значения подписи.

Чтобы указать алгоритм канонизации для подписанных данных XML, вы должны сказать это при создании ссылки:

Transform tr = fac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);

fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(tr), null, null);

Этот код добавит Transform с алгоритмом канонизации в Ссылку, ссылающуюся на #object, который будет хэширован.

3) В элементе Object будет тот же контент, который вы добавили к нему. Канонизация (или любое другое преобразование) будет применено к этому контенту перед вычислением значения дайджеста.

4) KeyValue является необязательным и является подсказкой для верификатора подписи. Обычные подписи будут иметь сертификат в сертификате X509 вместо значения ключа.

Надеюсь это поможет. Moez

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