#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 для контекста).