View Javadoc
1   /*
2    * Kuali Coeus, a comprehensive research administration system for higher education.
3    * 
4    * Copyright 2005-2015 Kuali, Inc.
5    * 
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Affero General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Affero General Public License for more details.
15   * 
16   * You should have received a copy of the GNU Affero General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.kuali.coeus.s2sgen.impl.hash;
20  
21  import org.apache.xml.security.algorithms.MessageDigestAlgorithm;
22  import org.apache.xml.security.c14n.CanonicalizationException;
23  import org.apache.xml.security.c14n.Canonicalizer;
24  import org.apache.xml.security.c14n.InvalidCanonicalizerException;
25  import org.apache.xml.security.signature.XMLSignatureException;
26  import org.apache.xml.security.utils.Base64;
27  import org.apache.xml.security.utils.DigesterOutputStream;
28  import org.kuali.coeus.s2sgen.api.core.S2SException;
29  import org.kuali.coeus.s2sgen.impl.util.XPathExecutor;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  import org.w3c.dom.Document;
33  import org.w3c.dom.Node;
34  
35  import javax.xml.transform.TransformerException;
36  
37  /**
38   * This is a convenience object that simplifies the hashing processing to one
39   * method call.
40   * 
41   * @author David Wong
42   */
43  public class GrantApplicationHash {
44  
45  	private static final Logger log = LoggerFactory.getLogger(GrantApplicationHash.class
46              .getName());
47  
48  	static java.security.MessageDigest messageDigester = null;
49  
50  	static {
51  		org.apache.xml.security.Init.init();
52  		try {
53  			messageDigester = java.security.MessageDigest.getInstance("SHA-1");
54  		} catch (Exception ex) {
55  			log.error(
56  					"Unable to get instance of java.security.MessageDigester",
57  					ex);
58  		}
59  	}
60  
61  	/**
62  	 * Added private constructor to prevent creation by user.
63  	 */
64  	private GrantApplicationHash() {
65  
66  	}
67  
68  	/**
69  	 * Computes the hash value for the Grants.gov application XML.
70  	 * 
71  	 * @param xml
72  	 *            The Grants.gov application XML.
73  	 * @return The SHA-1 hash value of &lt;grant:forms&gt; tag inside the
74  	 *         application XML.
75  	 * @throws Exception
76  	 *             When the XML cannot be parsed.
77  	 */
78  	public final static String computeGrantFormsHash(String xml) throws S2SException {
79  		GrantApplicationXpath xpath;
80          try {
81              xpath = new GrantApplicationXpath(xml);
82              return _hash(xpath);
83          }catch (Exception e) {
84              log.error(e.getMessage(), e);
85              throw new S2SException(e.getMessage(),e);
86          }
87  	}
88  
89  	/**
90  	 * Computes the hash of an binary attachment.
91  	 * 
92  	 * @param attachment
93  	 * @return The SHA-1 hash value of the attachment byte array.
94  	 * @throws Exception
95  	 */
96  	public final static String computeAttachmentHash(byte[] attachment) {
97  
98  		byte[] rawDigest = messageDigester.digest(attachment);
99  
100 		return Base64.encode(rawDigest);
101 
102 	}
103 
104 	/**
105 	 * Computes the hash value for the Grants.gov application XML.
106 	 * 
107 	 * @param xpath
108 	 *            An xpath object holding the Grants.gov application XML.
109 	 * @return The SHA-1 hash value of &lt;grant:forms&gt; tag inside the
110 	 *         application XML.
111 	 * @throws Exception
112 	 *             When the XML cannot be parsed.
113 	 */
114 	public final static String computeGrantFormsHash(GrantApplicationXpath xpath)
115 			throws Exception {
116 		return _hash(xpath);
117 	}
118 
119 	/**
120 	 * Computes the hash value for the Grants.gov application XML.
121 	 * 
122 	 * @param xml
123 	 *            The Grants.gov application XML.
124 	 * @return The SHA-1 hash value of &lt;grant:forms&gt; tag inside the
125 	 *         application XML.
126 	 * @throws Exception
127 	 *             When the XML cannot be parsed.
128 	 */
129 	public final static String computeGrantFormsHash(Document xml) throws Exception {
130 		XPathExecutor executor = new XPathExecutor(null);
131 		executor.setDoc(xml);
132 		GrantApplicationXpath xpath = new GrantApplicationXpath(null);
133 		xpath.setExecutor(executor);
134 		return _hash(xpath);
135 	}
136 
137 	private static String _hash(GrantApplicationXpath xpath)
138 			throws TransformerException, XMLSignatureException,
139 			InvalidCanonicalizerException, CanonicalizationException {
140 		Node formsNode = xpath.getFormsNode();
141 		DigesterOutputStream digester = _createDigesterOutputStream(xpath
142 				.getExecutor().getDoc());
143 		Canonicalizer canonicalizer = Canonicalizer
144 				.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
145 		canonicalizer.setWriter(digester);
146 		canonicalizer.canonicalizeSubtree(formsNode);
147 		byte[] hash = digester.getDigestValue();
148 		return Base64.encode(hash);
149 	}
150 
151 	private static DigesterOutputStream _createDigesterOutputStream(Document doc)
152 			throws XMLSignatureException {
153 		DigesterOutputStream stream = null;
154 		if (doc != null) {
155 			stream = new DigesterOutputStream(MessageDigestAlgorithm
156 					.getInstance(doc,
157 							MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1));
158 		}
159 		return stream;
160 	}
161 }