1 /*
2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.provider;
27 
28 import sun.security.util.HexDumpEncoder;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Locale;
33 
34 public abstract class AbstractHashDrbg extends AbstractDrbg {
35 
36     protected int outLen;
37     protected int seedLen;
38 
alg2strength(String algorithm)39     private static int alg2strength(String algorithm) {
40         switch (algorithm.toUpperCase(Locale.ROOT)) {
41             case "SHA-224":
42             case "SHA-512/224":
43                 return 192;
44             case "SHA-256":
45             case "SHA-512/256":
46             case "SHA-384":
47             case "SHA-512":
48                 return 256;
49             default:
50                 throw new IllegalArgumentException(algorithm +
51                         " not supported in Hash_DBRG");
52         }
53     }
54 
chooseAlgorithmAndStrength()55     protected void chooseAlgorithmAndStrength() {
56         if (requestedAlgorithm != null) {
57             algorithm = requestedAlgorithm.toUpperCase(Locale.ROOT);
58             int supportedStrength = alg2strength(algorithm);
59             if (requestedInstantiationSecurityStrength >= 0) {
60                 int tryStrength = getStandardStrength(
61                         requestedInstantiationSecurityStrength);
62                 if (tryStrength > supportedStrength) {
63                     throw new IllegalArgumentException(algorithm +
64                             " does not support strength " +
65                             requestedInstantiationSecurityStrength);
66                 }
67                 this.securityStrength = tryStrength;
68             } else {
69                 this.securityStrength = DEFAULT_STRENGTH > supportedStrength ?
70                         supportedStrength : DEFAULT_STRENGTH;
71             }
72         } else {
73             int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
74                     DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
75             tryStrength = getStandardStrength(tryStrength);
76             // The default algorithm which is enough for all strengths.
77             // Remember to sync with "securerandom.drbg.config" in java.security
78             algorithm = "SHA-256";
79             this.securityStrength = tryStrength;
80         }
81         switch (algorithm.toUpperCase(Locale.ROOT)) {
82             case "SHA-224":
83             case "SHA-512/224":
84                 this.seedLen = 440 / 8;
85                 this.outLen = 224 / 8;
86                 break;
87             case "SHA-256":
88             case "SHA-512/256":
89                 this.seedLen = 440 / 8;
90                 this.outLen = 256 / 8;
91                 break;
92             case "SHA-384":
93                 this.seedLen = 888 / 8;
94                 this.outLen = 384 / 8;
95                 break;
96             case "SHA-512":
97                 this.seedLen = 888 / 8;
98                 this.outLen = 512 / 8;
99                 break;
100             default:
101                 throw new IllegalArgumentException(algorithm +
102                         " not supported in Hash_DBRG");
103         }
104         this.minLength = this.securityStrength / 8;
105     }
106 
107     @Override
instantiateAlgorithm(byte[] entropy)108     public void instantiateAlgorithm(byte[] entropy) {
109         if (debug != null) {
110             debug.println(this, "instantiate");
111         }
112 
113         // 800-90Ar1 10.1.1.2: Hash_DRBG Instantiate Process.
114         // 800-90Ar1 10.1.2.3: Hmac_DRBG Instantiate Process.
115 
116         // Step 1: entropy_input || nonce || personalization_string.
117         List<byte[]> inputs = new ArrayList<>(3);
118         inputs.add(entropy);
119         inputs.add(nonce);
120         if (personalizationString != null) {
121             inputs.add(personalizationString);
122         }
123         hashReseedInternal(inputs);
124     }
125 
126     @Override
reseedAlgorithm( byte[] ei, byte[] additionalInput)127     protected void reseedAlgorithm(
128             byte[] ei,
129             byte[] additionalInput) {
130         if (debug != null) {
131             debug.println(this, "reseedAlgorithm\n" +
132                     new HexDumpEncoder().encodeBuffer(ei) + "\n" +
133                     ((additionalInput == null) ? "" :
134                         new HexDumpEncoder().encodeBuffer(additionalInput)));
135         }
136 
137         // 800-90Ar1 10.1.1.3: Hash_DRBG Reseed Process.
138         // 800-90Ar1 10.1.2.4: Hmac_DRBG Reseed Process.
139 
140         // Step 1: entropy_input || additional_input.
141         List<byte[]> inputs = new ArrayList<>(2);
142         inputs.add(ei);
143         if (additionalInput != null) {
144             inputs.add(additionalInput);
145         }
146         hashReseedInternal(inputs);
147     }
148 
149     /**
150      * Operates on multiple inputs.
151      * @param inputs not null, each element neither null
152      */
hashReseedInternal(List<byte[]> inputs)153     protected abstract void hashReseedInternal(List<byte[]> inputs);
154 }
155