1 /* 2 * Copyright (c) 2005, 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.nio.ByteBuffer; 29 30 import javax.crypto.MacSpi; 31 import javax.crypto.SecretKey; 32 import java.security.*; 33 import java.security.spec.AlgorithmParameterSpec; 34 35 import static com.sun.crypto.provider.TlsPrfGenerator.genPad; 36 37 /** 38 * This file contains the code for the SslMacMD5 and SslMacSHA1 implementations. 39 * The SSL 3.0 MAC is a variation of the HMAC algorithm. 40 * 41 * Note that we don't implement Cloneable as that is not needed for SSL. 42 * 43 * @author Andreas Sterbenz 44 * @since 1.6 45 */ 46 final class SslMacCore { 47 48 private final MessageDigest md; 49 private final byte[] pad1, pad2; 50 51 private boolean first; // Is this the first data to be processed? 52 private byte[] secret; 53 54 /** 55 * Standard constructor, creates a new SslMacCore instance instantiating 56 * a MessageDigest of the specified name. 57 */ 58 SslMacCore(String digestAlgorithm, byte[] pad1, byte[] pad2) 59 throws NoSuchAlgorithmException { 60 md = MessageDigest.getInstance(digestAlgorithm); 61 this.pad1 = pad1; 62 this.pad2 = pad2; 63 first = true; 64 } 65 66 /** 67 * Returns the length of the Mac in bytes. 68 * 69 * @return the Mac length in bytes. 70 */ 71 int getDigestLength() { 72 return md.getDigestLength(); 73 } 74 75 /** 76 * Initializes the Mac with the given secret key and algorithm parameters. 77 * 78 * @param key the secret key. 79 * @param params the algorithm parameters. 80 * 81 * @exception InvalidKeyException if the given key is inappropriate for 82 * initializing this MAC. 83 * @exception InvalidAlgorithmParameterException if the given algorithm 84 * parameters are inappropriate for this MAC. 85 */ 86 void init(Key key, AlgorithmParameterSpec params) 87 throws InvalidKeyException, InvalidAlgorithmParameterException { 88 89 if (params != null) { 90 throw new InvalidAlgorithmParameterException 91 ("SslMac does not use parameters"); 92 } 93 94 if (!(key instanceof SecretKey)) { 95 throw new InvalidKeyException("Secret key expected"); 96 } 97 98 secret = key.getEncoded(); 99 if (secret == null || secret.length == 0) { 100 throw new InvalidKeyException("Missing key data"); 101 } 102 103 reset(); 104 } 105 106 /** 107 * Processes the given byte. 108 * 109 * @param input the input byte to be processed. 110 */ 111 void update(byte input) { 112 if (first == true) { 113 // compute digest for 1st pass; start with inner pad 114 md.update(secret); 115 md.update(pad1); 116 first = false; 117 } 118 119 // add the passed byte to the inner digest 120 md.update(input); 121 } 122 123 /** 124 * Processes the first <code>len</code> bytes in <code>input</code>, 125 * starting at <code>offset</code>. 126 * 127 * @param input the input buffer. 128 * @param offset the offset in <code>input</code> where the input starts. 129 * @param len the number of bytes to process. 130 */ 131 void update(byte[] input, int offset, int len) { 132 if (first == true) { 133 // compute digest for 1st pass; start with inner pad 134 md.update(secret); 135 md.update(pad1); 136 first = false; 137 } 138 139 // add the selected part of an array of bytes to the inner digest 140 md.update(input, offset, len); 141 } 142 143 void update(ByteBuffer input) { 144 if (first == true) { 145 // compute digest for 1st pass; start with inner pad 146 md.update(secret); 147 md.update(pad1); 148 first = false; 149 } 150 151 md.update(input); 152 } 153 154 /** 155 * Completes the Mac computation and resets the Mac for further use, 156 * maintaining the secret key that the Mac was initialized with. 157 * 158 * @return the Mac result. 159 */ 160 byte[] doFinal() { 161 if (first == true) { 162 // compute digest for 1st pass; start with inner pad 163 md.update(secret); 164 md.update(pad1); 165 } else { 166 first = true; 167 } 168 169 try { 170 // finish the inner digest 171 byte[] tmp = md.digest(); 172 173 // compute digest for 2nd pass; start with outer pad 174 md.update(secret); 175 md.update(pad2); 176 // add result of 1st hash 177 md.update(tmp); 178 179 md.digest(tmp, 0, tmp.length); 180 return tmp; 181 } catch (DigestException e) { 182 // should never occur 183 throw new ProviderException(e); 184 } 185 } 186 187 /** 188 * Resets the Mac for further use, maintaining the secret key that the 189 * Mac was initialized with. 190 */ 191 void reset() { 192 if (first == false) { 193 md.reset(); 194 first = true; 195 } 196 } 197 198 // nested static class for the SslMacMD5 implementation 199 public static final class SslMacMD5 extends MacSpi { 200 private final SslMacCore core; 201 public SslMacMD5() throws NoSuchAlgorithmException { 202 core = new SslMacCore("MD5", md5Pad1, md5Pad2); 203 } 204 protected int engineGetMacLength() { 205 return core.getDigestLength(); 206 } 207 protected void engineInit(Key key, AlgorithmParameterSpec params) 208 throws InvalidKeyException, InvalidAlgorithmParameterException { 209 core.init(key, params); 210 } 211 protected void engineUpdate(byte input) { 212 core.update(input); 213 } 214 protected void engineUpdate(byte[] input, int offset, int len) { 215 core.update(input, offset, len); 216 } 217 protected void engineUpdate(ByteBuffer input) { 218 core.update(input); 219 } 220 protected byte[] engineDoFinal() { 221 return core.doFinal(); 222 } 223 protected void engineReset() { 224 core.reset(); 225 } 226 227 static final byte[] md5Pad1 = genPad((byte)0x36, 48); 228 static final byte[] md5Pad2 = genPad((byte)0x5c, 48); 229 } 230 231 // nested static class for the SslMacMD5 implementation 232 public static final class SslMacSHA1 extends MacSpi { 233 private final SslMacCore core; 234 public SslMacSHA1() throws NoSuchAlgorithmException { 235 core = new SslMacCore("SHA", shaPad1, shaPad2); 236 } 237 protected int engineGetMacLength() { 238 return core.getDigestLength(); 239 } 240 protected void engineInit(Key key, AlgorithmParameterSpec params) 241 throws InvalidKeyException, InvalidAlgorithmParameterException { 242 core.init(key, params); 243 } 244 protected void engineUpdate(byte input) { 245 core.update(input); 246 } 247 protected void engineUpdate(byte[] input, int offset, int len) { 248 core.update(input, offset, len); 249 } 250 protected void engineUpdate(ByteBuffer input) { 251 core.update(input); 252 } 253 protected byte[] engineDoFinal() { 254 return core.doFinal(); 255 } 256 protected void engineReset() { 257 core.reset(); 258 } 259 260 static final byte[] shaPad1 = genPad((byte)0x36, 40); 261 static final byte[] shaPad2 = genPad((byte)0x5c, 40); 262 } 263 264 }