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 
  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</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 
  51 public 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 }