001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.security;
027
028 import java.nio.ByteBuffer;
029
030 import sun.security.jca.JCAUtil;
031
032 /**
033 * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
034 * for the <code>MessageDigest</code> class, which provides the functionality
035 * of a message digest algorithm, such as MD5 or SHA. Message digests are
036 * secure one-way hash functions that take arbitrary-sized data and output a
037 * fixed-length hash value.
038 *
039 * <p> All the abstract methods in this class must be implemented by a
040 * cryptographic service provider who wishes to supply the implementation
041 * of a particular message digest algorithm.
042 *
043 * <p> Implementations are free to implement the Cloneable interface.
044 *
045 * @author Benjamin Renaud
046 *
047 * @version 1.23, 05/05/07
048 *
049 * @see MessageDigest
050 */
051
052 public abstract class MessageDigestSpi {
053
054 // for re-use in engineUpdate(ByteBuffer input)
055 private byte[] tempArray;
056
057 /**
058 * Returns the digest length in bytes.
059 *
060 * <p>This concrete method has been added to this previously-defined
061 * abstract class. (For backwards compatibility, it cannot be abstract.)
062 *
063 * <p>The default behavior is to return 0.
064 *
065 * <p>This method may be overridden by a provider to return the digest
066 * length.
067 *
068 * @return the digest length in bytes.
069 *
070 * @since 1.2
071 */
072 protected int engineGetDigestLength() {
073 return 0;
074 }
075
076 /**
077 * Updates the digest using the specified byte.
078 *
079 * @param input the byte to use for the update.
080 */
081 protected abstract void engineUpdate(byte input);
082
083 /**
084 * Updates the digest using the specified array of bytes,
085 * starting at the specified offset.
086 *
087 * @param input the array of bytes to use for the update.
088 *
089 * @param offset the offset to start from in the array of bytes.
090 *
091 * @param len the number of bytes to use, starting at
092 * <code>offset</code>.
093 */
094 protected abstract void engineUpdate(byte[] input, int offset,
095 int len);
096
097 /**
098 * Update the digest using the specified ByteBuffer. The digest is
099 * updated using the <code>input.remaining()</code> bytes starting
100 * at <code>input.position()</code>.
101 * Upon return, the buffer's position will be equal to its limit;
102 * its limit will not have changed.
103 *
104 * @param input the ByteBuffer
105 * @since 1.5
106 */
107 protected void engineUpdate(ByteBuffer input) {
108 if (input.hasRemaining() == false) {
109 return;
110 }
111 if (input.hasArray()) {
112 byte[] b = input.array();
113 int ofs = input.arrayOffset();
114 int pos = input.position();
115 int lim = input.limit();
116 engineUpdate(b, ofs + pos, lim - pos);
117 input.position(lim);
118 } else {
119 int len = input.remaining();
120 int n = JCAUtil.getTempArraySize(len);
121 if ((tempArray == null) || (n > tempArray.length)) {
122 tempArray = new byte[n];
123 }
124 while (len > 0) {
125 int chunk = Math.min(len, tempArray.length);
126 input.get(tempArray, 0, chunk);
127 engineUpdate(tempArray, 0, chunk);
128 len -= chunk;
129 }
130 }
131 }
132
133 /**
134 * Completes the hash computation by performing final
135 * operations such as padding. Once <code>engineDigest</code> has
136 * been called, the engine should be reset (see
137 * {@link #engineReset() engineReset}).
138 * Resetting is the responsibility of the
139 * engine implementor.
140 *
141 * @return the array of bytes for the resulting hash value.
142 */
143 protected abstract byte[] engineDigest();
144
145 /**
146 * Completes the hash computation by performing final
147 * operations such as padding. Once <code>engineDigest</code> has
148 * been called, the engine should be reset (see
149 * {@link #engineReset() engineReset}).
150 * Resetting is the responsibility of the
151 * engine implementor.
152 *
153 * This method should be abstract, but we leave it concrete for
154 * binary compatibility. Knowledgeable providers should override this
155 * method.
156 *
157 * @param buf the output buffer in which to store the digest
158 *
159 * @param offset offset to start from in the output buffer
160 *
161 * @param len number of bytes within buf allotted for the digest.
162 * Both this default implementation and the SUN provider do not
163 * return partial digests. The presence of this parameter is solely
164 * for consistency in our API's. If the value of this parameter is less
165 * than the actual digest length, the method will throw a DigestException.
166 * This parameter is ignored if its value is greater than or equal to
167 * the actual digest length.
168 *
169 * @return the length of the digest stored in the output buffer.
170 *
171 * @exception DigestException if an error occurs.
172 *
173 * @since 1.2
174 */
175 protected int engineDigest(byte[] buf, int offset, int len)
176 throws DigestException {
177
178 byte[] digest = engineDigest();
179 if (len < digest.length)
180 throw new DigestException("partial digests not returned");
181 if (buf.length - offset < digest.length)
182 throw new DigestException(
183 "insufficient space in the output "
184 + "buffer to store the digest");
185 System.arraycopy(digest, 0, buf, offset, digest.length);
186 return digest.length;
187 }
188
189 /**
190 * Resets the digest for further use.
191 */
192 protected abstract void engineReset();
193
194 /**
195 * Returns a clone if the implementation is cloneable.
196 *
197 * @return a clone if the implementation is cloneable.
198 *
199 * @exception CloneNotSupportedException if this is called on an
200 * implementation that does not support <code>Cloneable</code>.
201 */
202 public Object clone() throws CloneNotSupportedException {
203 if (this instanceof Cloneable) {
204 return super .clone();
205 } else {
206 throw new CloneNotSupportedException();
207 }
208 }
209 }
|