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      */
  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      */
  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      */
  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      */
 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      */
 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      */
 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      */
 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      */
 200     public Object clone() throws CloneNotSupportedException {
 201         if (this instanceof Cloneable) {
 202             return super.clone();
 203         } else {
 204             throw new CloneNotSupportedException();
 205         }
 206     }
 207 }