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. The
136     * {@code provider} supplied does not have to be registered.
137     *
138     * @param algorithm
139     *            the name of the algorithm to use
140     * @param provider
141     *            the provider
142     * @return a new instance of {@code MessageDigest} that utilizes the
143     *         specified algorithm from the specified provider
144     * @throws NoSuchAlgorithmException
145     *             if the specified algorithm is not available
146     * @throws NullPointerException
147     *             if {@code algorithm} is {@code null}
148     * @throws IllegalArgumentException if {@code provider == null}
149     */
150    public static MessageDigest getInstance(String algorithm, Provider provider)
151            throws NoSuchAlgorithmException {
152        if (provider == null) {
153            throw new IllegalArgumentException("provider == null");
154        }
155        if (algorithm == null) {
156            throw new NullPointerException("algorithm == null");
157        }
158        Object spi = ENGINE.getInstance(algorithm, provider, null);
159        if (spi instanceof MessageDigest) {
160            MessageDigest result = (MessageDigest) spi;
161            result.algorithm = algorithm;
162            result.provider = provider;
163            return result;
164        }
165        return new MessageDigestImpl((MessageDigestSpi) spi, provider, algorithm);
166    }
167
168    /**
169     * Puts this {@code MessageDigest} back in an initial state, such that it is
170     * ready to compute a one way hash value.
171     */
172    public void reset() {
173        engineReset();
174    }
175
176    /**
177     * Updates this {@code MessageDigest} using the given {@code byte}.
178     *
179     * @param arg0
180     *            the {@code byte} to update this {@code MessageDigest} with
181     * @see #reset()
182     */
183    public void update(byte arg0) {
184        engineUpdate(arg0);
185    }
186
187    /**
188     * Updates this {@code MessageDigest} using the given {@code byte[]}.
189     *
190     * @param input
191     *            the {@code byte} array
192     * @param offset
193     *            the index of the first byte in {@code input} to update from
194     * @param len
195     *            the number of bytes in {@code input} to update from
196     * @throws IllegalArgumentException
197     *             if {@code offset} or {@code len} are not valid in respect to
198     *             {@code input}
199     */
200    public void update(byte[] input, int offset, int len) {
201        if (input == null ||
202        // offset < 0 || len < 0 ||
203                // checks for negative values are commented out intentionally
204                // see HARMONY-1120 for details
205                (long) offset + (long) len > input.length) {
206            throw new IllegalArgumentException();
207        }
208        engineUpdate(input, offset, len);
209    }
210
211    /**
212     * Updates this {@code MessageDigest} using the given {@code byte[]}.
213     *
214     * @param input
215     *            the {@code byte} array
216     * @throws NullPointerException
217     *             if {@code input} is {@code null}
218     */
219    public void update(byte[] input) {
220        if (input == null) {
221            throw new NullPointerException("input == null");
222        }
223        engineUpdate(input, 0, input.length);
224    }
225
226    /**
227     * Computes and returns the final hash value for this {@link MessageDigest}.
228     * After the digest is computed the receiver is reset.
229     *
230     * @return the computed one way hash value
231     * @see #reset
232     */
233    public byte[] digest() {
234        return engineDigest();
235    }
236
237    /**
238     * Computes and stores the final hash value for this {@link MessageDigest}.
239     * After the digest is computed the receiver is reset.
240     *
241     * @param buf
242     *            the buffer to store the result
243     * @param offset
244     *            the index of the first byte in {@code buf} to store
245     * @param len
246     *            the number of bytes allocated for the digest
247     * @return the number of bytes written to {@code buf}
248     * @throws DigestException
249     *             if an error occurs
250     * @throws IllegalArgumentException
251     *             if {@code offset} or {@code len} are not valid in respect to
252     *             {@code buf}
253     * @see #reset()
254     */
255    public int digest(byte[] buf, int offset, int len) throws DigestException {
256        if (buf == null ||
257        // offset < 0 || len < 0 ||
258                // checks for negative values are commented out intentionally
259                // see HARMONY-1148 for details
260                (long) offset + (long) len > buf.length) {
261            throw new IllegalArgumentException();
262        }
263        return engineDigest(buf, offset, len);
264    }
265
266    /**
267     * Performs the final update and then computes and returns the final hash
268     * value for this {@link MessageDigest}. After the digest is computed the
269     * receiver is reset.
270     *
271     * @param input
272     *            the {@code byte} array
273     * @return the computed one way hash value
274     * @see #reset()
275     */
276    public byte[] digest(byte[] input) {
277        update(input);
278        return digest();
279    }
280
281    /**
282     * Returns a string containing a concise, human-readable description of this
283     * {@code MessageDigest} including the name of its algorithm.
284     *
285     * @return a printable representation for this {@code MessageDigest}
286     */
287    @Override
288    public String toString() {
289        return "MESSAGE DIGEST " + algorithm;
290    }
291
292    /**
293     * Indicates whether to digest are equal by performing a simply
294     * byte-per-byte compare of the two digests.
295     *
296     * @param digesta
297     *            the first digest to be compared
298     * @param digestb
299     *            the second digest to be compared
300     * @return {@code true} if the two hashes are equal, {@code false} otherwise
301     */
302    public static boolean isEqual(byte[] digesta, byte[] digestb) {
303        if (digesta.length != digestb.length) {
304            return false;
305        }
306        // Perform a constant time comparison to avoid timing attacks.
307        int v = 0;
308        for (int i = 0; i < digesta.length; i++) {
309            v |= (digesta[i] ^ digestb[i]);
310        }
311        return v == 0;
312    }
313
314    /**
315     * Returns the name of the algorithm of this {@code MessageDigest}.
316     *
317     * @return the name of the algorithm of this {@code MessageDigest}
318     */
319    public final String getAlgorithm() {
320        return algorithm;
321    }
322
323    /**
324     * Returns the provider associated with this {@code MessageDigest}.
325     *
326     * @return the provider associated with this {@code MessageDigest}
327     */
328    public final Provider getProvider() {
329        return provider;
330    }
331
332    /**
333     * Returns the engine digest length in bytes. If the implementation does not
334     * implement this function or is not an instance of {@code Cloneable},
335     * {@code 0} is returned.
336     *
337     * @return the digest length in bytes, or {@code 0}
338     */
339    public final int getDigestLength() {
340        int l = engineGetDigestLength();
341        if (l != 0) {
342            return l;
343        }
344        if (!(this instanceof Cloneable)) {
345            return 0;
346        }
347        try {
348            MessageDigest md = (MessageDigest) clone();
349            return md.digest().length;
350        } catch (CloneNotSupportedException e) {
351            return 0;
352        }
353    }
354
355    /**
356     * Updates this {@code MessageDigest} using the given {@code input}.
357     *
358     * @param input
359     *            the {@code ByteBuffer}
360     */
361    public final void update(ByteBuffer input) {
362        engineUpdate(input);
363    }
364
365    /**
366     *
367     * The internal MessageDigest implementation
368     *
369     */
370    private static class MessageDigestImpl extends MessageDigest {
371
372        // MessageDigestSpi implementation
373        private MessageDigestSpi spiImpl;
374
375        // MessageDigestImpl ctor
376        private MessageDigestImpl(MessageDigestSpi messageDigestSpi,
377                Provider provider, String algorithm) {
378            super(algorithm);
379            super.provider = provider;
380            spiImpl = messageDigestSpi;
381        }
382
383        // engineReset() implementation
384        @Override
385        protected void engineReset() {
386            spiImpl.engineReset();
387        }
388
389        // engineDigest() implementation
390        @Override
391        protected byte[] engineDigest() {
392            return spiImpl.engineDigest();
393        }
394
395        // engineGetDigestLength() implementation
396        @Override
397        protected int engineGetDigestLength() {
398            return spiImpl.engineGetDigestLength();
399        }
400
401        // engineUpdate() implementation
402        @Override
403        protected void engineUpdate(byte arg0) {
404            spiImpl.engineUpdate(arg0);
405        }
406
407        // engineUpdate() implementation
408        @Override
409        protected void engineUpdate(byte[] arg0, int arg1, int arg2) {
410            spiImpl.engineUpdate(arg0, arg1, arg2);
411        }
412
413        // Returns a clone if the spiImpl is cloneable
414        @Override
415        public Object clone() throws CloneNotSupportedException {
416            MessageDigestSpi spi = (MessageDigestSpi) spiImpl.clone();
417            return new MessageDigestImpl(spi, getProvider(), getAlgorithm());
418        }
419    }
420}
421