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.io.FilterInputStream; 21import java.io.IOException; 22import java.io.InputStream; 23 24/** 25 * {@code DigestInputStream} is a {@code FilterInputStream} which maintains an 26 * associated message digest. 27 */ 28public class DigestInputStream extends FilterInputStream { 29 30 /** 31 * The message digest for this stream. 32 */ 33 protected MessageDigest digest; 34 35 // Indicates whether digest functionality is on or off 36 private boolean isOn = true; 37 38 /** 39 * Constructs a new instance of this {@code DigestInputStream}, using the 40 * given {@code stream} and the {@code digest}. 41 * 42 * <p><strong>Warning:</strong> passing a null source creates an invalid 43 * {@code DigestInputStream}. All operations on such a stream will fail. 44 * 45 * @param stream 46 * the input stream. 47 * @param digest 48 * the message digest. 49 */ 50 public DigestInputStream(InputStream stream, MessageDigest digest) { 51 super(stream); 52 this.digest = digest; 53 } 54 55 /** 56 * Returns the message digest for this stream. 57 * 58 * @return the message digest for this stream. 59 */ 60 public MessageDigest getMessageDigest() { 61 return digest; 62 } 63 64 /** 65 * Sets the message digest which this stream will use. 66 * 67 * @param digest 68 * the message digest which this stream will use. 69 */ 70 public void setMessageDigest(MessageDigest digest) { 71 this.digest = digest; 72 } 73 74 /** 75 * Reads the next byte and returns it as an {@code int}. Updates the digest 76 * for the byte if this function is {@link #on(boolean)}. 77 * <p> 78 * This operation is blocking. 79 * 80 * @return the byte which was read or -1 at end of stream. 81 * @throws IOException 82 * if reading the source stream causes an {@code IOException}. 83 */ 84 @Override 85 public int read() throws IOException { 86 // read the next byte 87 int byteRead = in.read(); 88 // update digest only if 89 // - digest functionality is on 90 // - eos has not been reached 91 if (isOn && (byteRead != -1)) { 92 digest.update((byte)byteRead); 93 } 94 // return byte read 95 return byteRead; 96 } 97 98 /** 99 * Reads up to {@code byteCount} bytes into {@code buffer}, starting at 100 * {@code byteOffset}. Updates the digest if this function is 101 * {@link #on(boolean)}. 102 * 103 * <p>This operation is blocking. 104 * 105 * <p>Returns the number of bytes actually read or -1 if the end of the 106 * filtered stream has been reached while reading. 107 * 108 * @throws IOException 109 * if reading the source stream causes an {@code IOException} 110 */ 111 @Override 112 public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 113 int bytesRead = in.read(buffer, byteOffset, byteCount); 114 // update digest only if 115 // - digest functionality is on 116 // - eos has not been reached 117 if (isOn && (bytesRead != -1)) { 118 digest.update(buffer, byteOffset, bytesRead); 119 } 120 // return number of bytes read 121 return bytesRead; 122 } 123 124 /** 125 * Enables or disables the digest function (default is on). 126 * 127 * @param on 128 * {@code true} if the digest should be computed, {@code false} 129 * otherwise. 130 * @see MessageDigest 131 */ 132 public void on(boolean on) { 133 isOn = on; 134 } 135 136 /** 137 * Returns a string containing a concise, human-readable description of this 138 * {@code DigestInputStream} including the digest. 139 * 140 * @return a printable representation for this {@code DigestInputStream}. 141 */ 142 @Override 143 public String toString() { 144 return super.toString() + ", " + digest.toString() + 145 (isOn ? ", is on" : ", is off"); 146 } 147} 148