1/* 2 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package java.security; 27 28import java.nio.ByteBuffer; 29 30import sun.security.jca.JCAUtil; 31 32/** 33 * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) 34 * for the <code>MessageDigest</code> class, which provides the functionality 35 * of a message digest algorithm, such as MD5 or SHA. Message digests are 36 * secure one-way hash functions that take arbitrary-sized data and output a 37 * fixed-length hash value. 38 * 39 * <p> All the abstract methods in this class must be implemented by a 40 * cryptographic service provider who wishes to supply the implementation 41 * of a particular message digest algorithm. 42 * 43 * <p> Implementations are free to implement the Cloneable interface. 44 * 45 * @author Benjamin Renaud 46 * 47 * 48 * @see MessageDigest 49 */ 50 51public abstract class MessageDigestSpi { 52 53 // for re-use in engineUpdate(ByteBuffer input) 54 private byte[] tempArray; 55 56 /** 57 * Returns the digest length in bytes. 58 * 59 * <p>This concrete method has been added to this previously-defined 60 * abstract class. (For backwards compatibility, it cannot be abstract.) 61 * 62 * <p>The default behavior is to return 0. 63 * 64 * <p>This method may be overridden by a provider to return the digest 65 * length. 66 * 67 * @return the digest length in bytes. 68 * 69 * @since 1.2 70 */ 71 protected int engineGetDigestLength() { 72 return 0; 73 } 74 75 /** 76 * Updates the digest using the specified byte. 77 * 78 * @param input the byte to use for the update. 79 */ 80 protected abstract void engineUpdate(byte input); 81 82 /** 83 * Updates the digest using the specified array of bytes, 84 * starting at the specified offset. 85 * 86 * @param input the array of bytes to use for the update. 87 * 88 * @param offset the offset to start from in the array of bytes. 89 * 90 * @param len the number of bytes to use, starting at 91 * <code>offset</code>. 92 */ 93 protected abstract void engineUpdate(byte[] input, int offset, int len); 94 95 /** 96 * Update the digest using the specified ByteBuffer. The digest is 97 * updated using the <code>input.remaining()</code> bytes starting 98 * at <code>input.position()</code>. 99 * Upon return, the buffer's position will be equal to its limit; 100 * its limit will not have changed. 101 * 102 * @param input the ByteBuffer 103 * @since 1.5 104 */ 105 protected void engineUpdate(ByteBuffer input) { 106 if (input.hasRemaining() == false) { 107 return; 108 } 109 if (input.hasArray()) { 110 byte[] b = input.array(); 111 int ofs = input.arrayOffset(); 112 int pos = input.position(); 113 int lim = input.limit(); 114 engineUpdate(b, ofs + pos, lim - pos); 115 input.position(lim); 116 } else { 117 int len = input.remaining(); 118 int n = JCAUtil.getTempArraySize(len); 119 if ((tempArray == null) || (n > tempArray.length)) { 120 tempArray = new byte[n]; 121 } 122 while (len > 0) { 123 int chunk = Math.min(len, tempArray.length); 124 input.get(tempArray, 0, chunk); 125 engineUpdate(tempArray, 0, chunk); 126 len -= chunk; 127 } 128 } 129 } 130 131 /** 132 * Completes the hash computation by performing final 133 * operations such as padding. Once <code>engineDigest</code> has 134 * been called, the engine should be reset (see 135 * {@link #engineReset() engineReset}). 136 * Resetting is the responsibility of the 137 * engine implementor. 138 * 139 * @return the array of bytes for the resulting hash value. 140 */ 141 protected abstract byte[] engineDigest(); 142 143 /** 144 * Completes the hash computation by performing final 145 * operations such as padding. Once <code>engineDigest</code> has 146 * been called, the engine should be reset (see 147 * {@link #engineReset() engineReset}). 148 * Resetting is the responsibility of the 149 * engine implementor. 150 * 151 * This method should be abstract, but we leave it concrete for 152 * binary compatibility. Knowledgeable providers should override this 153 * method. 154 * 155 * @param buf the output buffer in which to store the digest 156 * 157 * @param offset offset to start from in the output buffer 158 * 159 * @param len number of bytes within buf allotted for the digest. 160 * Both this default implementation and the SUN provider do not 161 * return partial digests. The presence of this parameter is solely 162 * for consistency in our API's. If the value of this parameter is less 163 * than the actual digest length, the method will throw a DigestException. 164 * This parameter is ignored if its value is greater than or equal to 165 * the actual digest length. 166 * 167 * @return the length of the digest stored in the output buffer. 168 * 169 * @exception DigestException if an error occurs. 170 * 171 * @since 1.2 172 */ 173 protected int engineDigest(byte[] buf, int offset, int len) 174 throws DigestException { 175 176 byte[] digest = engineDigest(); 177 if (len < digest.length) 178 throw new DigestException("partial digests not returned"); 179 if (buf.length - offset < digest.length) 180 throw new DigestException("insufficient space in the output " 181 + "buffer to store the digest"); 182 System.arraycopy(digest, 0, buf, offset, digest.length); 183 return digest.length; 184 } 185 186 /** 187 * Resets the digest for further use. 188 */ 189 protected abstract void engineReset(); 190 191 /** 192 * Returns a clone if the implementation is cloneable. 193 * 194 * @return a clone if the implementation is cloneable. 195 * 196 * @exception CloneNotSupportedException if this is called on an 197 * implementation that does not support <code>Cloneable</code>. 198 */ 199 public Object clone() throws CloneNotSupportedException { 200 if (this instanceof Cloneable) { 201 return super.clone(); 202 } else { 203 throw new CloneNotSupportedException(); 204 } 205 } 206} 207