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 }