1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 module hunt.shiro.crypto.hash.HashRequest;
20 
21 import hunt.shiro.crypto.hash.SimpleHashRequest;
22 
23 import hunt.shiro.util.ByteSource;
24 import hunt.shiro.util.SimpleByteSource;
25 
26 /**
27  * A {@code HashRequest} is composed of data that will be used by a {@link HashService} to compute a hash (aka
28  * 'digest').  While you can instantiate a concrete {@code HashRequest} class directly, most will find using the
29  * {@link HashRequest.Builder} more convenient.
30  *
31  * @see HashRequest.Builder
32  */
33 interface HashRequest {
34 
35     /**
36      * Returns the source data that will be hashed by a {@link HashService}. For example, this might be a
37      * {@code ByteSource} representation of a password, or file, etc.
38      *
39      * @return the source data that will be hashed by a {@link HashService}.
40      */
41     ByteSource getSource();
42 
43     /**
44      * Returns a salt to be used by the {@link HashService} during hash computation, or {@code null} if no salt is
45      * provided as part of the request.
46      * <p/>
47      * Note that a {@code null} value does not necessarily mean a salt won't be used at all - it just
48      * means that the request didn't include one.  The servicing {@link HashService} is free to provide a salting
49      * strategy for a request, even if the request did not specify one.
50      *
51      * @return a salt to be used by the {@link HashService} during hash computation, or {@code null} if no salt is
52      *         provided as part of the request.
53      */
54     ByteSource getSalt();
55 
56     /**
57      * Returns the number of requested hash iterations to be performed when computing the final {@code Hash} result.
58      * A non-positive (0 or less) indicates that the {@code HashService}'s default iteration configuration should
59      * be used.  A positive value overrides the {@code HashService}'s configuration for a single request.
60      * <p/>
61      * Note that a {@code HashService} is free to ignore this number if it determines the number is not sufficient
62      * to meet a desired level of security.
63      *
64      * @return the number of requested hash iterations to be performed when computing the final {@code Hash} result.
65      */
66     int getIterations();
67 
68     /**
69      * Returns the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}, or
70      * {@code null} if the default algorithm configuration of the {@code HashService} should be used.  A non-null value
71      * overrides the {@code HashService}'s configuration for a single request.
72      * <p/>
73      * Note that a {@code HashService} is free to ignore this value if it determines that the algorithm is not
74      * sufficient to meet a desired level of security.
75      *
76      * @return the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}, or
77      *         {@code null} if the default algorithm configuration of the {@code HashService} should be used.
78      */
79     string getAlgorithmName();
80 
81     /**
82      * A Builder class representing the Builder design pattern for constructing {@link HashRequest} instances.
83      *
84      * @see SimpleHashRequest
85      */
86     static class Builder {
87 
88         private ByteSource source;
89         private ByteSource salt;
90         private int iterations;
91         private string algorithmName;
92 
93         /**
94          * Default no-arg constructor.
95          */
96         this() {
97             this.iterations = 0;
98         }
99 
100         /**
101          * Sets the source data that will be hashed by a {@link HashService}. For example, this might be a
102          * {@code ByteSource} representation of a password, or file, etc.
103          *
104          * @param source the source data that will be hashed by a {@link HashService}.
105          * @return this {@code Builder} instance for method chaining.
106          * @see HashRequest#getSource()
107          * @see #setSource(Object)
108          */
109         Builder setSource(ByteSource source) {
110             this.source = source;
111             return this;
112         }
113 
114         /**
115          * Sets the source data that will be hashed by a {@link HashService}.
116          * <p/>
117          * This is a convenience alternative to {@link #setSource(ByteSource)}: it will attempt to convert the
118          * argument into a {@link ByteSource} instance using Shiro's default conversion heuristics
119          * (as defined by {@link ByteSourceUtil#isCompatible(Object) ByteSourceUtil.isCompatible}.  If the object
120          * cannot be heuristically converted to a {@code ByteSource}, an {@code IllegalArgumentException} will be
121          * thrown.
122          *
123          * @param source the byte-backed source data that will be hashed by a {@link HashService}.
124          * @return this {@code Builder} instance for method chaining.
125          * @throws IllegalArgumentException if the argument cannot be heuristically converted to a {@link ByteSource}
126          *                                  instance.
127          * @see HashRequest#getSource()
128          * @see #setSource(ByteSource)
129          */
130         Builder setSource(Object source) {
131             this.source = ByteSourceUtil.bytes(source);
132             return this;
133         }
134 
135         /**
136          * Sets a salt to be used by the {@link HashService} during hash computation.
137          * <p/>
138          * <b>NOTE</b>: not calling this method does not necessarily mean a salt won't be used at all - it just
139          * means that the request didn't include a salt.  The servicing {@link HashService} is free to provide a salting
140          * strategy for a request, even if the request did not specify one.  You can always check the result
141          * {@code Hash} {@link Hash#getSalt() getSalt()} method to see what the actual
142          * salt was (if any), which may or may not match this request salt.
143          *
144          * @param salt a salt to be used by the {@link HashService} during hash computation
145          * @return this {@code Builder} instance for method chaining.
146          * @see HashRequest#getSalt()
147          */
148         Builder setSalt(ByteSource salt) {
149             this.salt = salt;
150             return this;
151         }
152 
153         /**
154          * Sets a salt to be used by the {@link HashService} during hash computation.
155          * <p/>
156          * This is a convenience alternative to {@link #setSalt(ByteSource)}: it will attempt to convert the
157          * argument into a {@link ByteSource} instance using Shiro's default conversion heuristics
158          * (as defined by {@link ByteSourceUtil#isCompatible(Object) ByteSourceUtil.isCompatible}.  If the object
159          * cannot be heuristically converted to a {@code ByteSource}, an {@code IllegalArgumentException} will be
160          * thrown.
161          *
162          * @param salt a salt to be used by the {@link HashService} during hash computation.
163          * @return this {@code Builder} instance for method chaining.
164          * @throws IllegalArgumentException if the argument cannot be heuristically converted to a {@link ByteSource}
165          *                                  instance.
166          * @see #setSalt(ByteSource)
167          * @see HashRequest#getSalt()
168          */
169         Builder setSalt(Object salt) {
170             this.salt = ByteSourceUtil.bytes(salt);
171             return this;
172         }
173 
174         /**
175          * Sets the number of requested hash iterations to be performed when computing the final {@code Hash} result.
176          * Not calling this method or setting a non-positive value (0 or less) indicates that the {@code HashService}'s
177          * default iteration configuration should be used.  A positive value overrides the {@code HashService}'s
178          * configuration for a single request.
179          * <p/>
180          * Note that a {@code HashService} is free to ignore this number if it determines the number is not sufficient
181          * to meet a desired level of security. You can always check the result
182          * {@code Hash} {@link Hash#getIterations() getIterations()} method to see what the actual
183          * number of iterations was, which may or may not match this request salt.
184          *
185          * @param iterations the number of requested hash iterations to be performed when computing the final
186          *                   {@code Hash} result.
187          * @return this {@code Builder} instance for method chaining.
188          * @see HashRequest#getIterations()
189          */
190         Builder setIterations(int iterations) {
191             this.iterations = iterations;
192             return this;
193         }
194 
195         /**
196          * Sets the name of the hash algorithm the {@code HashService} should use when computing the {@link Hash}.
197          * Not calling this method or setting it to {@code null} indicates the the default algorithm configuration of
198          * the {@code HashService} should be used.  A non-null value
199          * overrides the {@code HashService}'s configuration for a single request.
200          * <p/>
201          * Note that a {@code HashService} is free to ignore this value if it determines that the algorithm is not
202          * sufficient to meet a desired level of security. You can always check the result
203          * {@code Hash} {@link Hash#getAlgorithmName() getAlgorithmName()} method to see what the actual
204          * algorithm was, which may or may not match this request salt.
205          *
206          * @param algorithmName the name of the hash algorithm the {@code HashService} should use when computing the
207          *                      {@link Hash}, or {@code null} if the default algorithm configuration of the
208          *                      {@code HashService} should be used.
209          * @return this {@code Builder} instance for method chaining.
210          * @see HashRequest#getAlgorithmName()
211          */
212         Builder setAlgorithmName(string algorithmName) {
213             this.algorithmName = algorithmName;
214             return this;
215         }
216 
217         /**
218          * Builds a {@link HashRequest} instance reflecting the specified configuration.
219          *
220          * @return a {@link HashRequest} instance reflecting the specified configuration.
221          */
222         HashRequest build() {
223             return new SimpleHashRequest(this.algorithmName, this.source, this.salt, this.iterations);
224         }
225     }
226 }