1 /* 2 * Copyright (c) 1997, 2013, 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 26 package java.security; 27 28 import java.nio.ByteBuffer; 29 30 import sun.security.jca.JCAUtil; 31 32 /** 33 * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) 34 * for the {@code MessageDigest} 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 * @since 1.2 47 * 48 * 49 * @see MessageDigest 50 */ 51 52 public abstract class MessageDigestSpi { 53 54 // for re-use in engineUpdate(ByteBuffer input) 55 private byte[] tempArray; 56 57 /** 58 * Returns the digest length in bytes. 59 * 60 * <p>This concrete method has been added to this previously-defined 61 * abstract class. (For backwards compatibility, it cannot be abstract.) 62 * 63 * <p>The default behavior is to return 0. 64 * 65 * <p>This method may be overridden by a provider to return the digest 66 * length. 67 * 68 * @return the digest length in bytes. 69 * 70 * @since 1.2 71 */ engineGetDigestLength()72 protected int engineGetDigestLength() { 73 return 0; 74 } 75 76 /** 77 * Updates the digest using the specified byte. 78 * 79 * @param input the byte to use for the update. 80 */ engineUpdate(byte input)81 protected abstract void engineUpdate(byte input); 82 83 /** 84 * Updates the digest using the specified array of bytes, 85 * starting at the specified offset. 86 * 87 * @param input the array of bytes to use for the update. 88 * 89 * @param offset the offset to start from in the array of bytes. 90 * 91 * @param len the number of bytes to use, starting at 92 * {@code offset}. 93 */ engineUpdate(byte[] input, int offset, int len)94 protected abstract void engineUpdate(byte[] input, int offset, int len); 95 96 /** 97 * Update the digest using the specified ByteBuffer. The digest is 98 * updated using the {@code input.remaining()} bytes starting 99 * at {@code input.position()}. 100 * Upon return, the buffer's position will be equal to its limit; 101 * its limit will not have changed. 102 * 103 * @param input the ByteBuffer 104 * @since 1.5 105 */ engineUpdate(ByteBuffer input)106 protected void engineUpdate(ByteBuffer input) { 107 if (input.hasRemaining() == false) { 108 return; 109 } 110 if (input.hasArray()) { 111 byte[] b = input.array(); 112 int ofs = input.arrayOffset(); 113 int pos = input.position(); 114 int lim = input.limit(); 115 engineUpdate(b, ofs + pos, lim - pos); 116 input.position(lim); 117 } else { 118 int len = input.remaining(); 119 int n = JCAUtil.getTempArraySize(len); 120 if ((tempArray == null) || (n > tempArray.length)) { 121 tempArray = new byte[n]; 122 } 123 while (len > 0) { 124 int chunk = Math.min(len, tempArray.length); 125 input.get(tempArray, 0, chunk); 126 engineUpdate(tempArray, 0, chunk); 127 len -= chunk; 128 } 129 } 130 } 131 132 /** 133 * Completes the hash computation by performing final 134 * operations such as padding. Once {@code engineDigest} has 135 * been called, the engine should be reset (see 136 * {@link #engineReset() engineReset}). 137 * Resetting is the responsibility of the 138 * engine implementor. 139 * 140 * @return the array of bytes for the resulting hash value. 141 */ engineDigest()142 protected abstract byte[] engineDigest(); 143 144 /** 145 * Completes the hash computation by performing final 146 * operations such as padding. Once {@code engineDigest} has 147 * been called, the engine should be reset (see 148 * {@link #engineReset() engineReset}). 149 * Resetting is the responsibility of the 150 * engine implementor. 151 * 152 * This method should be abstract, but we leave it concrete for 153 * binary compatibility. Knowledgeable providers should override this 154 * method. 155 * 156 * @param buf the output buffer in which to store the digest 157 * 158 * @param offset offset to start from in the output buffer 159 * 160 * @param len number of bytes within buf allotted for the digest. 161 * Both this default implementation and the SUN provider do not 162 * return partial digests. The presence of this parameter is solely 163 * for consistency in our API's. If the value of this parameter is less 164 * than the actual digest length, the method will throw a DigestException. 165 * This parameter is ignored if its value is greater than or equal to 166 * the actual digest length. 167 * 168 * @return the length of the digest stored in the output buffer. 169 * 170 * @exception DigestException if an error occurs. 171 * 172 * @since 1.2 173 */ engineDigest(byte[] buf, int offset, int len)174 protected int engineDigest(byte[] buf, int offset, int len) 175 throws DigestException { 176 177 byte[] digest = engineDigest(); 178 if (len < digest.length) 179 throw new DigestException("partial digests not returned"); 180 if (buf.length - offset < digest.length) 181 throw new DigestException("insufficient space in the output " 182 + "buffer to store the digest"); 183 System.arraycopy(digest, 0, buf, offset, digest.length); 184 return digest.length; 185 } 186 187 /** 188 * Resets the digest for further use. 189 */ engineReset()190 protected abstract void engineReset(); 191 192 /** 193 * Returns a clone if the implementation is cloneable. 194 * 195 * @return a clone if the implementation is cloneable. 196 * 197 * @exception CloneNotSupportedException if this is called on an 198 * implementation that does not support {@code Cloneable}. 199 */ clone()200 public Object clone() throws CloneNotSupportedException { 201 if (this instanceof Cloneable) { 202 return super.clone(); 203 } else { 204 throw new CloneNotSupportedException(); 205 } 206 } 207 } 208