1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package org.nuiton.util;
33
34 import org.w3c.dom.Attr;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.Node;
38 import org.w3c.dom.NodeList;
39 import org.w3c.dom.ProcessingInstruction;
40 import org.w3c.dom.Text;
41
42 import java.io.ByteArrayOutputStream;
43 import java.io.DataOutputStream;
44 import java.io.IOException;
45 import java.io.UnsupportedEncodingException;
46 import java.security.MessageDigest;
47 import java.security.NoSuchAlgorithmException;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.SortedMap;
52 import java.util.TreeMap;
53
54
55
56
57
58
59
60
61 public class DigestGenerator {
62 public static final String UNICODE_BIG_UNMARKED = "UnicodeBigUnmarked";
63
64
65
66
67
68
69
70
71
72 public byte[] getDigest(Document document, String digestAlgorithm)
73 throws Exception {
74 byte[] digest;
75 try {
76 MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
77 ByteArrayOutputStream baos = new ByteArrayOutputStream();
78 DataOutputStream dos = new DataOutputStream(baos);
79 dos.writeInt(9);
80 Collection childNodes = getValidElements(document);
81 dos.writeInt(childNodes.size());
82 for (Object childNode : childNodes) {
83 Node node = (Node) childNode;
84 if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
85 dos.write(getDigest((ProcessingInstruction) node,
86 digestAlgorithm));
87 } else if (node.getNodeType() == Node.ELEMENT_NODE) {
88 dos.write(getDigest((Element) node, digestAlgorithm));
89 }
90 }
91 dos.close();
92 md.update(baos.toByteArray());
93 digest = md.digest();
94 } catch (NoSuchAlgorithmException e) {
95 throw new Exception(e);
96 } catch (IOException e) {
97 throw new Exception(e);
98 }
99 return digest;
100 }
101
102
103
104
105
106
107
108
109
110 public byte[] getDigest(Node node, String digestAlgorithm) throws Exception {
111 if (node.getNodeType() == Node.ELEMENT_NODE) {
112 return getDigest((Element) node, digestAlgorithm);
113 }
114 if (node.getNodeType() == Node.TEXT_NODE) {
115 return getDigest((Text) node, digestAlgorithm);
116 }
117 if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
118 return getDigest((ProcessingInstruction) node, digestAlgorithm);
119 }
120 return new byte[0];
121 }
122
123
124
125
126
127
128
129
130
131 public byte[] getDigest(Element element, String digestAlgorithm)
132 throws Exception {
133 byte[] digest;
134 try {
135 MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
136 ByteArrayOutputStream baos = new ByteArrayOutputStream();
137 DataOutputStream dos = new DataOutputStream(baos);
138 dos.writeInt(1);
139 dos.write(getExpandedName(element).getBytes(UNICODE_BIG_UNMARKED));
140 dos.write((byte) 0);
141 dos.write((byte) 0);
142 Collection attrs = getAttributesWithoutNS(element);
143 dos.writeInt(attrs.size());
144 for (Object attr : attrs) {
145 dos.write(getDigest((Attr) attr, digestAlgorithm));
146 }
147 Node node = element.getFirstChild();
148
149
150
151 int length = element.getChildNodes().getLength();
152 dos.writeInt(length);
153 while (node != null) {
154 dos.write(getDigest(node, digestAlgorithm));
155 node = node.getNextSibling();
156 }
157 dos.close();
158 md.update(baos.toByteArray());
159 digest = md.digest();
160 } catch (NoSuchAlgorithmException e) {
161 throw new Exception(e);
162 } catch (IOException e) {
163 throw new Exception(e);
164 }
165 return digest;
166 }
167
168
169
170
171
172
173
174
175
176 public byte[] getDigest(ProcessingInstruction pi, String digestAlgorithm)
177 throws Exception {
178 byte[] digest;
179 try {
180 MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
181 md.update((byte) 0);
182 md.update((byte) 0);
183 md.update((byte) 0);
184 md.update((byte) 7);
185 md.update(pi.getTarget().getBytes(UNICODE_BIG_UNMARKED));
186 md.update((byte) 0);
187 md.update((byte) 0);
188 md.update(pi.getNodeValue().getBytes(UNICODE_BIG_UNMARKED));
189 digest = md.digest();
190 } catch (NoSuchAlgorithmException e) {
191 throw new Exception(e);
192 } catch (UnsupportedEncodingException e) {
193 throw new Exception(e);
194 }
195 return digest;
196 }
197
198
199
200
201
202
203
204
205
206 public byte[] getDigest(Attr attribute, String digestAlgorithm)
207 throws Exception {
208 byte[] digest = new byte[0];
209 if (!(attribute.getLocalName().equals("xmlns") || attribute
210 .getLocalName().startsWith("xmlns:"))) {
211 try {
212 MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
213 md.update((byte) 0);
214 md.update((byte) 0);
215 md.update((byte) 0);
216 md.update((byte) 2);
217 md.update(getExpandedName(attribute).getBytes(
218 UNICODE_BIG_UNMARKED));
219 md.update((byte) 0);
220 md.update((byte) 0);
221 md.update(attribute.getValue().getBytes(UNICODE_BIG_UNMARKED));
222 digest = md.digest();
223 } catch (NoSuchAlgorithmException e) {
224 throw new Exception(e);
225 } catch (UnsupportedEncodingException e) {
226 throw new Exception(e);
227 }
228 }
229 return digest;
230 }
231
232
233
234
235
236
237
238
239
240 public byte[] getDigest(Text text, String digestAlgorithm) throws Exception {
241 byte[] digest;
242 try {
243 MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
244 md.update((byte) 0);
245 md.update((byte) 0);
246 md.update((byte) 0);
247 md.update((byte) 3);
248 md.update(text.getTextContent().getBytes(UNICODE_BIG_UNMARKED));
249 digest = md.digest();
250 } catch (NoSuchAlgorithmException e) {
251 throw new Exception(e);
252 } catch (UnsupportedEncodingException e) {
253 throw new Exception(e);
254 }
255 return digest;
256 }
257
258
259
260
261
262
263
264
265 public String getExpandedName(Element element) {
266 return element.getNamespaceURI() + ":" + element.getLocalName();
267 }
268
269
270
271
272
273
274
275
276 public String getExpandedName(Attr attribute) {
277 return attribute.getNamespaceURI() + ":" + attribute.getLocalName();
278 }
279
280
281
282
283
284
285
286 public Collection getAttributesWithoutNS(Element element) {
287 SortedMap map = new TreeMap();
288 for (int i = 0; i < element.getAttributes().getLength(); i++) {
289 Attr attribute = (Attr) element.getAttributes().item(i);
290 if (!(attribute.getLocalName().equals("xmlns") || attribute
291 .getLocalName().startsWith("xmlns:"))) {
292 map.put(getExpandedName(attribute), attribute);
293 }
294 }
295 return map.values();
296 }
297
298
299
300
301
302
303
304 public Collection getValidElements(Document document) {
305 ArrayList list = new ArrayList();
306 NodeList childNodes = document.getChildNodes();
307 for (int i = 0; i < childNodes.getLength(); i++) {
308 Node node = childNodes.item(i);
309 if (node.getNodeType() == Node.ELEMENT_NODE
310 || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
311 list.add(node);
312 }
313 }
314 return list;
315 }
316
317
318
319
320
321
322
323 public String getStringRepresentation(byte[] array) {
324 String str = "";
325 for (byte anArray : array) {
326 str += anArray;
327 }
328 return str;
329 }
330
331
332
333
334
335
336
337
338
339
340 public boolean compareNode(Node node, Node comparingNode,
341 String digestAlgorithm) throws Exception {
342 return Arrays.equals(getDigest(node, digestAlgorithm), getDigest(
343 comparingNode, digestAlgorithm));
344 }
345
346
347
348
349
350
351
352
353
354
355 public boolean compareDocument(Document document,
356 Document comparingDocument, String digestAlgorithm)
357 throws Exception {
358 return Arrays.equals(getDigest(document, digestAlgorithm), getDigest(
359 comparingDocument, digestAlgorithm));
360 }
361
362
363
364
365
366
367
368
369
370
371 public boolean compareAttribute(Attr attribute, Attr comparingAttribute,
372 String digestAlgorithm) throws Exception {
373 return Arrays.equals(getDigest(attribute, digestAlgorithm), getDigest(
374 comparingAttribute, digestAlgorithm));
375 }
376
377
378 public static final String md5DigestAlgorithm = "MD5";
379
380
381 public static final String shaDigestAlgorithm = "SHA";
382
383
384 public static final String sha1DigestAlgorithm = "SHA1";
385 }