• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package org.apache.commons.io.input;
18 
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.security.MessageDigest;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.Provider;
24 import java.util.Objects;
25 
26 import org.apache.commons.io.build.AbstractStreamBuilder;
27 
28 /**
29  * This class is an example for using an {@link ObservableInputStream}. It creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer},
30  * which calculates a checksum using a {@link MessageDigest}, for example, a SHA-512 sum.
31  * <p>
32  * To build an instance, see {@link Builder}.
33  * </p>
34  * <p>
35  * See the MessageDigest section in the <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java
36  * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names.
37  * </p>
38  * <p>
39  * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe, so is {@link MessageDigestCalculatingInputStream}.
40  * </p>
41  * @deprecated Use {@link MessageDigestInputStream}.
42  */
43 @Deprecated
44 public class MessageDigestCalculatingInputStream extends ObservableInputStream {
45 
46     /**
47      * Builds a new {@link MessageDigestCalculatingInputStream} instance.
48      * <p>
49      * For example:
50      * </p>
51      * <pre>{@code
52      * MessageDigestCalculatingInputStream s = MessageDigestCalculatingInputStream.builder()
53      *   .setPath(path)
54      *   .setMessageDigest("SHA-512")
55      *   .get();}
56      * </pre>
57      *
58      * @since 2.12.0
59      */
60     public static class Builder extends AbstractStreamBuilder<MessageDigestCalculatingInputStream, Builder> {
61 
62         private MessageDigest messageDigest;
63 
64         /**
65          * Constructs a new Builder.
66          */
Builder()67         public Builder() {
68             try {
69                 this.messageDigest = getDefaultMessageDigest();
70             } catch (final NoSuchAlgorithmException e) {
71                 // Should not happen.
72                 throw new IllegalStateException(e);
73             }
74         }
75 
76         /**
77          * Constructs a new instance.
78          * <p>
79          * This builder use the aspects InputStream, OpenOption[], and MessageDigest.
80          * </p>
81          * <p>
82          * You must provide an origin that can be converted to an InputStream by this builder, otherwise, this call will throw an
83          * {@link UnsupportedOperationException}.
84          * </p>
85          *
86          * @return a new instance.
87          * @throws UnsupportedOperationException if the origin cannot provide an InputStream.
88          * @see #getInputStream()
89          */
90         @SuppressWarnings("resource")
91         @Override
get()92         public MessageDigestCalculatingInputStream get() throws IOException {
93             return new MessageDigestCalculatingInputStream(getInputStream(), messageDigest);
94         }
95 
96         /**
97          * Sets the message digest.
98          * <p>
99          * The MD5 cryptographic algorithm is weak and should not be used.
100          * </p>
101          *
102          * @param messageDigest the message digest.
103          */
setMessageDigest(final MessageDigest messageDigest)104         public void setMessageDigest(final MessageDigest messageDigest) {
105             this.messageDigest = messageDigest;
106         }
107 
108         /**
109          * Sets the name of the name of the message digest algorithm.
110          * <p>
111          * The MD5 cryptographic algorithm is weak and should not be used.
112          * </p>
113          *
114          * @param algorithm the name of the algorithm. See the MessageDigest section in the
115          *                  <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography
116          *                  Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names.
117          * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified algorithm.
118          */
setMessageDigest(final String algorithm)119         public void setMessageDigest(final String algorithm) throws NoSuchAlgorithmException {
120             this.messageDigest = MessageDigest.getInstance(algorithm);
121         }
122 
123     }
124 
125     /**
126      * Maintains the message digest.
127      */
128     public static class MessageDigestMaintainingObserver extends Observer {
129         private final MessageDigest messageDigest;
130 
131         /**
132          * Constructs an MessageDigestMaintainingObserver for the given MessageDigest.
133          *
134          * @param messageDigest the message digest to use
135          * @throws NullPointerException if messageDigest is null.
136          */
MessageDigestMaintainingObserver(final MessageDigest messageDigest)137         public MessageDigestMaintainingObserver(final MessageDigest messageDigest) {
138             this.messageDigest = Objects.requireNonNull(messageDigest, "messageDigest");
139         }
140 
141         @Override
data(final byte[] input, final int offset, final int length)142         public void data(final byte[] input, final int offset, final int length) throws IOException {
143             messageDigest.update(input, offset, length);
144         }
145 
146         @Override
data(final int input)147         public void data(final int input) throws IOException {
148             messageDigest.update((byte) input);
149         }
150     }
151 
152     /**
153      * The default message digest algorithm.
154      * <p>
155      * The MD5 cryptographic algorithm is weak and should not be used.
156      * </p>
157      */
158     private static final String DEFAULT_ALGORITHM = "MD5";
159 
160     /**
161      * Constructs a new {@link Builder}.
162      *
163      * @return a new {@link Builder}.
164      * @since 2.12.0
165      */
builder()166     public static Builder builder() {
167         return new Builder();
168     }
169 
170     /**
171      * Gets a MessageDigest object that implements the default digest algorithm.
172      *
173      * @return a Message Digest object that implements the default algorithm.
174      * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation.
175      * @see Provider
176      */
getDefaultMessageDigest()177     static MessageDigest getDefaultMessageDigest() throws NoSuchAlgorithmException {
178         return MessageDigest.getInstance(DEFAULT_ALGORITHM);
179     }
180 
181     private final MessageDigest messageDigest;
182 
183     /**
184      * Constructs a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the "MD5" algorithm.
185      * <p>
186      * The MD5 algorithm is weak and should not be used.
187      * </p>
188      *
189      * @param inputStream the stream to calculate the message digest for
190      * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified algorithm.
191      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
192      */
193     @Deprecated
MessageDigestCalculatingInputStream(final InputStream inputStream)194     public MessageDigestCalculatingInputStream(final InputStream inputStream) throws NoSuchAlgorithmException {
195         this(inputStream, getDefaultMessageDigest());
196     }
197 
198     /**
199      * Constructs a new instance, which calculates a signature on the given stream, using the given {@link MessageDigest}.
200      * <p>
201      * The MD5 cryptographic algorithm is weak and should not be used.
202      * </p>
203      *
204      * @param inputStream   the stream to calculate the message digest for
205      * @param messageDigest the message digest to use
206      * @throws NullPointerException if messageDigest is null.
207      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
208      */
209     @Deprecated
MessageDigestCalculatingInputStream(final InputStream inputStream, final MessageDigest messageDigest)210     public MessageDigestCalculatingInputStream(final InputStream inputStream, final MessageDigest messageDigest) {
211         super(inputStream, new MessageDigestMaintainingObserver(messageDigest));
212         this.messageDigest = messageDigest;
213     }
214 
215     /**
216      * Constructs a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the given algorithm.
217      * <p>
218      * The MD5 cryptographic algorithm is weak and should not be used.
219      * </p>
220      *
221      * @param inputStream the stream to calculate the message digest for
222      * @param algorithm   the name of the algorithm requested. See the MessageDigest section in the
223      *                    <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography
224      *                    Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names.
225      * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified algorithm.
226      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
227      */
228     @Deprecated
MessageDigestCalculatingInputStream(final InputStream inputStream, final String algorithm)229     public MessageDigestCalculatingInputStream(final InputStream inputStream, final String algorithm) throws NoSuchAlgorithmException {
230         this(inputStream, MessageDigest.getInstance(algorithm));
231     }
232 
233     /**
234      * Gets the {@link MessageDigest}, which is being used for generating the checksum.
235      * <p>
236      * <em>Note</em>: The checksum will only reflect the data, which has been read so far. This is probably not, what you expect. Make sure, that the complete
237      * data has been read, if that is what you want. The easiest way to do so is by invoking {@link #consume()}.
238      * </p>
239      *
240      * @return the message digest used
241      */
getMessageDigest()242     public MessageDigest getMessageDigest() {
243         return messageDigest;
244     }
245 }
246