1 /* 2 * Copyright (c) 2002, 2012, 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 using the 57 * specified MessageDigest object. 58 */ 59 HmacCore(MessageDigest md, int bl) { 60 this.md = md; 61 this.blockLen = bl; 62 this.k_ipad = new byte[blockLen]; 63 this.k_opad = new byte[blockLen]; 64 first = true; 65 } 66 67 /** 68 * Standard constructor, creates a new HmacCore instance instantiating 69 * a MessageDigest of the specified name. 70 */ 71 HmacCore(String digestAlgorithm, int bl) throws NoSuchAlgorithmException { 72 this(MessageDigest.getInstance(digestAlgorithm), bl); 73 } 74 75 /** 76 * Returns the length of the HMAC in bytes. 77 * 78 * @return the HMAC length in bytes. 79 */ 80 protected int engineGetMacLength() { 81 return this.md.getDigestLength(); 82 } 83 84 /** 85 * Initializes the HMAC with the given secret key and algorithm parameters. 86 * 87 * @param key the secret key. 88 * @param params the algorithm parameters. 89 * 90 * @exception InvalidKeyException if the given key is inappropriate for 91 * initializing this MAC. 92 * @exception InvalidAlgorithmParameterException if the given algorithm 93 * parameters are inappropriate for this MAC. 94 */ 95 protected void engineInit(Key key, AlgorithmParameterSpec params) 96 throws InvalidKeyException, InvalidAlgorithmParameterException { 97 if (params != null) { 98 throw new InvalidAlgorithmParameterException 99 ("HMAC does not use parameters"); 100 } 101 102 if (!(key instanceof SecretKey)) { 103 throw new InvalidKeyException("Secret key expected"); 104 } 105 106 byte[] secret = key.getEncoded(); 107 if (secret == null) { 108 throw new InvalidKeyException("Missing key data"); 109 } 110 111 // if key is longer than the block length, reset it using 112 // the message digest object. 113 if (secret.length > blockLen) { 114 byte[] tmp = md.digest(secret); 115 // now erase the secret 116 Arrays.fill(secret, (byte)0); 117 secret = tmp; 118 } 119 120 // XOR k with ipad and opad, respectively 121 for (int i = 0; i < blockLen; i++) { 122 int si = (i < secret.length) ? secret[i] : 0; 123 k_ipad[i] = (byte)(si ^ 0x36); 124 k_opad[i] = (byte)(si ^ 0x5c); 125 } 126 127 // now erase the secret 128 Arrays.fill(secret, (byte)0); 129 secret = null; 130 131 engineReset(); 132 } 133 134 /** 135 * Processes the given byte. 136 * 137 * @param input the input byte to be processed. 138 */ 139 protected void engineUpdate(byte input) { 140 if (first == true) { 141 // compute digest for 1st pass; start with inner pad 142 md.update(k_ipad); 143 first = false; 144 } 145 146 // add the passed byte to the inner digest 147 md.update(input); 148 } 149 150 /** 151 * Processes the first <code>len</code> bytes in <code>input</code>, 152 * starting at <code>offset</code>. 153 * 154 * @param input the input buffer. 155 * @param offset the offset in <code>input</code> where the input starts. 156 * @param len the number of bytes to process. 157 */ 158 protected void engineUpdate(byte input[], int offset, int len) { 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 selected part of an array of bytes to the inner digest 166 md.update(input, offset, len); 167 } 168 169 /** 170 * Processes the <code>input.remaining()</code> bytes in the ByteBuffer 171 * <code>input</code>. 172 * 173 * @param input the input byte buffer. 174 */ 175 protected void engineUpdate(ByteBuffer input) { 176 if (first == true) { 177 // compute digest for 1st pass; start with inner pad 178 md.update(k_ipad); 179 first = false; 180 } 181 182 md.update(input); 183 } 184 185 /** 186 * Completes the HMAC computation and resets the HMAC for further use, 187 * maintaining the secret key that the HMAC was initialized with. 188 * 189 * @return the HMAC result. 190 */ 191 protected byte[] engineDoFinal() { 192 if (first == true) { 193 // compute digest for 1st pass; start with inner pad 194 md.update(k_ipad); 195 } else { 196 first = true; 197 } 198 199 try { 200 // finish the inner digest 201 byte[] tmp = md.digest(); 202 203 // compute digest for 2nd pass; start with outer pad 204 md.update(k_opad); 205 // add result of 1st hash 206 md.update(tmp); 207 208 md.digest(tmp, 0, tmp.length); 209 return tmp; 210 } catch (DigestException e) { 211 // should never occur 212 throw new ProviderException(e); 213 } 214 } 215 216 /** 217 * Resets the HMAC for further use, maintaining the secret key that the 218 * HMAC was initialized with. 219 */ 220 protected void engineReset() { 221 if (first == false) { 222 md.reset(); 223 first = true; 224 } 225 } 226 227 /* 228 * Clones this object. 229 */ 230 public Object clone() throws CloneNotSupportedException { 231 HmacCore copy = (HmacCore) super.clone(); 232 copy.md = (MessageDigest) md.clone(); 233 copy.k_ipad = k_ipad.clone(); 234 copy.k_opad = k_opad.clone(); 235 return copy; 236 } 237 238 // nested static class for the HmacSHA224 implementation 239 public static final class HmacSHA224 extends HmacCore { 240 public HmacSHA224() throws NoSuchAlgorithmException { 241 super("SHA-224", 64); 242 } 243 } 244 245 // nested static class for the HmacSHA256 implementation 246 public static final class HmacSHA256 extends HmacCore { 247 public HmacSHA256() throws NoSuchAlgorithmException { 248 super("SHA-256", 64); 249 } 250 } 251 252 // nested static class for the HmacSHA384 implementation 253 public static final class HmacSHA384 extends HmacCore { 254 public HmacSHA384() throws NoSuchAlgorithmException { 255 super("SHA-384", 128); 256 } 257 } 258 259 // nested static class for the HmacSHA512 implementation 260 public static final class HmacSHA512 extends HmacCore { 261 public HmacSHA512() throws NoSuchAlgorithmException { 262 super("SHA-512", 128); 263 } 264 } 265 }