1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20import java.nio.ByteBuffer; 21 22/** 23 * {@code MessageDigestSpi} is the Service Provider Interface (SPI) definition 24 * for {@link MessageDigest}. Examples of digest algorithms are MD5 and SHA. A 25 * digest is a secure one way hash function for a stream of bytes. It acts like 26 * a fingerprint for a stream of bytes. 27 * 28 * @see MessageDigest 29 */ 30public abstract class MessageDigestSpi { 31 32 /** 33 * Returns the engine digest length in bytes. If the implementation does not 34 * implement this function {@code 0} is returned. 35 * 36 * @return the digest length in bytes, or {@code 0}. 37 */ 38 protected int engineGetDigestLength() { 39 return 0; 40 } 41 42 /** 43 * Updates this {@code MessageDigestSpi} using the given {@code byte}. 44 * 45 * @param input 46 * the {@code byte} to update this {@code MessageDigestSpi} with. 47 * @see #engineReset() 48 */ 49 protected abstract void engineUpdate(byte input); 50 51 /** 52 * Updates this {@code MessageDigestSpi} using the given {@code byte[]}. 53 * 54 * @param input 55 * the {@code byte} array. 56 * @param offset 57 * the index of the first byte in {@code input} to update from. 58 * @param len 59 * the number of bytes in {@code input} to update from. 60 * @throws IllegalArgumentException 61 * if {@code offset} or {@code len} are not valid in respect to 62 * {@code input}. 63 */ 64 protected abstract void engineUpdate(byte[] input, int offset, int len); 65 66 /** 67 * Updates this {@code MessageDigestSpi} using the given {@code input}. 68 * 69 * @param input 70 * the {@code ByteBuffer}. 71 */ 72 protected void engineUpdate(ByteBuffer input) { 73 if (!input.hasRemaining()) { 74 return; 75 } 76 byte[] tmp; 77 if (input.hasArray()) { 78 tmp = input.array(); 79 int offset = input.arrayOffset(); 80 int position = input.position(); 81 int limit = input.limit(); 82 engineUpdate(tmp, offset+position, limit - position); 83 input.position(limit); 84 } else { 85 tmp = new byte[input.limit() - input.position()]; 86 input.get(tmp); 87 engineUpdate(tmp, 0, tmp.length); 88 } 89 } 90 91 /** 92 * Computes and returns the final hash value for this 93 * {@link MessageDigestSpi}. After the digest is computed the receiver is 94 * reset. 95 * 96 * @return the computed one way hash value. 97 * @see #engineReset() 98 */ 99 protected abstract byte[] engineDigest(); 100 101 /** 102 * Computes and stores the final hash value for this 103 * {@link MessageDigestSpi}. After the digest is computed the receiver is 104 * reset. 105 * 106 * @param buf 107 * the buffer to store the result in. 108 * @param offset 109 * the index of the first byte in {@code buf} to store in. 110 * @param len 111 * the number of bytes allocated for the digest. 112 * @return the number of bytes written to {@code buf}. 113 * @throws DigestException 114 * if an error occures. 115 * @throws IllegalArgumentException 116 * if {@code offset} or {@code len} are not valid in respect to 117 * {@code buf}. 118 * @see #engineReset() 119 */ 120 protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { 121 if (len < engineGetDigestLength()) { 122 engineReset(); 123 throw new DigestException("The value of len parameter is less than the actual digest length"); 124 } 125 if (offset < 0) { 126 engineReset(); 127 throw new DigestException("offset < 0"); 128 } 129 if (offset + len > buf.length) { 130 engineReset(); 131 throw new DigestException("offset + len > buf.length"); 132 } 133 byte[] tmp = engineDigest(); 134 if (len < tmp.length) { 135 throw new DigestException("The value of len parameter is less than the actual digest length"); 136 } 137 System.arraycopy(tmp, 0, buf, offset, tmp.length); 138 return tmp.length; 139 } 140 141 /** 142 * Puts this {@code MessageDigestSpi} back in an initial state, such that it 143 * is ready to compute a one way hash value. 144 */ 145 protected abstract void engineReset(); 146 147 @Override 148 public Object clone() throws CloneNotSupportedException { 149 return super.clone(); 150 } 151} 152