1 package jsdsi;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.InputStream;
5 import java.net.URI;
6 import java.security.MessageDigest;
7 import java.security.NoSuchAlgorithmException;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
11
12 import jsdsi.sexp.SexpList;
13 import jsdsi.sexp.SexpParseException;
14 import jsdsi.sexp.SexpUtil;
15 import jsdsi.util.DigestAlgoEnum;
16 import jsdsi.util.DigestUtils;
17
18 /***
19 * A cryptographic hash.
20 *
21 * @author Sameer Ajmani
22 * @author Sean Radford
23 * @version $Revision: 1.9.2.1 $ $Date: 2005/11/08 03:12:52 $
24 *
25 * @todo add verify method(s)
26 */
27 public class Hash extends Obj {
28
29 private static final long serialVersionUID = -1318052205486635960L;
30
31 /***
32 * Hash algorithm.
33 */
34 private transient final DigestAlgoEnum digest;
35
36 /***
37 * Hash value.
38 */
39 private transient final byte[] data;
40
41 /***
42 * URIs of the hashed data.
43 */
44 private transient final URI[] uris;
45
46 /***
47 * Creates a new <code>Hash</code>.
48 *
49 * @param a hash algorithm
50 * @param d hash value (<i>not</i> the data to hash)
51 * @param u URIs of the hashed data (may be <code>null</code>).
52 *
53 */
54 public Hash(DigestAlgoEnum a, byte[] d, URI[] u) {
55 assert(a != null) : "null algo";
56 assert(d != null) : "null data";
57 this.digest = a;
58 this.data = d;
59 this.uris = u;
60 }
61
62 /***
63 * Creates a new <code>Hash</code>.
64 *
65 * @param a hash algorithm.
66 * @param o JSDSI object to hash.
67 * @param u URIs of the hashed data (may be <code>null</code>).
68 *
69 */
70 public Hash(DigestAlgoEnum a, Obj o, URI[] u) {
71 assert(a != null) : "null algo";
72 assert(o != null) : "null object";
73 this.digest = a;
74 this.data = DigestUtils.getDigest(a).digest(o.toByteArray());
75 this.uris = u;
76 }
77
78 /***
79 * Creates a new <code>Hash</code>.
80 *
81 * @param a SPKI hash algorithm name
82 * @param d hash value (<i>not</i> the data to hash)
83 * @param u URIs of the hashed data
84 *
85 * @deprecated use {@link #Hash(jsdsi.util.DigestAlgoEnum, byte[], URI[])}
86 */
87 public Hash(String a, byte[] d, URI[] u) {
88 this(DigestAlgoEnum.fromSpki(a), d, u);
89 }
90
91 /***
92 * Creates a new <code>Hash</code>.
93 *
94 * @param a hash algorithm name.
95 * @param o object to hash.
96 * @param u URIs of the hashed data.
97 *
98 * @deprecated use {@link #Hash(jsdsi.util.DigestAlgoEnum, Obj, URI[])}
99 */
100 public Hash(String a, Obj o, URI[] u) {
101 this(DigestAlgoEnum.fromSpki(a), o, u);
102 }
103
104 /***
105 * Creates a new <code>Hash</code> from an algorithm name and a byte array
106 * that contains a hash value.
107 *
108 * @param a name of the hash algorithm used.
109 * @param d the value of the hash (<i>not</i> the data to hash).
110 *
111 * @deprecated use {@link #Hash(jsdsi.util.DigestAlgoEnum, byte[], java.net.URI[])}
112 */
113 public Hash(String a, byte[] d) {
114 this(a, d, null);
115 }
116
117 /***
118 * Creates a new <code>Hash</code> from an algorithm name and an object.
119 *
120 * @param a name of the hash algorithm used.
121 * @param o JSDSI object to calculate the hash value from.
122 *
123 * @deprecated use {@link #Hash(jsdsi.util.DigestAlgoEnum, jsdsi.Obj, java.net.URI[])}
124 */
125 public Hash(String a, Obj o) {
126 this(a, o, null);
127 }
128
129
130 /***
131 * Creates a new <code>Hash</code> using a given algorithm name, a
132 * value to hash, and an array of URIs.
133 *
134 * @param a hash algorithm
135 * @param d data to hash
136 * @param u URIs of the data to hash
137 * @return the created Hash object (may be <code>null</code>)
138 */
139 public static Hash create(DigestAlgoEnum a, byte[] d, URI[] u) {
140 return create(a, new ByteArrayInputStream(d), u);
141 }
142
143 /***
144 * Creates a new <code>Hash</code> of the data from the given
145 * InputStream, using the given algorithm
146 * @param a hash algorithm
147 * @param is data to hash
148 * @param u URIs of the data being hashed (may be <code>null</code>)
149 * @return the created Hash object
150 */
151 public static Hash create(DigestAlgoEnum a, InputStream is, URI[] u) {
152 assert(a != null) : "null algo";
153 assert(is != null) : "null data";
154 MessageDigest digester = DigestUtils.getDigest(a);
155 Iterator it = new jsdsi.util.InputStreamIterator(is);
156 while (it.hasNext()) {
157 digester.update( (byte[]) it.next() );
158 }
159 byte[] value = digester.digest();
160 return new Hash(a, value, u);
161 }
162
163 /***
164 * Creates a new <code>Hash</code> using a given algorithm name, a
165 * value to hash, and an array of URIs.
166 *
167 * @param a hash algorithm name
168 * @param d data to hash
169 * @param u URIs of the data to hash
170 * @return the created Hash object
171 *
172 * @deprecated use {@link Hash#create(jsdsi.util.DigestAlgoEnum, byte[], java.net.URI[])}
173 */
174 public static Hash create(String a,
175 byte[] d,
176 URI[] u) throws NoSuchAlgorithmException {
177 return create(DigestAlgoEnum.fromJdk(a),
178 new ByteArrayInputStream(d), u);
179 }
180
181 /***
182 * Creates a new <code>Hash</code> of the data from the given
183 * InputStream, using the given algorithm.
184 * @param a hash algorithm name
185 * @param is data to hash
186 * @param u URIs of the data being hashed
187 * @return the created Hash object
188 *
189 * @deprecated use {@link Hash#create(jsdsi.util.DigestAlgoEnum, java.io.InputStream, java.net.URI[])}
190 */
191 public static Hash create(String a,
192 InputStream is,
193 URI[] u) throws NoSuchAlgorithmException {
194 return create(DigestAlgoEnum.fromJdk(a), is, u);
195 }
196
197 /***
198 * @return the digest for this Hash
199 */
200 public DigestAlgoEnum getDigest() {
201 return this.digest;
202 }
203
204 /***
205 * @return the JDK name of the hash algorithm.
206 */
207 public String getAlgorithm() {
208 return this.digest.jdkName();
209 }
210
211 /***
212 * @return the hash value.
213 */
214 public byte[] getData() {
215 return data;
216 }
217
218 /***
219 * @return the URIs of the hashed data.
220 */
221 public URI[] getURIs() {
222 return uris;
223 }
224
225 public boolean equals(Object o) {
226 if (o instanceof Hash) {
227 Hash h = (Hash) o;
228 return this.digest.equals(h.digest)
229 && java.util.Arrays.equals(data, h.data)
230 && Util.equals(uris, h.uris);
231 }
232 return false;
233 }
234
235 /***
236 * @see java.lang.Object#hashCode()
237 */
238 public int hashCode() {
239 return this.digest.hashCode()
240 ^ Util.hashCode(this.data)
241 ^ Util.hashCode(this.uris);
242 }
243
244 public SexpList toSexp() {
245 List l = new ArrayList(3);
246 l.add(SexpUtil.toSexp(this.digest.spkiName()));
247 l.add(SexpUtil.toSexp(getData()));
248 if (getURIs() != null) {
249 l.add(SexpUtil.toSexp(getURIs()));
250 }
251 return SexpUtil.toSexp("hash", l);
252 }
253
254 public static Hash parseHash(SexpList l) throws SexpParseException {
255 Iterator hbody = SexpUtil.getBody(l);
256 String algo = SexpUtil.getNextString(hbody, "hash algo");
257 DigestAlgoEnum digest = calculateDigestEnum(algo);
258 byte[] data = SexpUtil.getNextByteArray(hbody, "hash data");
259 SexpUtil.checkDone(hbody, "hash"); // TODO: support URIs
260 return new Hash(digest, data, null);
261 }
262
263 /***
264 * Temporary method to cope with legacy certificates/signatures
265 * which incorrectly have JDK algorithm names in their SExpression.
266 * @param algo
267 * @return
268 * @todo Method should be removed in the future when legacy data is
269 * no longer an issue
270 */
271 static DigestAlgoEnum calculateDigestEnum(String algo) {
272 try {
273 return DigestAlgoEnum.fromSpki(algo);
274 } catch (JsdsiRuntimeException e) {
275 // was not a SPKI algo name, so was it a legacy JDK one...
276 return DigestAlgoEnum.fromJdk(algo);
277 }
278 }
279 }
This page was automatically generated by Maven