1 /* 2 * Copyright (c) 2002, 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 com.sun.crypto.provider; 27 28 import java.util.Arrays; 29 30 import java.nio.ByteBuffer; 31 32 import javax.crypto.MacSpi; 33 import javax.crypto.SecretKey; 34 import java.security.*; 35 import java.security.spec.*; 36 37 /** 38 * This class constitutes the core of HMAC-<MD> algorithms, where 39 * <MD> can be SHA1 or MD5, etc. See RFC 2104 for spec. 40 * 41 * It also contains the implementation classes for SHA-224, SHA-256, 42 * SHA-384, and SHA-512 HMACs. 43 * 44 * @author Jan Luehe 45 */ 46 abstract class HmacCore extends MacSpi implements Cloneable { 47 48 private MessageDigest md; 49 private byte[] k_ipad; // inner padding - key XORd with ipad 50 private byte[] k_opad; // outer padding - key XORd with opad 51 private boolean first; // Is this the first data to be processed? 52 53 private final int blockLen; 54 55 /** 56 * Standard constructor, creates a new HmacCore instance instantiating 57 * a MessageDigest of the specified name. 58 */ 59 HmacCore(String digestAlgo, int bl) throws NoSuchAlgorithmException { 60 MessageDigest md = MessageDigest.getInstance(digestAlgo); 61 if (!(md instanceof Cloneable)) { 62 // use SUN provider if the most preferred one does not support 63 // cloning 64 Provider sun = Security.getProvider("SUN"); 65 if (sun != null) { 66 md = MessageDigest.getInstance(digestAlgo, sun); 67 } else { 68 String noCloneProv = md.getProvider().getName(); 69 // if no Sun provider, use provider list 70 Provider[] provs = Security.getProviders(); 71 for (Provider p : provs) { 72 try { 73 if (!p.getName().equals(noCloneProv)) { 74 MessageDigest md2 = 75 MessageDigest.getInstance(digestAlgo, p); 76 if (md2 instanceof Cloneable) { 77 md = md2; 78 break; 79 } 80 } 81 } catch (NoSuchAlgorithmException nsae) { 82 continue; 83 } 84 } 85 } 86 } 87 this.md = md; 88 this.blockLen = bl; 89 this.k_ipad = new byte[blockLen]; 90 this.k_opad = new byte[blockLen]; 91 first = true; 92 } 93 94 /** 95 * Returns the length of the HMAC in bytes. 96 * 97 * @return the HMAC length in bytes. 98 */ 99 protected int engineGetMacLength() { 100 return this.md.getDigestLength(); 101 } 102 103 /** 104 * Initializes the HMAC with the given secret key and algorithm parameters. 105 * 106 * @param key the secret key. 107 * @param params the algorithm parameters. 108 * 109 * @exception InvalidKeyException if the given key is inappropriate for 110 * initializing this MAC. 111 * @exception InvalidAlgorithmParameterException if the given algorithm 112 * parameters are inappropriate for this MAC. 113 */ 114 protected void engineInit(Key key, AlgorithmParameterSpec params) 115 throws InvalidKeyException, InvalidAlgorithmParameterException { 116 if (params != null) { 117 throw new InvalidAlgorithmParameterException 118 ("HMAC does not use parameters"); 119 } 120 121 if (!(key instanceof SecretKey)) { 122 throw new InvalidKeyException("Secret key expected"); 123 } 124 125 byte[] secret = key.getEncoded(); 126 if (secret == null) { 127 throw new InvalidKeyException("Missing key data"); 128 } 129 130 // if key is longer than the block length, reset it using 131 // the message digest object. 132 if (secret.length > blockLen) { 133 byte[] tmp = md.digest(secret); 134 // now erase the secret 135 Arrays.fill(secret, (byte)0); 136 secret = tmp; 137 } 138 139 // XOR k with ipad and opad, respectively 140 for (int i = 0; i < blockLen; i++) { 141 int si = (i < secret.length) ? secret[i] : 0; 142 k_ipad[i] = (byte)(si ^ 0x36); 143 k_opad[i] = (byte)(si ^ 0x5c); 144 } 145 146 // now erase the secret 147 Arrays.fill(secret, (byte)0); 148 secret = null; 149 150 engineReset(); 151 } 152 153 /** 154 * Processes the given byte. 155 * 156 * @param input the input byte to be processed. 157 */ 158 protected void engineUpdate(byte input) { 159 if (first == true) { 160 // compute digest for 1st pass; start with inner pad 161 md.update(k_ipad); 162 first = false; 163 } 164 165 // add the passed byte to the inner digest 166 md.update(input); 167 } 168 169 /** 170 * Processes the first <code>len</code> bytes in <code>input</code>, 171 * starting at <code>offset</code>. 172 * 173 * @param input the input buffer. 174 * @param offset the offset in <code>input</code> where the input starts. 175 * @param len the number of bytes to process. 176 */ 177 protected void engineUpdate(byte input[], int offset, int len) { 178 if (first == true) { 179 // compute digest for 1st pass; start with inner pad 180 md.update(k_ipad); 181 first = false; 182 } 183 184 // add the selected part of an array of bytes to the inner digest 185 md.update(input, offset, len); 186 } 187 188 /** 189 * Processes the <code>input.remaining()</code> bytes in the ByteBuffer 190 * <code>input</code>. 191 * 192 * @param input the input byte buffer. 193 */ 194 protected void engineUpdate(ByteBuffer input) { 195 if (first == true) { 196 // compute digest for 1st pass; start with inner pad 197 md.update(k_ipad); 198 first = false; 199 } 200 201 md.update(input); 202 } 203 204 /** 205 * Completes the HMAC computation and resets the HMAC for further use, 206 * maintaining the secret key that the HMAC was initialized with. 207 * 208 * @return the HMAC result. 209 */ 210 protected byte[] engineDoFinal() { 211 if (first == true) { 212 // compute digest for 1st pass; start with inner pad 213 md.update(k_ipad); 214 } else { 215 first = true; 216 } 217 218 try { 219 // finish the inner digest 220 byte[] tmp = md.digest(); 221 222 // compute digest for 2nd pass; start with outer pad 223 md.update(k_opad); 224 // add result of 1st hash 225 md.update(tmp); 226 227 md.digest(tmp, 0, tmp.length); 228 return tmp; 229 } catch (DigestException e) { 230 // should never occur 231 throw new ProviderException(e); 232 } 233 } 234 235 /** 236 * Resets the HMAC for further use, maintaining the secret key that the 237 * HMAC was initialized with. 238 */ 239 protected void engineReset() { 240 if (first == false) { 241 md.reset(); 242 first = true; 243 } 244 } 245 246 /* 247 * Clones this object. 248 */ 249 public Object clone() throws CloneNotSupportedException { 250 HmacCore copy = (HmacCore) super.clone(); 251 copy.md = (MessageDigest) md.clone(); 252 copy.k_ipad = k_ipad.clone(); 253 copy.k_opad = k_opad.clone(); 254 return copy; 255 } 256 257 // nested static class for the HmacSHA224 implementation 258 public static final class HmacSHA224 extends HmacCore { 259 public HmacSHA224() throws NoSuchAlgorithmException { 260 super("SHA-224", 64); 261 } 262 } 263 264 // nested static class for the HmacSHA256 implementation 265 public static final class HmacSHA256 extends HmacCore { 266 public HmacSHA256() throws NoSuchAlgorithmException { 267 super("SHA-256", 64); 268 } 269 } 270 271 // nested static class for the HmacSHA384 implementation 272 public static final class HmacSHA384 extends HmacCore { 273 public HmacSHA384() throws NoSuchAlgorithmException { 274 super("SHA-384", 128); 275 } 276 } 277 278 // nested static class for the HmacSHA512 implementation 279 public static final class HmacSHA512 extends HmacCore { 280 public HmacSHA512() throws NoSuchAlgorithmException { 281 super("SHA-512", 128); 282 } 283 } 284 public static final class HmacSHA512_224 extends HmacCore { 285 public HmacSHA512_224() throws NoSuchAlgorithmException { 286 super("SHA-512/224", 128); 287 } 288 } 289 public static final class HmacSHA512_256 extends HmacCore { 290 public HmacSHA512_256() throws NoSuchAlgorithmException { 291 super("SHA-512/256", 128); 292 } 293 } 294 }