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;
21
22/**
23 * {@code MessageDigestSpi} is the Service Provider Interface (SPI) definition
24 * for {@link MessageDigest}. Examples of digest algorithms are MD5 and SHA. A
25 * digest is a secure one way hash function for a stream of bytes. It acts like
26 * a fingerprint for a stream of bytes.
27 *
28 * @see MessageDigest
29 */
30public abstract class MessageDigestSpi {
31
32    /**
33     * Returns the engine digest length in bytes. If the implementation does not
34     * implement this function {@code 0} is returned.
35     *
36     * @return the digest length in bytes, or {@code 0}.
37     */
38    protected int engineGetDigestLength() {
39        return 0;
40    }
41
42    /**
43     * Updates this {@code MessageDigestSpi} using the given {@code byte}.
44     *
45     * @param input
46     *            the {@code byte} to update this {@code MessageDigestSpi} with.
47     * @see #engineReset()
48     */
49    protected abstract void engineUpdate(byte input);
50
51    /**
52     * Updates this {@code MessageDigestSpi} using the given {@code byte[]}.
53     *
54     * @param input
55     *            the {@code byte} array.
56     * @param offset
57     *            the index of the first byte in {@code input} to update from.
58     * @param len
59     *            the number of bytes in {@code input} to update from.
60     * @throws IllegalArgumentException
61     *             if {@code offset} or {@code len} are not valid in respect to
62     *             {@code input}.
63     */
64    protected abstract void engineUpdate(byte[] input, int offset, int len);
65
66    /**
67     * Updates this {@code MessageDigestSpi} using the given {@code input}.
68     *
69     * @param input
70     *            the {@code ByteBuffer}.
71     */
72    protected void engineUpdate(ByteBuffer input) {
73        if (!input.hasRemaining()) {
74            return;
75        }
76        byte[] tmp;
77        if (input.hasArray()) {
78            tmp = input.array();
79            int offset = input.arrayOffset();
80            int position = input.position();
81            int limit = input.limit();
82            engineUpdate(tmp, offset+position, limit - position);
83            input.position(limit);
84        } else {
85            tmp = new byte[input.limit() - input.position()];
86            input.get(tmp);
87            engineUpdate(tmp, 0, tmp.length);
88        }
89    }
90
91    /**
92     * Computes and returns the final hash value for this
93     * {@link MessageDigestSpi}. After the digest is computed the receiver is
94     * reset.
95     *
96     * @return the computed one way hash value.
97     * @see #engineReset()
98     */
99    protected abstract byte[] engineDigest();
100
101    /**
102     * Computes and stores the final hash value for this
103     * {@link MessageDigestSpi}. After the digest is computed the receiver is
104     * reset.
105     *
106     * @param buf
107     *            the buffer to store the result in.
108     * @param offset
109     *            the index of the first byte in {@code buf} to store in.
110     * @param len
111     *            the number of bytes allocated for the digest.
112     * @return the number of bytes written to {@code buf}.
113     * @throws DigestException
114     *             if an error occures.
115     * @throws IllegalArgumentException
116     *             if {@code offset} or {@code len} are not valid in respect to
117     *             {@code buf}.
118     * @see #engineReset()
119     */
120    protected int engineDigest(byte[] buf, int offset, int len) throws DigestException {
121        if (len < engineGetDigestLength()) {
122            engineReset();
123            throw new DigestException("The value of len parameter is less than the actual digest length");
124        }
125        if (offset < 0) {
126            engineReset();
127            throw new DigestException("offset < 0");
128        }
129        if (offset + len > buf.length) {
130            engineReset();
131            throw new DigestException("offset + len > buf.length");
132        }
133        byte[] tmp = engineDigest();
134        if (len < tmp.length) {
135            throw new DigestException("The value of len parameter is less than the actual digest length");
136        }
137        System.arraycopy(tmp, 0, buf, offset, tmp.length);
138        return tmp.length;
139    }
140
141    /**
142     * Puts this {@code MessageDigestSpi} back in an initial state, such that it
143     * is ready to compute a one way hash value.
144     */
145    protected abstract void engineReset();
146
147    @Override
148    public Object clone() throws CloneNotSupportedException {
149        return super.clone();
150    }
151}
152