MAC.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 1996, 2015, 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
26package sun.security.ssl;
27
28import java.security.InvalidKeyException;
29import java.security.NoSuchAlgorithmException;
30
31import java.nio.ByteBuffer;
32
33import javax.crypto.Mac;
34import javax.crypto.SecretKey;
35
36import sun.security.ssl.CipherSuite.MacAlg;
37import static sun.security.ssl.CipherSuite.*;
38import static sun.security.ssl.CipherSuite.MacAlg.*;
39
40/**
41 * This class computes the "Message Authentication Code" (MAC) for each
42 * SSL stream and block cipher message.  This is essentially a shared-secret
43 * signature, used to provide integrity protection for SSL messages.  The
44 * MAC is actually one of several keyed hashes, as associated with the cipher
45 * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.)
46 *
47 * @author David Brownell
48 * @author Andreas Sterbenz
49 */
50final class MAC extends Authenticator {
51
52    static final MAC TLS_NULL = new MAC(false);
53
54    // Value of the null MAC is fixed
55    private static final byte[] nullMAC = new byte[0];
56
57    // internal identifier for the MAC algorithm
58    private final MacAlg macAlg;
59
60    // JCE Mac object
61    private final Mac mac;
62
63    MAC(boolean isDTLS) {
64        super(isDTLS);
65
66        macAlg = M_NULL;
67        mac = null;
68    }
69
70    /**
71     * Set up, configured for the given MAC type and version.
72     */
73    MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key)
74            throws NoSuchAlgorithmException, InvalidKeyException {
75        super(protocolVersion);
76        this.macAlg = macAlg;
77
78        String algorithm;
79
80        // using SSL MAC computation?
81        boolean useSSLMac = (protocolVersion.v < ProtocolVersion.TLS10.v);
82
83        if (macAlg == M_MD5) {
84            algorithm = useSSLMac ? "SslMacMD5" : "HmacMD5";
85        } else if (macAlg == M_SHA) {
86            algorithm = useSSLMac ? "SslMacSHA1" : "HmacSHA1";
87        } else if (macAlg == M_SHA256) {
88            algorithm = "HmacSHA256";    // TLS 1.2+
89        } else if (macAlg == M_SHA384) {
90            algorithm = "HmacSHA384";    // TLS 1.2+
91        } else {
92            throw new RuntimeException("Unknown Mac " + macAlg);
93        }
94
95        mac = JsseJce.getMac(algorithm);
96        mac.init(key);
97    }
98
99    /**
100     * Returns the length of the MAC.
101     */
102    int MAClen() {
103        return macAlg.size;
104    }
105
106    /**
107     * Returns the hash function block length of the MAC alorithm.
108     */
109    int hashBlockLen() {
110        return macAlg.hashBlockSize;
111    }
112
113    /**
114     * Returns the hash function minimal padding length of the MAC alorithm.
115     */
116    int minimalPaddingLen() {
117        return macAlg.minimalPaddingSize;
118    }
119
120    /**
121     * Computes and returns the MAC for the data in this byte array.
122     *
123     * @param type record type
124     * @param buf compressed record on which the MAC is computed
125     * @param offset start of compressed record data
126     * @param len the size of the compressed record
127     * @param isSimulated if true, simulate the MAC computation
128     *
129     * @return the MAC result
130     */
131    final byte[] compute(byte type, byte buf[],
132            int offset, int len, boolean isSimulated) {
133        if (macAlg.size == 0) {
134            return nullMAC;
135        }
136
137        if (!isSimulated) {
138            // Uses the implicit sequence number for the computation.
139            byte[] additional = acquireAuthenticationBytes(type, len, null);
140            mac.update(additional);
141        }
142        mac.update(buf, offset, len);
143
144        return mac.doFinal();
145    }
146
147    /**
148     * Compute and returns the MAC for the remaining data
149     * in this ByteBuffer.
150     *
151     * On return, the bb position == limit, and limit will
152     * have not changed.
153     *
154     * @param type record type
155     * @param bb a ByteBuffer in which the position and limit
156     *          demarcate the data to be MAC'd.
157     * @param isSimulated if true, simulate the MAC computation
158     * @param sequence the explicit sequence number, or null if using
159     *        the implicit sequence number for the computation
160     *
161     * @return the MAC result
162     */
163    final byte[] compute(byte type, ByteBuffer bb,
164            byte[] sequence, boolean isSimulated) {
165
166        if (macAlg.size == 0) {
167            return nullMAC;
168        }
169
170        if (!isSimulated) {
171            // Uses the explicit sequence number for the computation.
172            byte[] additional =
173                    acquireAuthenticationBytes(type, bb.remaining(), sequence);
174            mac.update(additional);
175        }
176        mac.update(bb);
177
178        return mac.doFinal();
179    }
180
181    /**
182     * Compute and returns the MAC for the remaining data
183     * in this ByteBuffer.
184     *
185     * On return, the bb position == limit, and limit will
186     * have not changed.
187     *
188     * @param type record type
189     * @param bb a ByteBuffer in which the position and limit
190     *        demarcate the data to be MAC'd.
191     * @param isSimulated if true, simulate the the MAC computation
192     *
193     * @return the MAC result
194     */
195    final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) {
196        // Uses the implicit sequence number for the computation.
197        return compute(type, bb, null, isSimulated);
198    }
199}
200