MessageDigest.java revision 86acc043d3334651ee26c65467d78d6cefedd397
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.nio.ByteBuffer;
21import org.apache.harmony.security.fortress.Engine;
22
23/**
24 * Uses a one-way hash function to turn an arbitrary number of bytes into a
25 * fixed-length byte sequence. The original arbitrary-length sequence is the
26 * <i>message</i>, and the fixed-length byte sequence is the <i>digest</i> or
27 * <i>message digest</i>.
28 *
29 * <h4>Sample Code</h4>
30 * <p>The basic pattern to digest an {@link java.io.InputStream} looks like this:
31 * <pre>
32 *  MessageDigest digester = MessageDigest.getInstance("MD5");
33 *  byte[] bytes = new byte[8192];
34 *  int byteCount;
35 *  while ((byteCount = in.read(bytes)) > 0) {
36 *    digester.update(bytes, 0, byteCount);
37 *  }
38 *  byte[] digest = digester.digest();
39 * </pre>
40 *
41 * <p>That is, after creating or resetting a {@code MessageDigest} you should
42 * call {@link #update(byte[],int,int)} for each block of input data, and then call {@link #digest}
43 * to get the final digest. Note that calling {@code digest} resets the {@code MessageDigest}.
44 * Advanced users who want partial digests should clone their {@code MessageDigest} before
45 * calling {@code digest}.
46 *
47 * <p>This class is not thread-safe.
48 *
49 * @see MessageDigestSpi
50 */
51public abstract class MessageDigest extends MessageDigestSpi {
52
53    // Used to access common engine functionality
54    private static final Engine ENGINE = new Engine("MessageDigest");
55
56    // The provider
57    private Provider provider;
58
59    // The algorithm.
60    private String algorithm;
61
62    /**
63     * Constructs a new instance of {@code MessageDigest} with the name of
64     * the algorithm to use.
65     *
66     * @param algorithm
67     *            the name of algorithm to use
68     */
69    protected MessageDigest(String algorithm) {
70        this.algorithm = algorithm;
71    }
72
73    /**
74     * Returns a new instance of {@code MessageDigest} that utilizes the
75     * specified algorithm.
76     *
77     * @param algorithm
78     *            the name of the algorithm to use
79     * @return a new instance of {@code MessageDigest} that utilizes the
80     *         specified algorithm
81     * @throws NoSuchAlgorithmException
82     *             if the specified algorithm is not available
83     * @throws NullPointerException
84     *             if {@code algorithm} is {@code null}
85     */
86    public static MessageDigest getInstance(String algorithm)
87            throws NoSuchAlgorithmException {
88        if (algorithm == null) {
89            throw new NullPointerException("algorithm == null");
90        }
91        Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
92        Object spi = sap.spi;
93        Provider provider = sap.provider;
94        if (spi instanceof MessageDigest) {
95            MessageDigest result = (MessageDigest) spi;
96            result.algorithm = algorithm;
97            result.provider = provider;
98            return result;
99        }
100        return new MessageDigestImpl((MessageDigestSpi) sap.spi, sap.provider, algorithm);
101    }
102
103    /**
104     * Returns a new instance of {@code MessageDigest} that utilizes the
105     * specified algorithm from the specified provider.
106     *
107     * @param algorithm
108     *            the name of the algorithm to use
109     * @param provider
110     *            the name of the provider
111     * @return a new instance of {@code MessageDigest} that utilizes the
112     *         specified algorithm from the specified provider
113     * @throws NoSuchAlgorithmException
114     *             if the specified algorithm is not available
115     * @throws NoSuchProviderException
116     *             if the specified provider is not available
117     * @throws NullPointerException
118     *             if {@code algorithm} is {@code null}
119     * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
120     */
121    public static MessageDigest getInstance(String algorithm, String provider)
122            throws NoSuchAlgorithmException, NoSuchProviderException {
123        if (provider == null || provider.isEmpty()) {
124            throw new IllegalArgumentException();
125        }
126        Provider p = Security.getProvider(provider);
127        if (p == null) {
128            throw new NoSuchProviderException(provider);
129        }
130        return getInstance(algorithm, p);
131    }
132
133    /**
134     * Returns a new instance of {@code MessageDigest} that utilizes the
135     * specified algorithm from the specified provider.
136     *
137     * @param algorithm
138     *            the name of the algorithm to use
139     * @param provider
140     *            the provider
141     * @return a new instance of {@code MessageDigest} that utilizes the
142     *         specified algorithm from the specified provider
143     * @throws NoSuchAlgorithmException
144     *             if the specified algorithm is not available
145     * @throws NullPointerException
146     *             if {@code algorithm} is {@code null}
147     * @throws IllegalArgumentException if {@code provider == null}
148     */
149    public static MessageDigest getInstance(String algorithm, Provider provider)
150            throws NoSuchAlgorithmException {
151        if (provider == null) {
152            throw new IllegalArgumentException();
153        }
154        if (algorithm == null) {
155            throw new NullPointerException("algorithm == null");
156        }
157        Object spi = ENGINE.getInstance(algorithm, provider, null);
158        if (spi instanceof MessageDigest) {
159            MessageDigest result = (MessageDigest) spi;
160            result.algorithm = algorithm;
161            result.provider = provider;
162            return result;
163        }
164        return new MessageDigestImpl((MessageDigestSpi) spi, provider, algorithm);
165    }
166
167    /**
168     * Puts this {@code MessageDigest} back in an initial state, such that it is
169     * ready to compute a one way hash value.
170     */
171    public void reset() {
172        engineReset();
173    }
174
175    /**
176     * Updates this {@code MessageDigest} using the given {@code byte}.
177     *
178     * @param arg0
179     *            the {@code byte} to update this {@code MessageDigest} with
180     * @see #reset()
181     */
182    public void update(byte arg0) {
183        engineUpdate(arg0);
184    }
185
186    /**
187     * Updates this {@code MessageDigest} using the given {@code byte[]}.
188     *
189     * @param input
190     *            the {@code byte} array
191     * @param offset
192     *            the index of the first byte in {@code input} to update from
193     * @param len
194     *            the number of bytes in {@code input} to update from
195     * @throws IllegalArgumentException
196     *             if {@code offset} or {@code len} are not valid in respect to
197     *             {@code input}
198     */
199    public void update(byte[] input, int offset, int len) {
200        if (input == null ||
201        // offset < 0 || len < 0 ||
202                // checks for negative values are commented out intentionally
203                // see HARMONY-1120 for details
204                (long) offset + (long) len > input.length) {
205            throw new IllegalArgumentException();
206        }
207        engineUpdate(input, offset, len);
208    }
209
210    /**
211     * Updates this {@code MessageDigest} using the given {@code byte[]}.
212     *
213     * @param input
214     *            the {@code byte} array
215     * @throws NullPointerException
216     *             if {@code input} is {@code null}
217     */
218    public void update(byte[] input) {
219        if (input == null) {
220            throw new NullPointerException("input == null");
221        }
222        engineUpdate(input, 0, input.length);
223    }
224
225    /**
226     * Computes and returns the final hash value for this {@link MessageDigest}.
227     * After the digest is computed the receiver is reset.
228     *
229     * @return the computed one way hash value
230     * @see #reset
231     */
232    public byte[] digest() {
233        return engineDigest();
234    }
235
236    /**
237     * Computes and stores the final hash value for this {@link MessageDigest}.
238     * After the digest is computed the receiver is reset.
239     *
240     * @param buf
241     *            the buffer to store the result
242     * @param offset
243     *            the index of the first byte in {@code buf} to store
244     * @param len
245     *            the number of bytes allocated for the digest
246     * @return the number of bytes written to {@code buf}
247     * @throws DigestException
248     *             if an error occurs
249     * @throws IllegalArgumentException
250     *             if {@code offset} or {@code len} are not valid in respect to
251     *             {@code buf}
252     * @see #reset()
253     */
254    public int digest(byte[] buf, int offset, int len) throws DigestException {
255        if (buf == null ||
256        // offset < 0 || len < 0 ||
257                // checks for negative values are commented out intentionally
258                // see HARMONY-1148 for details
259                (long) offset + (long) len > buf.length) {
260            throw new IllegalArgumentException();
261        }
262        return engineDigest(buf, offset, len);
263    }
264
265    /**
266     * Performs the final update and then computes and returns the final hash
267     * value for this {@link MessageDigest}. After the digest is computed the
268     * receiver is reset.
269     *
270     * @param input
271     *            the {@code byte} array
272     * @return the computed one way hash value
273     * @see #reset()
274     */
275    public byte[] digest(byte[] input) {
276        update(input);
277        return digest();
278    }
279
280    /**
281     * Returns a string containing a concise, human-readable description of this
282     * {@code MessageDigest} including the name of its algorithm.
283     *
284     * @return a printable representation for this {@code MessageDigest}
285     */
286    @Override
287    public String toString() {
288        return "MESSAGE DIGEST " + algorithm;
289    }
290
291    /**
292     * Indicates whether to digest are equal by performing a simply
293     * byte-per-byte compare of the two digests.
294     *
295     * @param digesta
296     *            the first digest to be compared
297     * @param digestb
298     *            the second digest to be compared
299     * @return {@code true} if the two hashes are equal, {@code false} otherwise
300     */
301    public static boolean isEqual(byte[] digesta, byte[] digestb) {
302        if (digesta.length != digestb.length) {
303            return false;
304        }
305        for (int i = 0; i < digesta.length; i++) {
306            if (digesta[i] != digestb[i]) {
307                return false;
308            }
309        }
310        return true;
311    }
312
313    /**
314     * Returns the name of the algorithm of this {@code MessageDigest}.
315     *
316     * @return the name of the algorithm of this {@code MessageDigest}
317     */
318    public final String getAlgorithm() {
319        return algorithm;
320    }
321
322    /**
323     * Returns the provider associated with this {@code MessageDigest}.
324     *
325     * @return the provider associated with this {@code MessageDigest}
326     */
327    public final Provider getProvider() {
328        return provider;
329    }
330
331    /**
332     * Returns the engine digest length in bytes. If the implementation does not
333     * implement this function or is not an instance of {@code Cloneable},
334     * {@code 0} is returned.
335     *
336     * @return the digest length in bytes, or {@code 0}
337     */
338    public final int getDigestLength() {
339        int l = engineGetDigestLength();
340        if (l != 0) {
341            return l;
342        }
343        if (!(this instanceof Cloneable)) {
344            return 0;
345        }
346        try {
347            MessageDigest md = (MessageDigest) clone();
348            return md.digest().length;
349        } catch (CloneNotSupportedException e) {
350            return 0;
351        }
352    }
353
354    @Override
355    public Object clone() throws CloneNotSupportedException {
356        if (this instanceof Cloneable) {
357            return super.clone();
358        }
359        throw new CloneNotSupportedException();
360    }
361
362    /**
363     * Updates this {@code MessageDigest} using the given {@code input}.
364     *
365     * @param input
366     *            the {@code ByteBuffer}
367     */
368    public final void update(ByteBuffer input) {
369        engineUpdate(input);
370    }
371
372    /**
373     *
374     * The internal MessageDigest implementation
375     *
376     */
377    private static class MessageDigestImpl extends MessageDigest {
378
379        // MessageDigestSpi implementation
380        private MessageDigestSpi spiImpl;
381
382        // MessageDigestImpl ctor
383        private MessageDigestImpl(MessageDigestSpi messageDigestSpi,
384                Provider provider, String algorithm) {
385            super(algorithm);
386            super.provider = provider;
387            spiImpl = messageDigestSpi;
388        }
389
390        // engineReset() implementation
391        @Override
392        protected void engineReset() {
393            spiImpl.engineReset();
394        }
395
396        // engineDigest() implementation
397        @Override
398        protected byte[] engineDigest() {
399            return spiImpl.engineDigest();
400        }
401
402        // engineGetDigestLength() implementation
403        @Override
404        protected int engineGetDigestLength() {
405            return spiImpl.engineGetDigestLength();
406        }
407
408        // engineUpdate() implementation
409        @Override
410        protected void engineUpdate(byte arg0) {
411            spiImpl.engineUpdate(arg0);
412        }
413
414        // engineUpdate() implementation
415        @Override
416        protected void engineUpdate(byte[] arg0, int arg1, int arg2) {
417            spiImpl.engineUpdate(arg0, arg1, arg2);
418        }
419
420        // Returns a clone if the spiImpl is cloneable
421        @Override
422        public Object clone() throws CloneNotSupportedException {
423            if (spiImpl instanceof Cloneable) {
424                MessageDigestSpi spi = (MessageDigestSpi) spiImpl.clone();
425                return new MessageDigestImpl(spi, getProvider(), getAlgorithm());
426            }
427
428            throw new CloneNotSupportedException();
429        }
430    }
431}
432