Создайте ту же подпись с помощью Signature и XMLSignature

#java #xml #signature #digital

Вопрос:

В образовательных целях я хотел бы иметь возможность создавать ту же подпись с помощью Signature и XMLSignature для простого XML. В настоящее время значения подписи, которые я получаю, отличаются.

 public class Test {

  //XML FILES
  static String xml = "<Person><name>John</name><age>20</age></Person>";

  //====================================================================================
  // MAIN
  //====================================================================================
  public static void main(String[] args) throws Exception {

    //GET XML
    Document          dataDocument = UtilXML.stringToDocument(xml);
    byte[]            dataBytes    = xml.getBytes();

    //CREATE KEYS
    KeyPairGenerator  keyPairGenerator = KeyPairGenerator.getInstance("RSA");
                      keyPairGenerator.initialize(2048);
    KeyPair           keyPair    = keyPairGenerator.generateKeyPair();
    PrivateKey        privateKey = keyPair.getPrivate();
    PublicKey         publicKey  = keyPair.getPublic();

    //SIGN IN TWO DIFFERENT WAYS
    byte[]  automaticSignatureBytes = UtilSignature.sign("SHA1withRSA", privateKey, dataBytes);
                                      UtilSignature.signDocument(dataDocument, privateKey, "Person", "", DigestMethod.SHA1, SignatureMethod.RSA_SHA1);

    System.out.println(UtilXML.documentToString(dataDocument));

  }

}
 

 public class UtilSignature {

  //====================================================================================
  // SIGN
  //====================================================================================
  // "SHA256withRSA" => SHA256 Hash   SHA256 Padding   RSA Encryption
  // "SHA1withRSA"   => SHA1   Hash   SHA1   Padding   RSA Encryption
  // "NONEwithRSA"   =>                                RSA Encryption
  public static byte[] sign(String algorithm, PrivateKey privateKey, byte[] dataBytes) throws Exception {

    //INITIALIZE SIGNATURE
    Signature signature = Signature.getInstance(algorithm);
              signature.initSign(privateKey);
              signature.update(dataBytes);

    //CREATE SIGNATURE
    byte[]    signatureBytes = signature.sign();

    //DISPLAY ENCODED SIGNATURE
    System.out.println("SIGNATURE = "   java.util.Base64.getEncoder().encodeToString(signatureBytes));

    //RETURN SIGNATURE
    return signatureBytes;

  }



    //================================================================================
  // SIGN DOCUMENT
  //================================================================================
  // UtilKeys.signDocument (document, privateKey, "Person", "data", DigestMethod.SHA1, SignatureMethod.RSA_SHA1);
  // <Person Id="data">
  public static void signDocument (
    Document   document,        //RETURN VALUE
    Key        privateKey,      //Private Key used to sign XML Element
    String     elementName,     //"Person"     Element to Sign
    String     referenceURI,    //"#data"
    String     digestMethod,    //DigestMethod.SHA1
    String     signatureMethod  //SignatureMethod.RSA_SHA1
  ) throws Exception {

    //CREATE SIGNATURE FACTORY
    XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");

    //GET REFERENCE
    Reference reference = factory.newReference(
      referenceURI,
      factory.newDigestMethod(digestMethod, null),
      Collections.singletonList(factory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
      null,
      null
    );

    //SPECIFY SIGNATURE TYPE
    SignedInfo signedInfo = factory.newSignedInfo(
      factory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,(C14NMethodParameterSpec) null),
      factory.newSignatureMethod(signatureMethod, null),Collections.singletonList(reference)
    );

    //PREPARE SIGN CONTEXT
    DOMSignContext domSignContext = new DOMSignContext(privateKey, document.getElementsByTagName(elementName).item(0));

    //FIX IF referenceURI POINTS TO Id ATTRIBUTE
    if (!referenceURI.equals("") ) {
      Element element = (Element) document.getElementsByTagName(elementName).item(0);
      domSignContext.setIdAttributeNS(element, null, "Id");
    }

    //SIGN DOCUMENT
    XMLSignature signature = factory.newXMLSignature(signedInfo, null);
                 signature.sign(domSignContext);

  }
 

 public class UtilXML {

  //=======================================================================================
  // DOCUMENT TO STRING
  //=======================================================================================
  public static String documentToString(Document document) throws Exception {

    DOMSource          domSource          = new DOMSource(document);

    StringWriter stringWriter = new StringWriter();
    StreamResult streamResult = new StreamResult(stringWriter);

    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer        transformer;
                       transformer        = transformerFactory.newTransformer();
                       transformer.transform(domSource, streamResult);

    //RETURN STRING
    return stringWriter.toString();

  }

  //================================================================================
  // STRING TO DOCUMENT
  //================================================================================
  public static Document stringToDocument(String xmlString) throws Exception {

    //READ XML STRING
    InputSource             inputSource = new InputSource();
                            inputSource.setCharacterStream(new StringReader(xmlString));

    //CONVERT TO DOCUMENT
    DocumentBuilderFactory  documentBuilderFactory = DocumentBuilderFactory.newInstance();
                            documentBuilderFactory.setNamespaceAware(true);    //IMPORTANT
    DocumentBuilder         documentBuilder = documentBuilderFactory.newDocumentBuilder();
    Document                document        = documentBuilder.parse(inputSource);

    //RETURN DOCUMENT
    return document;

  }
 

Результаты :

 SIGNATURE = FFb8T9xHRR0GzMPvBlG2fOR9o7OjcBdzoslXWECMKiJB31BNv9oA577xA84/zK7n/07U9uigccLCilUMCSjlkANOc2BvT3IHqFGTdZ6gzV14CuU0pZdznj7kLyYzR3zWeU2FWH/7vaX6BuQfesRjLWP Qp0msS4lcWxITecb9 AMu4lSQ3yt0espEdpZ51asgGQ204iLuUIeA4PDb0c 9eVWBzwr75oxWi/ dSdMh0pA5i/zDCZCGRv8QNW2QAooV5VoqbV0ckeHZSAYJa3ocrrlCewdiITXXcx/N5GUPxWallrk8bOoEssJqcARKAjQ9PjTiFCSXzWsoeOECLmQNw==

<?xml version="1.0" encoding="UTF-8"?><Person><name>John</name><age>20</age><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>PxmvRsQSxek1iLl/BIsSfTHoY1M=</DigestValue></Reference></SignedInfo><SignatureValue>MTk6to1oHSqGmGhTFZX3uII0iZAmPhVGNBMz7tPHSqlXSqnvtAKaKBwUClMAzDy3LxpPn3s8wNZEamp;#xD;
EWAHtBHZs29NNd3whhDPW3xyv9Z367PJjl2bMOQ8mzcb DPeTZoGIOjWJOidmrbdqqNhmJ0qvcX9amp;#xD;
pNazxILrI8MZvrVTHDRblWkdQUPJWXeiCN5p51/7bM38XsUl1EqqI7ewjyVBFiv6nd EkQeW2Rj amp;#xD;
ggEEUYH/Gr4dBsLLI3Ocm1euYxJJqH1MdaK4rYwD quIJCAyth3QLTen/0Swj11vJ/4enKS0ByTzamp;#xD;
cX7S/M1OhGF3AOFnIcTLftNy s2BvIK4MC9pfQ==</SignatureValue></Signature></Person>
 

Комментарии:

1. Во-первых, вы должны знать, что в целом цифровые подписи не являются детерминированными, и подписание одних и тех же данных дважды дает разные подписи. Однако конкретная схема здесь = RSASSA-PKCS1-v1_5 ЯВЛЯЕТСЯ детерминированной, и разница заключается в том, что то, что вы делаете, даже отдаленно не похоже на то, что делает XMLDSig ; см. 3.1 документа, на который я ссылался (и, вероятно, 2 для контекста).