TlsPrfGenerator.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 2005, 2013, 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 com.sun.crypto.provider; 27 28import java.util.Arrays; 29 30import java.security.*; 31import java.security.spec.AlgorithmParameterSpec; 32 33import javax.crypto.*; 34import javax.crypto.spec.SecretKeySpec; 35 36import sun.security.internal.spec.TlsPrfParameterSpec; 37 38/** 39 * KeyGenerator implementation for the TLS PRF function. 40 * <p> 41 * This class duplicates the HMAC functionality (RFC 2104) with 42 * performance optimizations (e.g. XOR'ing keys with padding doesn't 43 * need to be redone for each HMAC operation). 44 * 45 * @author Andreas Sterbenz 46 * @since 1.6 47 */ 48abstract class TlsPrfGenerator extends KeyGeneratorSpi { 49 50 // magic constants and utility functions, also used by other files 51 // in this package 52 53 private static final byte[] B0 = new byte[0]; 54 55 static final byte[] LABEL_MASTER_SECRET = // "master secret" 56 { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 }; 57 58 static final byte[] LABEL_KEY_EXPANSION = // "key expansion" 59 { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 }; 60 61 static final byte[] LABEL_CLIENT_WRITE_KEY = // "client write key" 62 { 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32, 63 107, 101, 121 }; 64 65 static final byte[] LABEL_SERVER_WRITE_KEY = // "server write key" 66 { 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32, 67 107, 101, 121 }; 68 69 static final byte[] LABEL_IV_BLOCK = // "IV block" 70 { 73, 86, 32, 98, 108, 111, 99, 107 }; 71 72 /* 73 * TLS HMAC "inner" and "outer" padding. This isn't a function 74 * of the digest algorithm. 75 */ 76 private static final byte[] HMAC_ipad64 = genPad((byte)0x36, 64); 77 private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128); 78 private static final byte[] HMAC_opad64 = genPad((byte)0x5c, 64); 79 private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128); 80 81 // SSL3 magic mix constants ("A", "BB", "CCC", ...) 82 static final byte[][] SSL3_CONST = genConst(); 83 84 static byte[] genPad(byte b, int count) { 85 byte[] padding = new byte[count]; 86 Arrays.fill(padding, b); 87 return padding; 88 } 89 90 static byte[] concat(byte[] b1, byte[] b2) { 91 int n1 = b1.length; 92 int n2 = b2.length; 93 byte[] b = new byte[n1 + n2]; 94 System.arraycopy(b1, 0, b, 0, n1); 95 System.arraycopy(b2, 0, b, n1, n2); 96 return b; 97 } 98 99 private static byte[][] genConst() { 100 int n = 10; 101 byte[][] arr = new byte[n][]; 102 for (int i = 0; i < n; i++) { 103 byte[] b = new byte[i + 1]; 104 Arrays.fill(b, (byte)('A' + i)); 105 arr[i] = b; 106 } 107 return arr; 108 } 109 110 // PRF implementation 111 112 private static final String MSG = "TlsPrfGenerator must be " 113 + "initialized using a TlsPrfParameterSpec"; 114 115 @SuppressWarnings("deprecation") 116 private TlsPrfParameterSpec spec; 117 118 public TlsPrfGenerator() { 119 } 120 121 protected void engineInit(SecureRandom random) { 122 throw new InvalidParameterException(MSG); 123 } 124 125 @SuppressWarnings("deprecation") 126 protected void engineInit(AlgorithmParameterSpec params, 127 SecureRandom random) throws InvalidAlgorithmParameterException { 128 if (params instanceof TlsPrfParameterSpec == false) { 129 throw new InvalidAlgorithmParameterException(MSG); 130 } 131 this.spec = (TlsPrfParameterSpec)params; 132 SecretKey key = spec.getSecret(); 133 if ((key != null) && ("RAW".equals(key.getFormat()) == false)) { 134 throw new InvalidAlgorithmParameterException( 135 "Key encoding format must be RAW"); 136 } 137 } 138 139 protected void engineInit(int keysize, SecureRandom random) { 140 throw new InvalidParameterException(MSG); 141 } 142 143 SecretKey engineGenerateKey0(boolean tls12) { 144 if (spec == null) { 145 throw new IllegalStateException( 146 "TlsPrfGenerator must be initialized"); 147 } 148 SecretKey key = spec.getSecret(); 149 byte[] secret = (key == null) ? null : key.getEncoded(); 150 try { 151 byte[] labelBytes = spec.getLabel().getBytes("UTF8"); 152 int n = spec.getOutputLength(); 153 byte[] prfBytes = (tls12 ? 154 doTLS12PRF(secret, labelBytes, spec.getSeed(), n, 155 spec.getPRFHashAlg(), spec.getPRFHashLength(), 156 spec.getPRFBlockSize()) : 157 doTLS10PRF(secret, labelBytes, spec.getSeed(), n)); 158 return new SecretKeySpec(prfBytes, "TlsPrf"); 159 } catch (GeneralSecurityException e) { 160 throw new ProviderException("Could not generate PRF", e); 161 } catch (java.io.UnsupportedEncodingException e) { 162 throw new ProviderException("Could not generate PRF", e); 163 } 164 } 165 166 static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, 167 byte[] seed, int outputLength, 168 String prfHash, int prfHashLength, int prfBlockSize) 169 throws NoSuchAlgorithmException, DigestException { 170 if (prfHash == null) { 171 throw new NoSuchAlgorithmException("Unspecified PRF algorithm"); 172 } 173 MessageDigest prfMD = MessageDigest.getInstance(prfHash); 174 return doTLS12PRF(secret, labelBytes, seed, outputLength, 175 prfMD, prfHashLength, prfBlockSize); 176 } 177 178 static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, 179 byte[] seed, int outputLength, 180 MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize) 181 throws DigestException { 182 183 if (secret == null) { 184 secret = B0; 185 } 186 187 // If we have a long secret, digest it first. 188 if (secret.length > mdPRFBlockSize) { 189 secret = mdPRF.digest(secret); 190 } 191 192 byte[] output = new byte[outputLength]; 193 byte [] ipad; 194 byte [] opad; 195 196 switch (mdPRFBlockSize) { 197 case 64: 198 ipad = HMAC_ipad64.clone(); 199 opad = HMAC_opad64.clone(); 200 break; 201 case 128: 202 ipad = HMAC_ipad128.clone(); 203 opad = HMAC_opad128.clone(); 204 break; 205 default: 206 throw new DigestException("Unexpected block size."); 207 } 208 209 // P_HASH(Secret, label + seed) 210 expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes, 211 seed, output, ipad, opad); 212 213 return output; 214 } 215 216 static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, 217 byte[] seed, int outputLength) throws NoSuchAlgorithmException, 218 DigestException { 219 MessageDigest md5 = MessageDigest.getInstance("MD5"); 220 MessageDigest sha = MessageDigest.getInstance("SHA1"); 221 return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha); 222 } 223 224 static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, 225 byte[] seed, int outputLength, MessageDigest md5, 226 MessageDigest sha) throws DigestException { 227 /* 228 * Split the secret into two halves S1 and S2 of same length. 229 * S1 is taken from the first half of the secret, S2 from the 230 * second half. 231 * Their length is created by rounding up the length of the 232 * overall secret divided by two; thus, if the original secret 233 * is an odd number of bytes long, the last byte of S1 will be 234 * the same as the first byte of S2. 235 * 236 * Note: Instead of creating S1 and S2, we determine the offset into 237 * the overall secret where S2 starts. 238 */ 239 240 if (secret == null) { 241 secret = B0; 242 } 243 int off = secret.length >> 1; 244 int seclen = off + (secret.length & 1); 245 246 byte[] secKey = secret; 247 int keyLen = seclen; 248 byte[] output = new byte[outputLength]; 249 250 // P_MD5(S1, label + seed) 251 // If we have a long secret, digest it first. 252 if (seclen > 64) { // 64: block size of HMAC-MD5 253 md5.update(secret, 0, seclen); 254 secKey = md5.digest(); 255 keyLen = secKey.length; 256 } 257 expand(md5, 16, secKey, 0, keyLen, labelBytes, seed, output, 258 HMAC_ipad64.clone(), HMAC_opad64.clone()); 259 260 // P_SHA-1(S2, label + seed) 261 // If we have a long secret, digest it first. 262 if (seclen > 64) { // 64: block size of HMAC-SHA1 263 sha.update(secret, off, seclen); 264 secKey = sha.digest(); 265 keyLen = secKey.length; 266 off = 0; 267 } 268 expand(sha, 20, secKey, off, keyLen, labelBytes, seed, output, 269 HMAC_ipad64.clone(), HMAC_opad64.clone()); 270 271 return output; 272 } 273 274 /* 275 * @param digest the MessageDigest to produce the HMAC 276 * @param hmacSize the HMAC size 277 * @param secret the secret 278 * @param secOff the offset into the secret 279 * @param secLen the secret length 280 * @param label the label 281 * @param seed the seed 282 * @param output the output array 283 */ 284 private static void expand(MessageDigest digest, int hmacSize, 285 byte[] secret, int secOff, int secLen, byte[] label, byte[] seed, 286 byte[] output, byte[] pad1, byte[] pad2) throws DigestException { 287 /* 288 * modify the padding used, by XORing the key into our copy of that 289 * padding. That's to avoid doing that for each HMAC computation. 290 */ 291 for (int i = 0; i < secLen; i++) { 292 pad1[i] ^= secret[i + secOff]; 293 pad2[i] ^= secret[i + secOff]; 294 } 295 296 byte[] tmp = new byte[hmacSize]; 297 byte[] aBytes = null; 298 299 /* 300 * compute: 301 * 302 * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + 303 * HMAC_hash(secret, A(2) + seed) + 304 * HMAC_hash(secret, A(3) + seed) + ... 305 * A() is defined as: 306 * 307 * A(0) = seed 308 * A(i) = HMAC_hash(secret, A(i-1)) 309 */ 310 int remaining = output.length; 311 int ofs = 0; 312 while (remaining > 0) { 313 /* 314 * compute A() ... 315 */ 316 // inner digest 317 digest.update(pad1); 318 if (aBytes == null) { 319 digest.update(label); 320 digest.update(seed); 321 } else { 322 digest.update(aBytes); 323 } 324 digest.digest(tmp, 0, hmacSize); 325 326 // outer digest 327 digest.update(pad2); 328 digest.update(tmp); 329 if (aBytes == null) { 330 aBytes = new byte[hmacSize]; 331 } 332 digest.digest(aBytes, 0, hmacSize); 333 334 /* 335 * compute HMAC_hash() ... 336 */ 337 // inner digest 338 digest.update(pad1); 339 digest.update(aBytes); 340 digest.update(label); 341 digest.update(seed); 342 digest.digest(tmp, 0, hmacSize); 343 344 // outer digest 345 digest.update(pad2); 346 digest.update(tmp); 347 digest.digest(tmp, 0, hmacSize); 348 349 int k = Math.min(hmacSize, remaining); 350 for (int i = 0; i < k; i++) { 351 output[ofs++] ^= tmp[i]; 352 } 353 remaining -= k; 354 } 355 } 356 357 /** 358 * A KeyGenerator implementation that supports TLS 1.2. 359 * <p> 360 * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF 361 * calculations. As of 2010, there is no PKCS11-level support for TLS 362 * 1.2 PRF calculations, and no known OS's have an internal variant 363 * we could use. Therefore for TLS 1.2, we are updating JSSE to request 364 * a different provider algorithm: "SunTls12Prf". If we reused the 365 * name "SunTlsPrf", the PKCS11 provider would need be updated to 366 * fail correctly when presented with the wrong version number 367 * (via Provider.Service.supportsParameters()), and add the 368 * appropriate supportsParamters() checks into KeyGenerators (not 369 * currently there). 370 */ 371 public static class V12 extends TlsPrfGenerator { 372 protected SecretKey engineGenerateKey() { 373 return engineGenerateKey0(true); 374 } 375 } 376 377 /** 378 * A KeyGenerator implementation that supports TLS 1.0/1.1. 379 */ 380 public static class V10 extends TlsPrfGenerator { 381 protected SecretKey engineGenerateKey() { 382 return engineGenerateKey0(false); 383 } 384 } 385} 386