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