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      */
SslMacCore(String digestAlgorithm, byte[] pad1, byte[] pad2)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      */
getDigestLength()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      */
init(Key key, AlgorithmParameterSpec params)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      */
update(byte input)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      */
update(byte input[], int offset, int len)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 
update(ByteBuffer input)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      */
doFinal()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      */
reset()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;
SslMacMD5()201         public SslMacMD5() throws NoSuchAlgorithmException {
202             core = new SslMacCore("MD5", md5Pad1, md5Pad2);
203         }
engineGetMacLength()204         protected int engineGetMacLength() {
205             return core.getDigestLength();
206         }
engineInit(Key key, AlgorithmParameterSpec params)207         protected void engineInit(Key key, AlgorithmParameterSpec params)
208                 throws InvalidKeyException, InvalidAlgorithmParameterException {
209             core.init(key, params);
210         }
engineUpdate(byte input)211         protected void engineUpdate(byte input) {
212             core.update(input);
213         }
engineUpdate(byte input[], int offset, int len)214         protected void engineUpdate(byte input[], int offset, int len) {
215             core.update(input, offset, len);
216         }
engineUpdate(ByteBuffer input)217         protected void engineUpdate(ByteBuffer input) {
218             core.update(input);
219         }
engineDoFinal()220         protected byte[] engineDoFinal() {
221             return core.doFinal();
222         }
engineReset()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;
SslMacSHA1()234         public SslMacSHA1() throws NoSuchAlgorithmException {
235             core = new SslMacCore("SHA", shaPad1, shaPad2);
236         }
engineGetMacLength()237         protected int engineGetMacLength() {
238             return core.getDigestLength();
239         }
engineInit(Key key, AlgorithmParameterSpec params)240         protected void engineInit(Key key, AlgorithmParameterSpec params)
241                 throws InvalidKeyException, InvalidAlgorithmParameterException {
242             core.init(key, params);
243         }
engineUpdate(byte input)244         protected void engineUpdate(byte input) {
245             core.update(input);
246         }
engineUpdate(byte input[], int offset, int len)247         protected void engineUpdate(byte input[], int offset, int len) {
248             core.update(input, offset, len);
249         }
engineUpdate(ByteBuffer input)250         protected void engineUpdate(ByteBuffer input) {
251             core.update(input);
252         }
engineDoFinal()253         protected byte[] engineDoFinal() {
254             return core.doFinal();
255         }
engineReset()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 }
265