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.SecureRandomNumberGenerator;
20 
21 import hunt.shiro.crypto.RandomNumberGenerator;
22 import hunt.shiro.util.ByteSource;
23 import hunt.shiro.util.SimpleByteSource;
24 
25 import hunt.security.SecureRandom;
26 
27 import hunt.Exceptions;
28 
29 /**
30  * Default implementation of the {@link RandomNumberGenerator RandomNumberGenerator} interface, backed by a
31  * {@link SecureRandom SecureRandom} instance.
32  * <p/>
33  * This class is a little easier to use than using the JDK's {@code SecureRandom} class directly.  It also
34  * allows for JavaBeans-style of customization, convenient for Shiro's INI configuration or other IoC configuration
35  * mechanism.
36  *
37  * @since 1.1
38  */
39 class SecureRandomNumberGenerator : RandomNumberGenerator {
40 
41     protected enum int DEFAULT_NEXT_BYTES_SIZE = 16; //16 bytes == 128 bits (a common number in crypto)
42 
43     private int defaultNextBytesSize;
44     private SecureRandom secureRandom;
45 
46     /**
47      * Creates a new instance with a default backing {@link SecureRandom SecureRandom} and a
48      * {@link #getDefaultNextBytesSize() defaultNextBytesSize} of {@code 16}, which equals 128 bits, a size commonly
49      * used in cryptographic algorithms.
50      */
51     this() {
52         this.defaultNextBytesSize = DEFAULT_NEXT_BYTES_SIZE;
53         this.secureRandom = new SecureRandom();
54     }
55 
56     /**
57      * Seeds the backing {@link SecureRandom SecureRandom} instance with additional seed data.
58      *
59      * @param bytes the seed bytes
60      * @see SecureRandom#setSeed(byte[])
61      */
62     void setSeed(byte[] bytes) {
63         this.secureRandom.setSeed(bytes);
64     }
65 
66     /**
67      * Returns the {@link SecureRandom SecureRandom} backing this instance.
68      *
69      * @return the {@link SecureRandom SecureRandom} backing this instance.
70      */
71     SecureRandom getSecureRandom() {
72         return secureRandom;
73     }
74 
75     /**
76      * Sets the {@link SecureRandom SecureRandom} to back this instance.
77      *
78      * @param random the {@link SecureRandom SecureRandom} to back this instance.
79      * @throws NullPointerException if the method argument is null
80      */
81     void setSecureRandom(SecureRandom random) {
82         if (random is null) {
83             throw new NullPointerException("SecureRandom argument cannot be null.");
84         }
85         this.secureRandom = random;
86     }
87 
88     /**
89      * Returns the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}.  Defaults to
90      * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms.
91      *
92      * @return the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}.
93      */
94     int getDefaultNextBytesSize() {
95         return defaultNextBytesSize;
96     }
97 
98     /**
99      * Sets the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. Defaults to
100      * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms.
101      *
102      * @param defaultNextBytesSize the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}.
103      * @throws IllegalArgumentException if the argument is 0 or negative
104      */
105     void setDefaultNextBytesSize(int defaultNextBytesSize) {
106         if ( defaultNextBytesSize <= 0) {
107             throw new IllegalArgumentException("size value must be a positive integer (1 or larger)");
108         }
109         this.defaultNextBytesSize = defaultNextBytesSize;
110     }
111 
112     ByteSource nextBytes() {
113         return nextBytes(getDefaultNextBytesSize());
114     }
115 
116     ByteSource nextBytes(int numBytes) {
117         if (numBytes <= 0) {
118             throw new IllegalArgumentException("numBytes argument must be a positive integer (1 or larger)");
119         }
120         byte[] bytes = new byte[numBytes];
121         this.secureRandom.nextBytes(bytes);
122         return ByteSourceUtil.bytes(bytes);
123     }
124 }