1 /* 2 * Copyright (c) 2002, 2009, 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 the SHA-256, 42 * SHA-384, and SHA-512 HMACs. 43 * 44 * @author Jan Luehe 45 */ 46 final class HmacCore implements Cloneable { 47 48 private final MessageDigest md; 49 private final byte[] k_ipad; // inner padding - key XORd with ipad 50 private final 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 * Constructor used for cloning. 77 */ 78 private HmacCore(HmacCore other) throws CloneNotSupportedException { 79 this.md = (MessageDigest)other.md.clone(); 80 this.blockLen = other.blockLen; 81 this.k_ipad = (byte[])other.k_ipad.clone(); 82 this.k_opad = (byte[])other.k_opad.clone(); 83 this.first = other.first; 84 } 85 86 /** 87 * Returns the length of the HMAC in bytes. 88 * 89 * @return the HMAC length in bytes. 90 */ 91 int getDigestLength() { 92 return this.md.getDigestLength(); 93 } 94 95 /** 96 * Initializes the HMAC with the given secret key and algorithm parameters. 97 * 98 * @param key the secret key. 99 * @param params the algorithm parameters. 100 * 101 * @exception InvalidKeyException if the given key is inappropriate for 102 * initializing this MAC. 103 * @exception InvalidAlgorithmParameterException if the given algorithm 104 * parameters are inappropriate for this MAC. 105 */ 106 void init(Key key, AlgorithmParameterSpec params) 107 throws InvalidKeyException, InvalidAlgorithmParameterException { 108 109 if (params != null) { 110 throw new InvalidAlgorithmParameterException 111 ("HMAC does not use parameters"); 112 } 113 114 if (!(key instanceof SecretKey)) { 115 throw new InvalidKeyException("Secret key expected"); 116 } 117 118 byte[] secret = key.getEncoded(); 119 if (secret == null) { 120 throw new InvalidKeyException("Missing key data"); 121 } 122 123 // if key is longer than the block length, reset it using 124 // the message digest object. 125 if (secret.length > blockLen) { 126 byte[] tmp = md.digest(secret); 127 // now erase the secret 128 Arrays.fill(secret, (byte)0); 129 secret = tmp; 130 } 131 132 // XOR k with ipad and opad, respectively 133 for (int i = 0; i < blockLen; i++) { 134 int si = (i < secret.length) ? secret[i] : 0; 135 k_ipad[i] = (byte)(si ^ 0x36); 136 k_opad[i] = (byte)(si ^ 0x5c); 137 } 138 139 // now erase the secret 140 Arrays.fill(secret, (byte)0); 141 secret = null; 142 143 reset(); 144 } 145 146 /** 147 * Processes the given byte. 148 * 149 * @param input the input byte to be processed. 150 */ 151 void update(byte input) { 152 if (first == true) { 153 // compute digest for 1st pass; start with inner pad 154 md.update(k_ipad); 155 first = false; 156 } 157 158 // add the passed byte to the inner digest 159 md.update(input); 160 } 161 162 /** 163 * Processes the first <code>len</code> bytes in <code>input</code>, 164 * starting at <code>offset</code>. 165 * 166 * @param input the input buffer. 167 * @param offset the offset in <code>input</code> where the input starts. 168 * @param len the number of bytes to process. 169 */ 170 void update(byte input[], int offset, int len) { 171 if (first == true) { 172 // compute digest for 1st pass; start with inner pad 173 md.update(k_ipad); 174 first = false; 175 } 176 177 // add the selected part of an array of bytes to the inner digest 178 md.update(input, offset, len); 179 } 180 181 void update(ByteBuffer input) { 182 if (first == true) { 183 // compute digest for 1st pass; start with inner pad 184 md.update(k_ipad); 185 first = false; 186 } 187 188 md.update(input); 189 } 190 191 /** 192 * Completes the HMAC computation and resets the HMAC for further use, 193 * maintaining the secret key that the HMAC was initialized with. 194 * 195 * @return the HMAC result. 196 */ 197 byte[] doFinal() { 198 if (first == true) { 199 // compute digest for 1st pass; start with inner pad 200 md.update(k_ipad); 201 } else { 202 first = true; 203 } 204 205 try { 206 // finish the inner digest 207 byte[] tmp = md.digest(); 208 209 // compute digest for 2nd pass; start with outer pad 210 md.update(k_opad); 211 // add result of 1st hash 212 md.update(tmp); 213 214 md.digest(tmp, 0, tmp.length); 215 return tmp; 216 } catch (DigestException e) { 217 // should never occur 218 throw new ProviderException(e); 219 } 220 } 221 222 /** 223 * Resets the HMAC for further use, maintaining the secret key that the 224 * HMAC was initialized with. 225 */ 226 void reset() { 227 if (first == false) { 228 md.reset(); 229 first = true; 230 } 231 } 232 233 /* 234 * Clones this object. 235 */ 236 public Object clone() throws CloneNotSupportedException { 237 return new HmacCore(this); 238 } 239 240 // nested static class for the HmacSHA256 implementation 241 public static final class HmacSHA256 extends MacSpi implements Cloneable { 242 private final HmacCore core; 243 public HmacSHA256() throws NoSuchAlgorithmException { 244 core = new HmacCore("SHA-256", 64); 245 } 246 private HmacSHA256(HmacSHA256 base) throws CloneNotSupportedException { 247 core = (HmacCore)base.core.clone(); 248 } 249 protected int engineGetMacLength() { 250 return core.getDigestLength(); 251 } 252 protected void engineInit(Key key, AlgorithmParameterSpec params) 253 throws InvalidKeyException, InvalidAlgorithmParameterException { 254 core.init(key, params); 255 } 256 protected void engineUpdate(byte input) { 257 core.update(input); 258 } 259 protected void engineUpdate(byte input[], int offset, int len) { 260 core.update(input, offset, len); 261 } 262 protected void engineUpdate(ByteBuffer input) { 263 core.update(input); 264 } 265 protected byte[] engineDoFinal() { 266 return core.doFinal(); 267 } 268 protected void engineReset() { 269 core.reset(); 270 } 271 public Object clone() throws CloneNotSupportedException { 272 return new HmacSHA256(this); 273 } 274 } 275 276 // nested static class for the HmacSHA384 implementation 277 public static final class HmacSHA384 extends MacSpi implements Cloneable { 278 private final HmacCore core; 279 public HmacSHA384() throws NoSuchAlgorithmException { 280 core = new HmacCore("SHA-384", 128); 281 } 282 private HmacSHA384(HmacSHA384 base) throws CloneNotSupportedException { 283 core = (HmacCore)base.core.clone(); 284 } 285 protected int engineGetMacLength() { 286 return core.getDigestLength(); 287 } 288 protected void engineInit(Key key, AlgorithmParameterSpec params) 289 throws InvalidKeyException, InvalidAlgorithmParameterException { 290 core.init(key, params); 291 } 292 protected void engineUpdate(byte input) { 293 core.update(input); 294 } 295 protected void engineUpdate(byte input[], int offset, int len) { 296 core.update(input, offset, len); 297 } 298 protected void engineUpdate(ByteBuffer input) { 299 core.update(input); 300 } 301 protected byte[] engineDoFinal() { 302 return core.doFinal(); 303 } 304 protected void engineReset() { 305 core.reset(); 306 } 307 public Object clone() throws CloneNotSupportedException { 308 return new HmacSHA384(this); 309 } 310 } 311 312 // nested static class for the HmacSHA512 implementation 313 public static final class HmacSHA512 extends MacSpi implements Cloneable { 314 private final HmacCore core; 315 public HmacSHA512() throws NoSuchAlgorithmException { 316 core = new HmacCore("SHA-512", 128); 317 } 318 private HmacSHA512(HmacSHA512 base) throws CloneNotSupportedException { 319 core = (HmacCore)base.core.clone(); 320 } 321 protected int engineGetMacLength() { 322 return core.getDigestLength(); 323 } 324 protected void engineInit(Key key, AlgorithmParameterSpec params) 325 throws InvalidKeyException, InvalidAlgorithmParameterException { 326 core.init(key, params); 327 } 328 protected void engineUpdate(byte input) { 329 core.update(input); 330 } 331 protected void engineUpdate(byte input[], int offset, int len) { 332 core.update(input, offset, len); 333 } 334 protected void engineUpdate(ByteBuffer input) { 335 core.update(input); 336 } 337 protected byte[] engineDoFinal() { 338 return core.doFinal(); 339 } 340 protected void engineReset() { 341 core.reset(); 342 } 343 public Object clone() throws CloneNotSupportedException { 344 return new HmacSHA512(this); 345 } 346 } 347 348 } | 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 } |