1 /*
   2  * Copyright (c) 2018, 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 sun.security.ssl;
  27 
  28 import java.nio.ByteBuffer;
  29 import java.security.AccessController;
  30 import java.security.GeneralSecurityException;
  31 import java.security.InvalidAlgorithmParameterException;
  32 import java.security.InvalidKeyException;
  33 import java.security.Key;
  34 import java.security.PrivilegedAction;
  35 import java.security.SecureRandom;
  36 import java.security.Security;
  37 import java.security.spec.AlgorithmParameterSpec;
  38 import java.util.AbstractMap.SimpleImmutableEntry;
  39 import java.util.Arrays;
  40 import java.util.HashMap;
  41 import java.util.Map;
  42 import javax.crypto.BadPaddingException;
  43 import javax.crypto.Cipher;
  44 import javax.crypto.IllegalBlockSizeException;
  45 import javax.crypto.SecretKey;
  46 import javax.crypto.ShortBufferException;
  47 import javax.crypto.spec.GCMParameterSpec;
  48 import javax.crypto.spec.IvParameterSpec;
  49 import sun.security.ssl.Authenticator.MAC;
  50 import static sun.security.ssl.CipherType.*;
  51 import static sun.security.ssl.JsseJce.*;
  52 
  53 enum SSLCipher {
  54     // exportable ciphers
  55     @SuppressWarnings({"unchecked", "rawtypes"})
  56     B_NULL("NULL", NULL_CIPHER, 0, 0, 0, 0, true, true,
  57         (Map.Entry<ReadCipherGenerator,
  58                 ProtocolVersion[]>[])(new Map.Entry[] {
  59             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
  60                 new NullReadCipherGenerator(),
  61                 ProtocolVersion.PROTOCOLS_OF_NONE
  62             ),
  63             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
  64                 new NullReadCipherGenerator(),
  65                 ProtocolVersion.PROTOCOLS_TO_13
  66             )
  67         }),
  68         (Map.Entry<WriteCipherGenerator,
  69                 ProtocolVersion[]>[])(new Map.Entry[] {
  70             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
  71                 new NullWriteCipherGenerator(),
  72                 ProtocolVersion.PROTOCOLS_OF_NONE
  73             ),
  74             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
  75                 new NullWriteCipherGenerator(),
  76                 ProtocolVersion.PROTOCOLS_TO_13
  77             )
  78         })),
  79 
  80     @SuppressWarnings({"unchecked", "rawtypes"})
  81     B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true, true,
  82         (Map.Entry<ReadCipherGenerator,
  83                 ProtocolVersion[]>[])(new Map.Entry[] {
  84             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
  85                 new StreamReadCipherGenerator(),
  86                 ProtocolVersion.PROTOCOLS_TO_10
  87             )
  88         }),
  89         (Map.Entry<WriteCipherGenerator,
  90                 ProtocolVersion[]>[])(new Map.Entry[] {
  91             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
  92                 new StreamWriteCipherGenerator(),
  93                 ProtocolVersion.PROTOCOLS_TO_10
  94             )
  95         })),
  96 
  97     @SuppressWarnings({"unchecked", "rawtypes"})
  98     B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false, true,
  99         (Map.Entry<ReadCipherGenerator,
 100                 ProtocolVersion[]>[])(new Map.Entry[] {
 101             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 102                 new StreamReadCipherGenerator(),
 103                 ProtocolVersion.PROTOCOLS_TO_10
 104             )
 105         }),
 106         (Map.Entry<WriteCipherGenerator,
 107                 ProtocolVersion[]>[])(new Map.Entry[] {
 108             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 109                 new StreamWriteCipherGenerator(),
 110                 ProtocolVersion.PROTOCOLS_TO_10
 111             )
 112         })),
 113 
 114     @SuppressWarnings({"unchecked", "rawtypes"})
 115     B_DES_40(CIPHER_DES,  BLOCK_CIPHER, 5, 8, 8, 0, true, true,
 116         (Map.Entry<ReadCipherGenerator,
 117                 ProtocolVersion[]>[])(new Map.Entry[] {
 118             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 119                 new T10BlockReadCipherGenerator(),
 120                 ProtocolVersion.PROTOCOLS_TO_10
 121             )
 122         }),
 123         (Map.Entry<WriteCipherGenerator,
 124                 ProtocolVersion[]>[])(new Map.Entry[] {
 125             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 126                 new T10BlockWriteCipherGenerator(),
 127                 ProtocolVersion.PROTOCOLS_TO_10
 128             )
 129         })),
 130 
 131     // domestic strength ciphers
 132     @SuppressWarnings({"unchecked", "rawtypes"})
 133     B_RC4_128(CIPHER_RC4, STREAM_CIPHER, 16, 16, 0, 0, true, false,
 134         (Map.Entry<ReadCipherGenerator,
 135                 ProtocolVersion[]>[])(new Map.Entry[] {
 136             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 137                 new StreamReadCipherGenerator(),
 138                 ProtocolVersion.PROTOCOLS_TO_12
 139             )
 140         }),
 141         (Map.Entry<WriteCipherGenerator,
 142                 ProtocolVersion[]>[])(new Map.Entry[] {
 143             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 144                 new StreamWriteCipherGenerator(),
 145                 ProtocolVersion.PROTOCOLS_TO_12
 146             )
 147         })),
 148 
 149     @SuppressWarnings({"unchecked", "rawtypes"})
 150     B_DES(CIPHER_DES, BLOCK_CIPHER, 8, 8, 8, 0, true, false,
 151         (Map.Entry<ReadCipherGenerator,
 152                 ProtocolVersion[]>[])(new Map.Entry[] {
 153             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 154                 new T10BlockReadCipherGenerator(),
 155                 ProtocolVersion.PROTOCOLS_TO_10
 156             ),
 157             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 158                 new T11BlockReadCipherGenerator(),
 159                 ProtocolVersion.PROTOCOLS_OF_11
 160             )
 161         }),
 162         (Map.Entry<WriteCipherGenerator,
 163                 ProtocolVersion[]>[])(new Map.Entry[] {
 164             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 165                 new T10BlockWriteCipherGenerator(),
 166                 ProtocolVersion.PROTOCOLS_TO_10
 167             ),
 168             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 169                 new T11BlockWriteCipherGenerator(),
 170                 ProtocolVersion.PROTOCOLS_OF_11
 171             )
 172         })),
 173 
 174     @SuppressWarnings({"unchecked", "rawtypes"})
 175     B_3DES(CIPHER_3DES, BLOCK_CIPHER, 24, 24, 8, 0, true, false,
 176         (Map.Entry<ReadCipherGenerator,
 177                 ProtocolVersion[]>[])(new Map.Entry[] {
 178             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 179                 new T10BlockReadCipherGenerator(),
 180                 ProtocolVersion.PROTOCOLS_TO_10
 181             ),
 182             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 183                 new T11BlockReadCipherGenerator(),
 184                 ProtocolVersion.PROTOCOLS_11_12
 185             )
 186         }),
 187         (Map.Entry<WriteCipherGenerator,
 188                 ProtocolVersion[]>[])(new Map.Entry[] {
 189             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 190                 new T10BlockWriteCipherGenerator(),
 191                 ProtocolVersion.PROTOCOLS_TO_10
 192             ),
 193             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 194                 new T11BlockWriteCipherGenerator(),
 195                 ProtocolVersion.PROTOCOLS_11_12
 196             )
 197         })),
 198 
 199     @SuppressWarnings({"unchecked", "rawtypes"})
 200     B_IDEA("IDEA", BLOCK_CIPHER, 16, 16, 8, 0, false, false,
 201         (Map.Entry<ReadCipherGenerator,
 202                 ProtocolVersion[]>[])(new Map.Entry[] {
 203             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 204                 null,
 205                 ProtocolVersion.PROTOCOLS_TO_12
 206             )
 207         }),
 208         (Map.Entry<WriteCipherGenerator,
 209                 ProtocolVersion[]>[])(new Map.Entry[] {
 210             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 211                 null,
 212                 ProtocolVersion.PROTOCOLS_TO_12
 213             )
 214         })),
 215 
 216     @SuppressWarnings({"unchecked", "rawtypes"})
 217     B_AES_128(CIPHER_AES, BLOCK_CIPHER, 16, 16, 16, 0, true, false,
 218         (Map.Entry<ReadCipherGenerator,
 219                 ProtocolVersion[]>[])(new Map.Entry[] {
 220             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 221                 new T10BlockReadCipherGenerator(),
 222                 ProtocolVersion.PROTOCOLS_TO_10
 223             ),
 224             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 225                 new T11BlockReadCipherGenerator(),
 226                 ProtocolVersion.PROTOCOLS_11_12
 227             )
 228         }),
 229         (Map.Entry<WriteCipherGenerator,
 230                 ProtocolVersion[]>[])(new Map.Entry[] {
 231             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 232                 new T10BlockWriteCipherGenerator(),
 233                 ProtocolVersion.PROTOCOLS_TO_10
 234             ),
 235             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 236                 new T11BlockWriteCipherGenerator(),
 237                 ProtocolVersion.PROTOCOLS_11_12
 238             )
 239         })),
 240 
 241     @SuppressWarnings({"unchecked", "rawtypes"})
 242     B_AES_256(CIPHER_AES, BLOCK_CIPHER, 32, 32, 16, 0, true, false,
 243         (Map.Entry<ReadCipherGenerator,
 244                 ProtocolVersion[]>[])(new Map.Entry[] {
 245             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 246                 new T10BlockReadCipherGenerator(),
 247                 ProtocolVersion.PROTOCOLS_TO_10
 248             ),
 249             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 250                 new T11BlockReadCipherGenerator(),
 251                 ProtocolVersion.PROTOCOLS_11_12
 252             )
 253         }),
 254         (Map.Entry<WriteCipherGenerator,
 255                 ProtocolVersion[]>[])(new Map.Entry[] {
 256             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 257                 new T10BlockWriteCipherGenerator(),
 258                 ProtocolVersion.PROTOCOLS_TO_10
 259             ),
 260             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 261                 new T11BlockWriteCipherGenerator(),
 262                 ProtocolVersion.PROTOCOLS_11_12
 263             )
 264         })),
 265 
 266     @SuppressWarnings({"unchecked", "rawtypes"})
 267     B_AES_128_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 16, 16, 12, 4, true, false,
 268         (Map.Entry<ReadCipherGenerator,
 269                 ProtocolVersion[]>[])(new Map.Entry[] {
 270             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 271                 new T12GcmReadCipherGenerator(),
 272                 ProtocolVersion.PROTOCOLS_OF_12
 273             )
 274         }),
 275         (Map.Entry<WriteCipherGenerator,
 276                 ProtocolVersion[]>[])(new Map.Entry[] {
 277             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 278                 new T12GcmWriteCipherGenerator(),
 279                 ProtocolVersion.PROTOCOLS_OF_12
 280             )
 281         })),
 282 
 283     @SuppressWarnings({"unchecked", "rawtypes"})
 284     B_AES_256_GCM(CIPHER_AES_GCM, AEAD_CIPHER, 32, 32, 12, 4, true, false,
 285         (Map.Entry<ReadCipherGenerator,
 286                 ProtocolVersion[]>[])(new Map.Entry[] {
 287             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 288                 new T12GcmReadCipherGenerator(),
 289                 ProtocolVersion.PROTOCOLS_OF_12
 290             )
 291         }),
 292         (Map.Entry<WriteCipherGenerator,
 293                 ProtocolVersion[]>[])(new Map.Entry[] {
 294             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 295                 new T12GcmWriteCipherGenerator(),
 296                 ProtocolVersion.PROTOCOLS_OF_12
 297             )
 298         })),
 299 
 300     @SuppressWarnings({"unchecked", "rawtypes"})
 301     B_AES_128_GCM_IV(CIPHER_AES_GCM, AEAD_CIPHER, 16, 16, 12, 0, true, false,
 302         (Map.Entry<ReadCipherGenerator,
 303                 ProtocolVersion[]>[])(new Map.Entry[] {
 304             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 305                 new T13GcmReadCipherGenerator(),
 306                 ProtocolVersion.PROTOCOLS_OF_13
 307             )
 308         }),
 309         (Map.Entry<WriteCipherGenerator,
 310                 ProtocolVersion[]>[])(new Map.Entry[] {
 311             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 312                 new T13GcmWriteCipherGenerator(),
 313                 ProtocolVersion.PROTOCOLS_OF_13
 314             )
 315         })),
 316 
 317     @SuppressWarnings({"unchecked", "rawtypes"})
 318     B_AES_256_GCM_IV(CIPHER_AES_GCM, AEAD_CIPHER, 32, 32, 12, 0, true, false,
 319         (Map.Entry<ReadCipherGenerator,
 320                 ProtocolVersion[]>[])(new Map.Entry[] {
 321             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 322                 new T13GcmReadCipherGenerator(),
 323                 ProtocolVersion.PROTOCOLS_OF_13
 324             )
 325         }),
 326         (Map.Entry<WriteCipherGenerator,
 327                 ProtocolVersion[]>[])(new Map.Entry[] {
 328             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 329                 new T13GcmWriteCipherGenerator(),
 330                 ProtocolVersion.PROTOCOLS_OF_13
 331             )
 332         })),
 333 
 334     @SuppressWarnings({"unchecked", "rawtypes"})
 335     B_CC20_P1305(CIPHER_CHACHA20_POLY1305, AEAD_CIPHER, 32, 32, 12,
 336             12, true, false,
 337         (Map.Entry<ReadCipherGenerator,
 338                 ProtocolVersion[]>[])(new Map.Entry[] {
 339             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 340                 new T12CC20P1305ReadCipherGenerator(),
 341                 ProtocolVersion.PROTOCOLS_OF_12
 342             ),
 343             new SimpleImmutableEntry<ReadCipherGenerator, ProtocolVersion[]>(
 344                 new T13CC20P1305ReadCipherGenerator(),
 345                 ProtocolVersion.PROTOCOLS_OF_13
 346             )
 347         }),
 348         (Map.Entry<WriteCipherGenerator,
 349                 ProtocolVersion[]>[])(new Map.Entry[] {
 350             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 351                 new T12CC20P1305WriteCipherGenerator(),
 352                 ProtocolVersion.PROTOCOLS_OF_12
 353             ),
 354             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
 355                 new T13CC20P1305WriteCipherGenerator(),
 356                 ProtocolVersion.PROTOCOLS_OF_13
 357             )
 358         }));
 359 
 360     // descriptive name including key size, e.g. AES/128
 361     final String description;
 362 
 363     // JCE cipher transformation string, e.g. AES/CBC/NoPadding
 364     final String transformation;
 365 
 366     // algorithm name, e.g. AES
 367     final String algorithm;
 368 
 369     // supported and compile time enabled. Also see isAvailable()
 370     final boolean allowed;
 371 
 372     // number of bytes of entropy in the key
 373     final int keySize;
 374 
 375     // length of the actual cipher key in bytes.
 376     // for non-exportable ciphers, this is the same as keySize
 377     final int expandedKeySize;
 378 
 379     // size of the IV
 380     final int ivSize;
 381 
 382     // size of fixed IV
 383     //
 384     // record_iv_length = ivSize - fixedIvSize
 385     final int fixedIvSize;
 386 
 387     // exportable under 512/40 bit rules
 388     final boolean exportable;
 389 
 390     // Is the cipher algorithm of Cipher Block Chaining (CBC) mode?
 391     final CipherType cipherType;
 392 
 393     // size of the authentication tag, only applicable to cipher suites in
 394     // Galois Counter Mode (GCM)
 395     //
 396     // As far as we know, all supported GCM cipher suites use 128-bits
 397     // authentication tags.
 398     final int tagSize = 16;
 399 
 400     // runtime availability
 401     private final boolean isAvailable;
 402 
 403     private final Map.Entry<ReadCipherGenerator,
 404             ProtocolVersion[]>[] readCipherGenerators;
 405     private final Map.Entry<WriteCipherGenerator,
 406             ProtocolVersion[]>[] writeCipherGenerators;
 407 
 408     // Map of Ciphers listed in jdk.tls.keyLimits
 409     private static final HashMap<String, Long> cipherLimits = new HashMap<>();
 410 
 411     // Keywords found on the jdk.tls.keyLimits security property.
 412     final static String tag[] = {"KEYUPDATE"};
 413 
 414     static  {
 415         final long max = 4611686018427387904L; // 2^62
 416         String prop = AccessController.doPrivileged(
 417                 new PrivilegedAction<String>() {
 418             @Override
 419             public String run() {
 420                 return Security.getProperty("jdk.tls.keyLimits");
 421             }
 422         });
 423 
 424         if (prop != null) {
 425             String propvalue[] = prop.split(",");
 426 
 427             for (String entry : propvalue) {
 428                 int index;
 429                 // If this is not a UsageLimit, goto to next entry.
 430                 String values[] = entry.trim().toUpperCase().split(" ");
 431 
 432                 if (values[1].contains(tag[0])) {
 433                     index = 0;
 434                 } else {
 435                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 436                         SSLLogger.fine("jdk.tls.keyLimits:  Unknown action:  " +
 437                                 entry);
 438                     }
 439                     continue;
 440                 }
 441 
 442                 long size;
 443                 int i = values[2].indexOf("^");
 444                 try {
 445                     if (i >= 0) {
 446                         size = (long) Math.pow(2,
 447                                 Integer.parseInt(values[2].substring(i + 1)));
 448                     } else {
 449                         size = Long.parseLong(values[2]);
 450                     }
 451                     if (size < 1 || size > max) {
 452                         throw new NumberFormatException(
 453                             "Length exceeded limits");
 454                     }
 455                 } catch (NumberFormatException e) {
 456                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 457                         SSLLogger.fine("jdk.tls.keyLimits:  " + e.getMessage() +
 458                                 ":  " +  entry);
 459                     }
 460                     continue;
 461                 }
 462                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 463                     SSLLogger.fine("jdk.tls.keyLimits:  entry = " + entry +
 464                             ". " + values[0] + ":" + tag[index] + " = " + size);
 465                 }
 466                 cipherLimits.put(values[0] + ":" + tag[index], size);
 467             }
 468         }
 469     }
 470 
 471     private SSLCipher(String transformation,
 472             CipherType cipherType, int keySize,
 473             int expandedKeySize, int ivSize,
 474             int fixedIvSize, boolean allowed, boolean exportable,
 475             Map.Entry<ReadCipherGenerator,
 476                     ProtocolVersion[]>[] readCipherGenerators,
 477             Map.Entry<WriteCipherGenerator,
 478                     ProtocolVersion[]>[] writeCipherGenerators) {
 479         this.transformation = transformation;
 480         String[] splits = transformation.split("/");
 481         this.algorithm = splits[0];
 482         this.cipherType = cipherType;
 483         this.description = this.algorithm + "/" + (keySize << 3);
 484         this.keySize = keySize;
 485         this.ivSize = ivSize;
 486         this.fixedIvSize = fixedIvSize;
 487         this.allowed = allowed;
 488 
 489         this.expandedKeySize = expandedKeySize;
 490         this.exportable = exportable;
 491 
 492         // availability of this bulk cipher
 493         //
 494         // We assume all supported ciphers are always available since they are
 495         // shipped with the SunJCE  provider.  However, AES/256 is unavailable
 496         // when the default JCE policy jurisdiction files are installed because
 497         // of key length restrictions.
 498         this.isAvailable = allowed && isUnlimited(keySize, transformation);
 499 
 500         this.readCipherGenerators = readCipherGenerators;
 501         this.writeCipherGenerators = writeCipherGenerators;
 502     }
 503 
 504     SSLReadCipher createReadCipher(Authenticator authenticator,
 505             ProtocolVersion protocolVersion,
 506             SecretKey key, IvParameterSpec iv,
 507             SecureRandom random) throws GeneralSecurityException {
 508         if (readCipherGenerators.length == 0) {
 509             return null;
 510         }
 511 
 512         ReadCipherGenerator rcg = null;
 513         for (Map.Entry<ReadCipherGenerator,
 514                 ProtocolVersion[]> me : readCipherGenerators) {
 515             for (ProtocolVersion pv : me.getValue()) {
 516                 if (protocolVersion == pv) {
 517                     rcg = me.getKey();
 518                 }
 519             }
 520         }
 521 
 522         if (rcg != null) {
 523             return rcg.createCipher(this, authenticator,
 524                     protocolVersion, transformation, key, iv, random);
 525         }
 526         return null;
 527     }
 528 
 529     SSLWriteCipher createWriteCipher(Authenticator authenticator,
 530             ProtocolVersion protocolVersion,
 531             SecretKey key, IvParameterSpec iv,
 532             SecureRandom random) throws GeneralSecurityException {
 533         if (readCipherGenerators.length == 0) {
 534             return null;
 535         }
 536 
 537         WriteCipherGenerator rcg = null;
 538         for (Map.Entry<WriteCipherGenerator,
 539                 ProtocolVersion[]> me : writeCipherGenerators) {
 540             for (ProtocolVersion pv : me.getValue()) {
 541                 if (protocolVersion == pv) {
 542                     rcg = me.getKey();
 543                 }
 544             }
 545         }
 546 
 547         if (rcg != null) {
 548             return rcg.createCipher(this, authenticator,
 549                     protocolVersion, transformation, key, iv, random);
 550         }
 551         return null;
 552     }
 553 
 554     /**
 555      * Test if this bulk cipher is available. For use by CipherSuite.
 556      */
 557     boolean isAvailable() {
 558         return this.isAvailable;
 559     }
 560 
 561     private static boolean isUnlimited(int keySize, String transformation) {
 562         int keySizeInBits = keySize * 8;
 563         if (keySizeInBits > 128) {    // need the JCE unlimited
 564                                       // strength jurisdiction policy
 565             try {
 566                 if (Cipher.getMaxAllowedKeyLength(
 567                         transformation) < keySizeInBits) {
 568                     return false;
 569                 }
 570             } catch (Exception e) {
 571                 return false;
 572             }
 573         }
 574 
 575         return true;
 576     }
 577 
 578     @Override
 579     public String toString() {
 580         return description;
 581     }
 582 
 583     interface ReadCipherGenerator {
 584         SSLReadCipher createCipher(SSLCipher sslCipher,
 585                 Authenticator authenticator,
 586                 ProtocolVersion protocolVersion, String algorithm,
 587                 Key key, AlgorithmParameterSpec params,
 588                 SecureRandom random) throws GeneralSecurityException;
 589     }
 590 
 591     abstract static class SSLReadCipher {
 592         final Authenticator authenticator;
 593         final ProtocolVersion protocolVersion;
 594         boolean keyLimitEnabled = false;
 595         long keyLimitCountdown = 0;
 596         SecretKey baseSecret;
 597 
 598         SSLReadCipher(Authenticator authenticator,
 599                 ProtocolVersion protocolVersion) {
 600             this.authenticator = authenticator;
 601             this.protocolVersion = protocolVersion;
 602         }
 603 
 604         static final SSLReadCipher nullTlsReadCipher() {
 605             try {
 606                 return B_NULL.createReadCipher(
 607                         Authenticator.nullTlsMac(),
 608                         ProtocolVersion.NONE, null, null, null);
 609             } catch (GeneralSecurityException gse) {
 610                 // unlikely
 611                 throw new RuntimeException("Cannot create NULL SSLCipher", gse);
 612             }
 613         }
 614 
 615         static final SSLReadCipher nullDTlsReadCipher() {
 616             try {
 617                 return B_NULL.createReadCipher(
 618                         Authenticator.nullDtlsMac(),
 619                         ProtocolVersion.NONE, null, null, null);
 620             } catch (GeneralSecurityException gse) {
 621                 // unlikely
 622                 throw new RuntimeException("Cannot create NULL SSLCipher", gse);
 623             }
 624         }
 625 
 626         abstract Plaintext decrypt(byte contentType, ByteBuffer bb,
 627                     byte[] sequence) throws GeneralSecurityException;
 628 
 629         void dispose() {
 630             // blank
 631         }
 632 
 633         abstract int estimateFragmentSize(int packetSize, int headerSize);
 634 
 635         boolean isNullCipher() {
 636             return false;
 637         }
 638 
 639         /**
 640          * Check if processed bytes have reached the key usage limit.
 641          * If key usage limit is not be monitored, return false.
 642          */
 643         public boolean atKeyLimit() {
 644             if (keyLimitCountdown >= 0) {
 645                 return false;
 646             }
 647 
 648             // Turn off limit checking as KeyUpdate will be occurring
 649             keyLimitEnabled = false;
 650             return true;
 651         }
 652     }
 653 
 654     interface WriteCipherGenerator {
 655         SSLWriteCipher createCipher(SSLCipher sslCipher,
 656                 Authenticator authenticator,
 657                 ProtocolVersion protocolVersion, String algorithm,
 658                 Key key, AlgorithmParameterSpec params,
 659                 SecureRandom random) throws GeneralSecurityException;
 660     }
 661 
 662     abstract static class SSLWriteCipher {
 663         final Authenticator authenticator;
 664         final ProtocolVersion protocolVersion;
 665         boolean keyLimitEnabled = false;
 666         long keyLimitCountdown = 0;
 667         SecretKey baseSecret;
 668 
 669         SSLWriteCipher(Authenticator authenticator,
 670                 ProtocolVersion protocolVersion) {
 671             this.authenticator = authenticator;
 672             this.protocolVersion = protocolVersion;
 673         }
 674 
 675         abstract int encrypt(byte contentType, ByteBuffer bb);
 676 
 677         static final SSLWriteCipher nullTlsWriteCipher() {
 678             try {
 679                 return B_NULL.createWriteCipher(
 680                         Authenticator.nullTlsMac(),
 681                         ProtocolVersion.NONE, null, null, null);
 682             } catch (GeneralSecurityException gse) {
 683                 // unlikely
 684                 throw new RuntimeException(
 685                         "Cannot create NULL SSL write Cipher", gse);
 686             }
 687         }
 688 
 689         static final SSLWriteCipher nullDTlsWriteCipher() {
 690             try {
 691                 return B_NULL.createWriteCipher(
 692                         Authenticator.nullDtlsMac(),
 693                         ProtocolVersion.NONE, null, null, null);
 694             } catch (GeneralSecurityException gse) {
 695                 // unlikely
 696                 throw new RuntimeException(
 697                         "Cannot create NULL SSL write Cipher", gse);
 698             }
 699         }
 700 
 701         void dispose() {
 702             // blank
 703         }
 704 
 705         abstract int getExplicitNonceSize();
 706         abstract int calculateFragmentSize(int packetLimit, int headerSize);
 707         abstract int calculatePacketSize(int fragmentSize, int headerSize);
 708 
 709         boolean isCBCMode() {
 710             return false;
 711         }
 712 
 713         boolean isNullCipher() {
 714             return false;
 715         }
 716 
 717         /**
 718          * Check if processed bytes have reached the key usage limit.
 719          * If key usage limit is not be monitored, return false.
 720          */
 721         public boolean atKeyLimit() {
 722             if (keyLimitCountdown >= 0) {
 723                 return false;
 724             }
 725 
 726             // Turn off limit checking as KeyUpdate will be occurring
 727             keyLimitEnabled = false;
 728             return true;
 729         }
 730     }
 731 
 732     private static final
 733             class NullReadCipherGenerator implements ReadCipherGenerator {
 734         @Override
 735         public SSLReadCipher createCipher(SSLCipher sslCipher,
 736                 Authenticator authenticator,
 737                 ProtocolVersion protocolVersion, String algorithm,
 738                 Key key, AlgorithmParameterSpec params,
 739                 SecureRandom random) throws GeneralSecurityException {
 740             return new NullReadCipher(authenticator, protocolVersion);
 741         }
 742 
 743         static final class NullReadCipher extends SSLReadCipher {
 744             NullReadCipher(Authenticator authenticator,
 745                     ProtocolVersion protocolVersion) {
 746                 super(authenticator, protocolVersion);
 747             }
 748 
 749             @Override
 750             public Plaintext decrypt(byte contentType, ByteBuffer bb,
 751                     byte[] sequence) throws GeneralSecurityException {
 752                 MAC signer = (MAC)authenticator;
 753                 if (signer.macAlg().size != 0) {
 754                     checkStreamMac(signer, bb, contentType, sequence);
 755                 } else {
 756                     authenticator.increaseSequenceNumber();
 757                 }
 758 
 759                 return new Plaintext(contentType,
 760                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
 761                         -1, -1L, bb.slice());
 762             }
 763 
 764             @Override
 765             int estimateFragmentSize(int packetSize, int headerSize) {
 766                 int macLen = ((MAC)authenticator).macAlg().size;
 767                 return packetSize - headerSize - macLen;
 768             }
 769 
 770             @Override
 771             boolean isNullCipher() {
 772                 return true;
 773             }
 774         }
 775     }
 776 
 777     private static final
 778             class NullWriteCipherGenerator implements WriteCipherGenerator {
 779         @Override
 780         public SSLWriteCipher createCipher(SSLCipher sslCipher,
 781                 Authenticator authenticator,
 782                 ProtocolVersion protocolVersion, String algorithm,
 783                 Key key, AlgorithmParameterSpec params,
 784                 SecureRandom random) throws GeneralSecurityException {
 785             return new NullWriteCipher(authenticator, protocolVersion);
 786         }
 787 
 788         static final class NullWriteCipher extends SSLWriteCipher {
 789             NullWriteCipher(Authenticator authenticator,
 790                     ProtocolVersion protocolVersion) {
 791                 super(authenticator, protocolVersion);
 792             }
 793 
 794             @Override
 795             public int encrypt(byte contentType, ByteBuffer bb) {
 796                 // add message authentication code
 797                 MAC signer = (MAC)authenticator;
 798                 if (signer.macAlg().size != 0) {
 799                     addMac(signer, bb, contentType);
 800                 } else {
 801                     authenticator.increaseSequenceNumber();
 802                 }
 803 
 804                 int len = bb.remaining();
 805                 bb.position(bb.limit());
 806                 return len;
 807             }
 808 
 809 
 810             @Override
 811             int getExplicitNonceSize() {
 812                 return 0;
 813             }
 814 
 815             @Override
 816             int calculateFragmentSize(int packetLimit, int headerSize) {
 817                 int macLen = ((MAC)authenticator).macAlg().size;
 818                 return packetLimit - headerSize - macLen;
 819             }
 820 
 821             @Override
 822             int calculatePacketSize(int fragmentSize, int headerSize) {
 823                 int macLen = ((MAC)authenticator).macAlg().size;
 824                 return fragmentSize + headerSize + macLen;
 825             }
 826 
 827             @Override
 828             boolean isNullCipher() {
 829                 return true;
 830             }
 831         }
 832     }
 833 
 834     private static final
 835             class StreamReadCipherGenerator implements ReadCipherGenerator {
 836         @Override
 837         public SSLReadCipher createCipher(SSLCipher sslCipher,
 838                 Authenticator authenticator,
 839                 ProtocolVersion protocolVersion, String algorithm,
 840                 Key key, AlgorithmParameterSpec params,
 841                 SecureRandom random) throws GeneralSecurityException {
 842             return new StreamReadCipher(authenticator, protocolVersion,
 843                     algorithm, key, params, random);
 844         }
 845 
 846         static final class StreamReadCipher extends SSLReadCipher {
 847             private final Cipher cipher;
 848 
 849             StreamReadCipher(Authenticator authenticator,
 850                     ProtocolVersion protocolVersion, String algorithm,
 851                     Key key, AlgorithmParameterSpec params,
 852                     SecureRandom random) throws GeneralSecurityException {
 853                 super(authenticator, protocolVersion);
 854                 this.cipher = JsseJce.getCipher(algorithm);
 855                 cipher.init(Cipher.DECRYPT_MODE, key, params, random);
 856             }
 857 
 858             @Override
 859             public Plaintext decrypt(byte contentType, ByteBuffer bb,
 860                     byte[] sequence) throws GeneralSecurityException {
 861                 int len = bb.remaining();
 862                 int pos = bb.position();
 863                 ByteBuffer dup = bb.duplicate();
 864                 try {
 865                     if (len != cipher.update(dup, bb)) {
 866                         // catch BouncyCastle buffering error
 867                         throw new RuntimeException(
 868                                 "Unexpected number of plaintext bytes");
 869                     }
 870                     if (bb.position() != dup.position()) {
 871                         throw new RuntimeException(
 872                                 "Unexpected ByteBuffer position");
 873                     }
 874                 } catch (ShortBufferException sbe) {
 875                     // catch BouncyCastle buffering error
 876                     throw new RuntimeException("Cipher buffering error in " +
 877                         "JCE provider " + cipher.getProvider().getName(), sbe);
 878                 }
 879                 bb.position(pos);
 880                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
 881                     SSLLogger.fine(
 882                             "Plaintext after DECRYPTION", bb.duplicate());
 883                 }
 884 
 885                 MAC signer = (MAC)authenticator;
 886                 if (signer.macAlg().size != 0) {
 887                     checkStreamMac(signer, bb, contentType, sequence);
 888                 } else {
 889                     authenticator.increaseSequenceNumber();
 890                 }
 891 
 892                 return new Plaintext(contentType,
 893                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
 894                         -1, -1L, bb.slice());
 895             }
 896 
 897             @Override
 898             void dispose() {
 899                 if (cipher != null) {
 900                     try {
 901                         cipher.doFinal();
 902                     } catch (Exception e) {
 903                         // swallow all types of exceptions.
 904                     }
 905                 }
 906             }
 907 
 908             @Override
 909             int estimateFragmentSize(int packetSize, int headerSize) {
 910                 int macLen = ((MAC)authenticator).macAlg().size;
 911                 return packetSize - headerSize - macLen;
 912             }
 913         }
 914     }
 915 
 916     private static final
 917             class StreamWriteCipherGenerator implements WriteCipherGenerator {
 918         @Override
 919         public SSLWriteCipher createCipher(SSLCipher sslCipher,
 920                 Authenticator authenticator,
 921                 ProtocolVersion protocolVersion, String algorithm,
 922                 Key key, AlgorithmParameterSpec params,
 923                 SecureRandom random) throws GeneralSecurityException {
 924             return new StreamWriteCipher(authenticator,
 925                     protocolVersion, algorithm, key, params, random);
 926         }
 927 
 928         static final class StreamWriteCipher extends SSLWriteCipher {
 929             private final Cipher cipher;
 930 
 931             StreamWriteCipher(Authenticator authenticator,
 932                     ProtocolVersion protocolVersion, String algorithm,
 933                     Key key, AlgorithmParameterSpec params,
 934                     SecureRandom random) throws GeneralSecurityException {
 935                 super(authenticator, protocolVersion);
 936                 this.cipher = JsseJce.getCipher(algorithm);
 937                 cipher.init(Cipher.ENCRYPT_MODE, key, params, random);
 938             }
 939 
 940             @Override
 941             public int encrypt(byte contentType, ByteBuffer bb) {
 942                 // add message authentication code
 943                 MAC signer = (MAC)authenticator;
 944                 if (signer.macAlg().size != 0) {
 945                     addMac(signer, bb, contentType);
 946                 } else {
 947                     authenticator.increaseSequenceNumber();
 948                 }
 949 
 950                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
 951                     SSLLogger.finest(
 952                         "Padded plaintext before ENCRYPTION", bb.duplicate());
 953                 }
 954 
 955                 int len = bb.remaining();
 956                 ByteBuffer dup = bb.duplicate();
 957                 try {
 958                     if (len != cipher.update(dup, bb)) {
 959                         // catch BouncyCastle buffering error
 960                         throw new RuntimeException(
 961                                 "Unexpected number of plaintext bytes");
 962                     }
 963                     if (bb.position() != dup.position()) {
 964                         throw new RuntimeException(
 965                                 "Unexpected ByteBuffer position");
 966                     }
 967                 } catch (ShortBufferException sbe) {
 968                     // catch BouncyCastle buffering error
 969                     throw new RuntimeException("Cipher buffering error in " +
 970                         "JCE provider " + cipher.getProvider().getName(), sbe);
 971                 }
 972 
 973                 return len;
 974             }
 975 
 976             @Override
 977             void dispose() {
 978                 if (cipher != null) {
 979                     try {
 980                         cipher.doFinal();
 981                     } catch (Exception e) {
 982                         // swallow all types of exceptions.
 983                     }
 984                 }
 985             }
 986 
 987             @Override
 988             int getExplicitNonceSize() {
 989                 return 0;
 990             }
 991 
 992             @Override
 993             int calculateFragmentSize(int packetLimit, int headerSize) {
 994                 int macLen = ((MAC)authenticator).macAlg().size;
 995                 return packetLimit - headerSize - macLen;
 996             }
 997 
 998             @Override
 999             int calculatePacketSize(int fragmentSize, int headerSize) {
1000                 int macLen = ((MAC)authenticator).macAlg().size;
1001                 return fragmentSize + headerSize + macLen;
1002             }
1003         }
1004     }
1005 
1006     private static final
1007             class T10BlockReadCipherGenerator implements ReadCipherGenerator {
1008         @Override
1009         public SSLReadCipher createCipher(SSLCipher sslCipher,
1010                 Authenticator authenticator,
1011                 ProtocolVersion protocolVersion, String algorithm,
1012                 Key key, AlgorithmParameterSpec params,
1013                 SecureRandom random) throws GeneralSecurityException {
1014             return new BlockReadCipher(authenticator,
1015                     protocolVersion, algorithm, key, params, random);
1016         }
1017 
1018         static final class BlockReadCipher extends SSLReadCipher {
1019             private final Cipher cipher;
1020 
1021             BlockReadCipher(Authenticator authenticator,
1022                     ProtocolVersion protocolVersion, String algorithm,
1023                     Key key, AlgorithmParameterSpec params,
1024                     SecureRandom random) throws GeneralSecurityException {
1025                 super(authenticator, protocolVersion);
1026                 this.cipher = JsseJce.getCipher(algorithm);
1027                 cipher.init(Cipher.DECRYPT_MODE, key, params, random);
1028             }
1029 
1030             @Override
1031             public Plaintext decrypt(byte contentType, ByteBuffer bb,
1032                     byte[] sequence) throws GeneralSecurityException {
1033                 BadPaddingException reservedBPE = null;
1034 
1035                 // sanity check length of the ciphertext
1036                 MAC signer = (MAC)authenticator;
1037                 int cipheredLength = bb.remaining();
1038                 int tagLen = signer.macAlg().size;
1039                 if (tagLen != 0) {
1040                     if (!sanityCheck(tagLen, bb.remaining())) {
1041                         reservedBPE = new BadPaddingException(
1042                                 "ciphertext sanity check failed");
1043                     }
1044                 }
1045                 // decryption
1046                 int len = bb.remaining();
1047                 int pos = bb.position();
1048                 ByteBuffer dup = bb.duplicate();
1049                 try {
1050                     if (len != cipher.update(dup, bb)) {
1051                         // catch BouncyCastle buffering error
1052                         throw new RuntimeException(
1053                                 "Unexpected number of plaintext bytes");
1054                     }
1055 
1056                     if (bb.position() != dup.position()) {
1057                         throw new RuntimeException(
1058                                 "Unexpected ByteBuffer position");
1059                     }
1060                 } catch (ShortBufferException sbe) {
1061                     // catch BouncyCastle buffering error
1062                     throw new RuntimeException("Cipher buffering error in " +
1063                         "JCE provider " + cipher.getProvider().getName(), sbe);
1064                 }
1065 
1066                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1067                     SSLLogger.fine(
1068                             "Padded plaintext after DECRYPTION",
1069                             bb.duplicate().position(pos));
1070                 }
1071 
1072                 // remove the block padding
1073                 int blockSize = cipher.getBlockSize();
1074                 bb.position(pos);
1075                 try {
1076                     removePadding(bb, tagLen, blockSize, protocolVersion);
1077                 } catch (BadPaddingException bpe) {
1078                     if (reservedBPE == null) {
1079                         reservedBPE = bpe;
1080                     }
1081                 }
1082 
1083                 // Requires message authentication code for null, stream and
1084                 // block cipher suites.
1085                 try {
1086                     if (tagLen != 0) {
1087                         checkCBCMac(signer, bb,
1088                                 contentType, cipheredLength, sequence);
1089                     } else {
1090                         authenticator.increaseSequenceNumber();
1091                     }
1092                 } catch (BadPaddingException bpe) {
1093                     if (reservedBPE == null) {
1094                         reservedBPE = bpe;
1095                     }
1096                 }
1097 
1098                 // Is it a failover?
1099                 if (reservedBPE != null) {
1100                     throw reservedBPE;
1101                 }
1102 
1103                 return new Plaintext(contentType,
1104                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
1105                         -1, -1L, bb.slice());
1106             }
1107 
1108             @Override
1109             void dispose() {
1110                 if (cipher != null) {
1111                     try {
1112                         cipher.doFinal();
1113                     } catch (Exception e) {
1114                         // swallow all types of exceptions.
1115                     }
1116                 }
1117             }
1118 
1119             @Override
1120             int estimateFragmentSize(int packetSize, int headerSize) {
1121                 int macLen = ((MAC)authenticator).macAlg().size;
1122 
1123                 // No padding for a maximum fragment.
1124                 //
1125                 // 1 byte padding length field: 0x00
1126                 return packetSize - headerSize - macLen - 1;
1127             }
1128 
1129             /**
1130              * Sanity check the length of a fragment before decryption.
1131              *
1132              * In CBC mode, check that the fragment length is one or multiple
1133              * times of the block size of the cipher suite, and is at least
1134              * one (one is the smallest size of padding in CBC mode) bigger
1135              * than the tag size of the MAC algorithm except the explicit IV
1136              * size for TLS 1.1 or later.
1137              *
1138              * In non-CBC mode, check that the fragment length is not less than
1139              * the tag size of the MAC algorithm.
1140              *
1141              * @return true if the length of a fragment matches above
1142              *         requirements
1143              */
1144             private boolean sanityCheck(int tagLen, int fragmentLen) {
1145                 int blockSize = cipher.getBlockSize();
1146                 if ((fragmentLen % blockSize) == 0) {
1147                     int minimal = tagLen + 1;
1148                     minimal = (minimal >= blockSize) ? minimal : blockSize;
1149 
1150                     return (fragmentLen >= minimal);
1151                 }
1152 
1153                 return false;
1154             }
1155         }
1156     }
1157 
1158     private static final
1159             class T10BlockWriteCipherGenerator implements WriteCipherGenerator {
1160         @Override
1161         public SSLWriteCipher createCipher(SSLCipher sslCipher,
1162                 Authenticator authenticator,
1163                 ProtocolVersion protocolVersion, String algorithm,
1164                 Key key, AlgorithmParameterSpec params,
1165                 SecureRandom random) throws GeneralSecurityException {
1166             return new BlockWriteCipher(authenticator,
1167                     protocolVersion, algorithm, key, params, random);
1168         }
1169 
1170         static final class BlockWriteCipher extends SSLWriteCipher {
1171             private final Cipher cipher;
1172 
1173             BlockWriteCipher(Authenticator authenticator,
1174                     ProtocolVersion protocolVersion, String algorithm,
1175                     Key key, AlgorithmParameterSpec params,
1176                     SecureRandom random) throws GeneralSecurityException {
1177                 super(authenticator, protocolVersion);
1178                 this.cipher = JsseJce.getCipher(algorithm);
1179                 cipher.init(Cipher.ENCRYPT_MODE, key, params, random);
1180             }
1181 
1182             @Override
1183             public int encrypt(byte contentType, ByteBuffer bb) {
1184                 int pos = bb.position();
1185 
1186                 // add message authentication code
1187                 MAC signer = (MAC)authenticator;
1188                 if (signer.macAlg().size != 0) {
1189                     addMac(signer, bb, contentType);
1190                 } else {
1191                     authenticator.increaseSequenceNumber();
1192                 }
1193 
1194                 int blockSize = cipher.getBlockSize();
1195                 int len = addPadding(bb, blockSize);
1196                 bb.position(pos);
1197 
1198                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1199                     SSLLogger.fine(
1200                             "Padded plaintext before ENCRYPTION",
1201                             bb.duplicate());
1202                 }
1203 
1204                 ByteBuffer dup = bb.duplicate();
1205                 try {
1206                     if (len != cipher.update(dup, bb)) {
1207                         // catch BouncyCastle buffering error
1208                         throw new RuntimeException(
1209                                 "Unexpected number of plaintext bytes");
1210                     }
1211 
1212                     if (bb.position() != dup.position()) {
1213                         throw new RuntimeException(
1214                                 "Unexpected ByteBuffer position");
1215                     }
1216                 } catch (ShortBufferException sbe) {
1217                     // catch BouncyCastle buffering error
1218                     throw new RuntimeException("Cipher buffering error in " +
1219                         "JCE provider " + cipher.getProvider().getName(), sbe);
1220                 }
1221 
1222                 return len;
1223             }
1224 
1225             @Override
1226             void dispose() {
1227                 if (cipher != null) {
1228                     try {
1229                         cipher.doFinal();
1230                     } catch (Exception e) {
1231                         // swallow all types of exceptions.
1232                     }
1233                 }
1234             }
1235 
1236             @Override
1237             int getExplicitNonceSize() {
1238                 return 0;
1239             }
1240 
1241             @Override
1242             int calculateFragmentSize(int packetLimit, int headerSize) {
1243                 int macLen = ((MAC)authenticator).macAlg().size;
1244                 int blockSize = cipher.getBlockSize();
1245                 int fragLen = packetLimit - headerSize;
1246                 fragLen -= (fragLen % blockSize);   // cannot hold a block
1247                 // No padding for a maximum fragment.
1248                 fragLen -= 1;       // 1 byte padding length field: 0x00
1249                 fragLen -= macLen;
1250                 return fragLen;
1251             }
1252 
1253             @Override
1254             int calculatePacketSize(int fragmentSize, int headerSize) {
1255                 int macLen = ((MAC)authenticator).macAlg().size;
1256                 int blockSize = cipher.getBlockSize();
1257                 int paddedLen = fragmentSize + macLen + 1;
1258                 if ((paddedLen % blockSize)  != 0) {
1259                     paddedLen += blockSize - 1;
1260                     paddedLen -= paddedLen % blockSize;
1261                 }
1262 
1263                 return headerSize + paddedLen;
1264             }
1265 
1266             @Override
1267             boolean isCBCMode() {
1268                 return true;
1269             }
1270         }
1271     }
1272 
1273     // For TLS 1.1 and 1.2
1274     private static final
1275             class T11BlockReadCipherGenerator implements ReadCipherGenerator {
1276         @Override
1277         public SSLReadCipher createCipher(SSLCipher sslCipher,
1278                 Authenticator authenticator, ProtocolVersion protocolVersion,
1279                 String algorithm, Key key, AlgorithmParameterSpec params,
1280                 SecureRandom random) throws GeneralSecurityException {
1281             return new BlockReadCipher(authenticator, protocolVersion,
1282                     sslCipher, algorithm, key, params, random);
1283         }
1284 
1285         static final class BlockReadCipher extends SSLReadCipher {
1286             private final Cipher cipher;
1287 
1288             BlockReadCipher(Authenticator authenticator,
1289                     ProtocolVersion protocolVersion,
1290                     SSLCipher sslCipher, String algorithm,
1291                     Key key, AlgorithmParameterSpec params,
1292                     SecureRandom random) throws GeneralSecurityException {
1293                 super(authenticator, protocolVersion);
1294                 this.cipher = JsseJce.getCipher(algorithm);
1295                 if (params == null) {
1296                     params = new IvParameterSpec(new byte[sslCipher.ivSize]);
1297                 }
1298                 cipher.init(Cipher.DECRYPT_MODE, key, params, random);
1299             }
1300 
1301             @Override
1302             public Plaintext decrypt(byte contentType, ByteBuffer bb,
1303                     byte[] sequence) throws GeneralSecurityException {
1304                 BadPaddingException reservedBPE = null;
1305 
1306                 // sanity check length of the ciphertext
1307                 MAC signer = (MAC)authenticator;
1308                 int cipheredLength = bb.remaining();
1309                 int tagLen = signer.macAlg().size;
1310                 if (tagLen != 0) {
1311                     if (!sanityCheck(tagLen, bb.remaining())) {
1312                         reservedBPE = new BadPaddingException(
1313                                 "ciphertext sanity check failed");
1314                     }
1315                 }
1316 
1317                 // decryption
1318                 int len = bb.remaining();
1319                 int pos = bb.position();
1320                 ByteBuffer dup = bb.duplicate();
1321                 try {
1322                     if (len != cipher.update(dup, bb)) {
1323                         // catch BouncyCastle buffering error
1324                         throw new RuntimeException(
1325                                 "Unexpected number of plaintext bytes");
1326                     }
1327 
1328                     if (bb.position() != dup.position()) {
1329                         throw new RuntimeException(
1330                                 "Unexpected ByteBuffer position");
1331                     }
1332                 } catch (ShortBufferException sbe) {
1333                     // catch BouncyCastle buffering error
1334                     throw new RuntimeException("Cipher buffering error in " +
1335                         "JCE provider " + cipher.getProvider().getName(), sbe);
1336                 }
1337 
1338                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1339                     SSLLogger.fine(
1340                             "Padded plaintext after DECRYPTION",
1341                             bb.duplicate().position(pos));
1342                 }
1343 
1344                 // Ignore the explicit nonce.
1345                 bb.position(pos + cipher.getBlockSize());
1346                 pos = bb.position();
1347 
1348                 // remove the block padding
1349                 int blockSize = cipher.getBlockSize();
1350                 bb.position(pos);
1351                 try {
1352                     removePadding(bb, tagLen, blockSize, protocolVersion);
1353                 } catch (BadPaddingException bpe) {
1354                     if (reservedBPE == null) {
1355                         reservedBPE = bpe;
1356                     }
1357                 }
1358 
1359                 // Requires message authentication code for null, stream and
1360                 // block cipher suites.
1361                 try {
1362                     if (tagLen != 0) {
1363                         checkCBCMac(signer, bb,
1364                                 contentType, cipheredLength, sequence);
1365                     } else {
1366                         authenticator.increaseSequenceNumber();
1367                     }
1368                 } catch (BadPaddingException bpe) {
1369                     if (reservedBPE == null) {
1370                         reservedBPE = bpe;
1371                     }
1372                 }
1373 
1374                 // Is it a failover?
1375                 if (reservedBPE != null) {
1376                     throw reservedBPE;
1377                 }
1378 
1379                 return new Plaintext(contentType,
1380                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
1381                         -1, -1L, bb.slice());
1382             }
1383 
1384             @Override
1385             void dispose() {
1386                 if (cipher != null) {
1387                     try {
1388                         cipher.doFinal();
1389                     } catch (Exception e) {
1390                         // swallow all types of exceptions.
1391                     }
1392                 }
1393             }
1394 
1395             @Override
1396             int estimateFragmentSize(int packetSize, int headerSize) {
1397                 int macLen = ((MAC)authenticator).macAlg().size;
1398 
1399                 // No padding for a maximum fragment.
1400                 //
1401                 // 1 byte padding length field: 0x00
1402                 int nonceSize = cipher.getBlockSize();
1403                 return packetSize - headerSize - nonceSize - macLen - 1;
1404             }
1405 
1406             /**
1407              * Sanity check the length of a fragment before decryption.
1408              *
1409              * In CBC mode, check that the fragment length is one or multiple
1410              * times of the block size of the cipher suite, and is at least
1411              * one (one is the smallest size of padding in CBC mode) bigger
1412              * than the tag size of the MAC algorithm except the explicit IV
1413              * size for TLS 1.1 or later.
1414              *
1415              * In non-CBC mode, check that the fragment length is not less than
1416              * the tag size of the MAC algorithm.
1417              *
1418              * @return true if the length of a fragment matches above
1419              *         requirements
1420              */
1421             private boolean sanityCheck(int tagLen, int fragmentLen) {
1422                 int blockSize = cipher.getBlockSize();
1423                 if ((fragmentLen % blockSize) == 0) {
1424                     int minimal = tagLen + 1;
1425                     minimal = (minimal >= blockSize) ? minimal : blockSize;
1426                     minimal += blockSize;
1427 
1428                     return (fragmentLen >= minimal);
1429                 }
1430 
1431                 return false;
1432             }
1433         }
1434     }
1435 
1436     // For TLS 1.1 and 1.2
1437     private static final
1438             class T11BlockWriteCipherGenerator implements WriteCipherGenerator {
1439         @Override
1440         public SSLWriteCipher createCipher(SSLCipher sslCipher,
1441                 Authenticator authenticator, ProtocolVersion protocolVersion,
1442                 String algorithm, Key key, AlgorithmParameterSpec params,
1443                 SecureRandom random) throws GeneralSecurityException {
1444             return new BlockWriteCipher(authenticator, protocolVersion,
1445                     sslCipher, algorithm, key, params, random);
1446         }
1447 
1448         static final class BlockWriteCipher extends SSLWriteCipher {
1449             private final Cipher cipher;
1450             private final SecureRandom random;
1451 
1452             BlockWriteCipher(Authenticator authenticator,
1453                     ProtocolVersion protocolVersion,
1454                     SSLCipher sslCipher, String algorithm,
1455                     Key key, AlgorithmParameterSpec params,
1456                     SecureRandom random) throws GeneralSecurityException {
1457                 super(authenticator, protocolVersion);
1458                 this.cipher = JsseJce.getCipher(algorithm);
1459                 this.random = random;
1460                 if (params == null) {
1461                     params = new IvParameterSpec(new byte[sslCipher.ivSize]);
1462                 }
1463                 cipher.init(Cipher.ENCRYPT_MODE, key, params, random);
1464             }
1465 
1466             @Override
1467             public int encrypt(byte contentType, ByteBuffer bb) {
1468                 // To be unique and aware of overflow-wrap, sequence number
1469                 // is used as the nonce_explicit of block cipher suites.
1470                 int pos = bb.position();
1471 
1472                 // add message authentication code
1473                 MAC signer = (MAC)authenticator;
1474                 if (signer.macAlg().size != 0) {
1475                     addMac(signer, bb, contentType);
1476                 } else {
1477                     authenticator.increaseSequenceNumber();
1478                 }
1479 
1480                 // DON'T WORRY, the nonce spaces are considered already.
1481                 byte[] nonce = new byte[cipher.getBlockSize()];
1482                 random.nextBytes(nonce);
1483                 pos = pos - nonce.length;
1484                 bb.position(pos);
1485                 bb.put(nonce);
1486                 bb.position(pos);
1487 
1488                 int blockSize = cipher.getBlockSize();
1489                 int len = addPadding(bb, blockSize);
1490                 bb.position(pos);
1491 
1492                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1493                     SSLLogger.fine(
1494                             "Padded plaintext before ENCRYPTION",
1495                             bb.duplicate());
1496                 }
1497 
1498                 ByteBuffer dup = bb.duplicate();
1499                 try {
1500                     if (len != cipher.update(dup, bb)) {
1501                         // catch BouncyCastle buffering error
1502                         throw new RuntimeException(
1503                                 "Unexpected number of plaintext bytes");
1504                     }
1505 
1506                     if (bb.position() != dup.position()) {
1507                         throw new RuntimeException(
1508                                 "Unexpected ByteBuffer position");
1509                     }
1510                 } catch (ShortBufferException sbe) {
1511                     // catch BouncyCastle buffering error
1512                     throw new RuntimeException("Cipher buffering error in " +
1513                         "JCE provider " + cipher.getProvider().getName(), sbe);
1514                 }
1515 
1516                 return len;
1517             }
1518 
1519             @Override
1520             void dispose() {
1521                 if (cipher != null) {
1522                     try {
1523                         cipher.doFinal();
1524                     } catch (Exception e) {
1525                         // swallow all types of exceptions.
1526                     }
1527                 }
1528             }
1529 
1530             @Override
1531             int getExplicitNonceSize() {
1532                 return cipher.getBlockSize();
1533             }
1534 
1535             @Override
1536             int calculateFragmentSize(int packetLimit, int headerSize) {
1537                 int macLen = ((MAC)authenticator).macAlg().size;
1538                 int blockSize = cipher.getBlockSize();
1539                 int fragLen = packetLimit - headerSize - blockSize;
1540                 fragLen -= (fragLen % blockSize);   // cannot hold a block
1541                 // No padding for a maximum fragment.
1542                 fragLen -= 1;       // 1 byte padding length field: 0x00
1543                 fragLen -= macLen;
1544                 return fragLen;
1545             }
1546 
1547             @Override
1548             int calculatePacketSize(int fragmentSize, int headerSize) {
1549                 int macLen = ((MAC)authenticator).macAlg().size;
1550                 int blockSize = cipher.getBlockSize();
1551                 int paddedLen = fragmentSize + macLen + 1;
1552                 if ((paddedLen % blockSize)  != 0) {
1553                     paddedLen += blockSize - 1;
1554                     paddedLen -= paddedLen % blockSize;
1555                 }
1556 
1557                 return headerSize + blockSize + paddedLen;
1558             }
1559 
1560             @Override
1561             boolean isCBCMode() {
1562                 return true;
1563             }
1564         }
1565     }
1566 
1567     private static final
1568             class T12GcmReadCipherGenerator implements ReadCipherGenerator {
1569         @Override
1570         public SSLReadCipher createCipher(SSLCipher sslCipher,
1571                 Authenticator authenticator,
1572                 ProtocolVersion protocolVersion, String algorithm,
1573                 Key key, AlgorithmParameterSpec params,
1574                 SecureRandom random) throws GeneralSecurityException {
1575             return new GcmReadCipher(authenticator, protocolVersion, sslCipher,
1576                     algorithm, key, params, random);
1577         }
1578 
1579         static final class GcmReadCipher extends SSLReadCipher {
1580             private final Cipher cipher;
1581             private final int tagSize;
1582             private final Key key;
1583             private final byte[] fixedIv;
1584             private final int recordIvSize;
1585             private final SecureRandom random;
1586 
1587             GcmReadCipher(Authenticator authenticator,
1588                     ProtocolVersion protocolVersion,
1589                     SSLCipher sslCipher, String algorithm,
1590                     Key key, AlgorithmParameterSpec params,
1591                     SecureRandom random) throws GeneralSecurityException {
1592                 super(authenticator, protocolVersion);
1593                 this.cipher = JsseJce.getCipher(algorithm);
1594                 this.tagSize = sslCipher.tagSize;
1595                 this.key = key;
1596                 this.fixedIv = ((IvParameterSpec)params).getIV();
1597                 this.recordIvSize = sslCipher.ivSize - sslCipher.fixedIvSize;
1598                 this.random = random;
1599 
1600                 // DON'T initialize the cipher for AEAD!
1601             }
1602 
1603             @Override
1604             public Plaintext decrypt(byte contentType, ByteBuffer bb,
1605                     byte[] sequence) throws GeneralSecurityException {
1606                 if (bb.remaining() < (recordIvSize + tagSize)) {
1607                     throw new BadPaddingException(
1608                         "Insufficient buffer remaining for AEAD cipher " +
1609                         "fragment (" + bb.remaining() + "). Needs to be " +
1610                         "more than or equal to IV size (" + recordIvSize +
1611                          ") + tag size (" + tagSize + ")");
1612                 }
1613 
1614                 // initialize the AEAD cipher for the unique IV
1615                 byte[] iv = Arrays.copyOf(fixedIv,
1616                                     fixedIv.length + recordIvSize);
1617                 bb.get(iv, fixedIv.length, recordIvSize);
1618                 GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
1619                 try {
1620                     cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
1621                 } catch (InvalidKeyException |
1622                             InvalidAlgorithmParameterException ikae) {
1623                     // unlikely to happen
1624                     throw new RuntimeException(
1625                                 "invalid key or spec in GCM mode", ikae);
1626                 }
1627 
1628                 // update the additional authentication data
1629                 byte[] aad = authenticator.acquireAuthenticationBytes(
1630                         contentType, bb.remaining() - tagSize,
1631                         sequence);
1632                 cipher.updateAAD(aad);
1633 
1634                 // DON'T decrypt the nonce_explicit for AEAD mode. The buffer
1635                 // position has moved out of the nonce_explicit range.
1636                 int len, pos = bb.position();
1637                 ByteBuffer dup = bb.duplicate();
1638                 try {
1639                     len = cipher.doFinal(dup, bb);
1640                 } catch (IllegalBlockSizeException ibse) {
1641                     // unlikely to happen
1642                     throw new RuntimeException(
1643                         "Cipher error in AEAD mode \"" + ibse.getMessage() +
1644                         " \"in JCE provider " + cipher.getProvider().getName());
1645                 } catch (ShortBufferException sbe) {
1646                     // catch BouncyCastle buffering error
1647                     throw new RuntimeException("Cipher buffering error in " +
1648                         "JCE provider " + cipher.getProvider().getName(), sbe);
1649                 }
1650                 // reset the limit to the end of the decrypted data
1651                 bb.position(pos);
1652                 bb.limit(pos + len);
1653 
1654                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1655                     SSLLogger.fine(
1656                             "Plaintext after DECRYPTION", bb.duplicate());
1657                 }
1658 
1659                 return new Plaintext(contentType,
1660                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
1661                         -1, -1L, bb.slice());
1662             }
1663 
1664             @Override
1665             void dispose() {
1666                 if (cipher != null) {
1667                     try {
1668                         cipher.doFinal();
1669                     } catch (Exception e) {
1670                         // swallow all types of exceptions.
1671                     }
1672                 }
1673             }
1674 
1675             @Override
1676             int estimateFragmentSize(int packetSize, int headerSize) {
1677                 return packetSize - headerSize - recordIvSize - tagSize;
1678             }
1679         }
1680     }
1681 
1682     private static final
1683             class T12GcmWriteCipherGenerator implements WriteCipherGenerator {
1684         @Override
1685         public SSLWriteCipher createCipher(SSLCipher sslCipher,
1686                 Authenticator authenticator,
1687                 ProtocolVersion protocolVersion, String algorithm,
1688                 Key key, AlgorithmParameterSpec params,
1689                 SecureRandom random) throws GeneralSecurityException {
1690             return new GcmWriteCipher(authenticator, protocolVersion, sslCipher,
1691                     algorithm, key, params, random);
1692         }
1693 
1694         private static final class GcmWriteCipher extends SSLWriteCipher {
1695             private final Cipher cipher;
1696             private final int tagSize;
1697             private final Key key;
1698             private final byte[] fixedIv;
1699             private final int recordIvSize;
1700             private final SecureRandom random;
1701 
1702             GcmWriteCipher(Authenticator authenticator,
1703                     ProtocolVersion protocolVersion,
1704                     SSLCipher sslCipher, String algorithm,
1705                     Key key, AlgorithmParameterSpec params,
1706                     SecureRandom random) throws GeneralSecurityException {
1707                 super(authenticator, protocolVersion);
1708                 this.cipher = JsseJce.getCipher(algorithm);
1709                 this.tagSize = sslCipher.tagSize;
1710                 this.key = key;
1711                 this.fixedIv = ((IvParameterSpec)params).getIV();
1712                 this.recordIvSize = sslCipher.ivSize - sslCipher.fixedIvSize;
1713                 this.random = random;
1714 
1715                 // DON'T initialize the cipher for AEAD!
1716             }
1717 
1718             @Override
1719             public int encrypt(byte contentType,
1720                     ByteBuffer bb) {
1721                 // To be unique and aware of overflow-wrap, sequence number
1722                 // is used as the nonce_explicit of AEAD cipher suites.
1723                 byte[] nonce = authenticator.sequenceNumber();
1724 
1725                 // initialize the AEAD cipher for the unique IV
1726                 byte[] iv = Arrays.copyOf(fixedIv,
1727                                             fixedIv.length + nonce.length);
1728                 System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length);
1729 
1730                 GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
1731                 try {
1732                     cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
1733                 } catch (InvalidKeyException |
1734                             InvalidAlgorithmParameterException ikae) {
1735                     // unlikely to happen
1736                     throw new RuntimeException(
1737                                 "invalid key or spec in GCM mode", ikae);
1738                 }
1739 
1740                 // Update the additional authentication data, using the
1741                 // implicit sequence number of the authenticator.
1742                 byte[] aad = authenticator.acquireAuthenticationBytes(
1743                                         contentType, bb.remaining(), null);
1744                 cipher.updateAAD(aad);
1745 
1746                 // DON'T WORRY, the nonce spaces are considered already.
1747                 bb.position(bb.position() - nonce.length);
1748                 bb.put(nonce);
1749 
1750                 // DON'T encrypt the nonce for AEAD mode.
1751                 int len, pos = bb.position();
1752                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1753                     SSLLogger.fine(
1754                             "Plaintext before ENCRYPTION",
1755                             bb.duplicate());
1756                 }
1757 
1758                 ByteBuffer dup = bb.duplicate();
1759                 int outputSize = cipher.getOutputSize(dup.remaining());
1760                 if (outputSize > bb.remaining()) {
1761                     // Need to expand the limit of the output buffer for
1762                     // the authentication tag.
1763                     //
1764                     // DON'T worry about the buffer's capacity, we have
1765                     // reserved space for the authentication tag.
1766                     bb.limit(pos + outputSize);
1767                 }
1768 
1769                 try {
1770                     len = cipher.doFinal(dup, bb);
1771                 } catch (IllegalBlockSizeException |
1772                             BadPaddingException | ShortBufferException ibse) {
1773                     // unlikely to happen
1774                     throw new RuntimeException(
1775                             "Cipher error in AEAD mode in JCE provider " +
1776                             cipher.getProvider().getName(), ibse);
1777                 }
1778 
1779                 if (len != outputSize) {
1780                     throw new RuntimeException(
1781                             "Cipher buffering error in JCE provider " +
1782                             cipher.getProvider().getName());
1783                 }
1784 
1785                 return len + nonce.length;
1786             }
1787 
1788             @Override
1789             void dispose() {
1790                 if (cipher != null) {
1791                     try {
1792                         cipher.doFinal();
1793                     } catch (Exception e) {
1794                         // swallow all types of exceptions.
1795                     }
1796                 }
1797             }
1798 
1799             @Override
1800             int getExplicitNonceSize() {
1801                 return recordIvSize;
1802             }
1803 
1804             @Override
1805             int calculateFragmentSize(int packetLimit, int headerSize) {
1806                 return packetLimit - headerSize - recordIvSize - tagSize;
1807             }
1808 
1809             @Override
1810             int calculatePacketSize(int fragmentSize, int headerSize) {
1811                 return fragmentSize + headerSize + recordIvSize + tagSize;
1812             }
1813         }
1814     }
1815 
1816     private static final
1817             class T13GcmReadCipherGenerator implements ReadCipherGenerator {
1818 
1819         @Override
1820         public SSLReadCipher createCipher(SSLCipher sslCipher,
1821                 Authenticator authenticator, ProtocolVersion protocolVersion,
1822                 String algorithm, Key key, AlgorithmParameterSpec params,
1823                 SecureRandom random) throws GeneralSecurityException {
1824             return new GcmReadCipher(authenticator, protocolVersion, sslCipher,
1825                     algorithm, key, params, random);
1826         }
1827 
1828         static final class GcmReadCipher extends SSLReadCipher {
1829             private final Cipher cipher;
1830             private final int tagSize;
1831             private final Key key;
1832             private final byte[] iv;
1833             private final SecureRandom random;
1834 
1835             GcmReadCipher(Authenticator authenticator,
1836                     ProtocolVersion protocolVersion,
1837                     SSLCipher sslCipher, String algorithm,
1838                     Key key, AlgorithmParameterSpec params,
1839                     SecureRandom random) throws GeneralSecurityException {
1840                 super(authenticator, protocolVersion);
1841                 this.cipher = JsseJce.getCipher(algorithm);
1842                 this.tagSize = sslCipher.tagSize;
1843                 this.key = key;
1844                 this.iv = ((IvParameterSpec)params).getIV();
1845                 this.random = random;
1846 
1847                 keyLimitCountdown = cipherLimits.getOrDefault(
1848                         algorithm.toUpperCase() + ":" + tag[0], 0L);
1849                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1850                     SSLLogger.fine("KeyLimit read side: algorithm = " +
1851                             algorithm.toUpperCase() + ":" + tag[0] +
1852                             "\ncountdown value = " + keyLimitCountdown);
1853                 }
1854                 if (keyLimitCountdown > 0) {
1855                     keyLimitEnabled = true;
1856                 }
1857                 // DON'T initialize the cipher for AEAD!
1858             }
1859 
1860             @Override
1861             public Plaintext decrypt(byte contentType, ByteBuffer bb,
1862                     byte[] sequence) throws GeneralSecurityException {
1863                 // An implementation may receive an unencrypted record of type
1864                 // change_cipher_spec consisting of the single byte value 0x01
1865                 // at any time after the first ClientHello message has been
1866                 // sent or received and before the peer's Finished message has
1867                 // been received and MUST simply drop it without further
1868                 // processing.
1869                 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
1870                     return new Plaintext(contentType,
1871                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
1872                         -1, -1L, bb.slice());
1873                 }
1874 
1875                 if (bb.remaining() <= tagSize) {
1876                     throw new BadPaddingException(
1877                         "Insufficient buffer remaining for AEAD cipher " +
1878                         "fragment (" + bb.remaining() + "). Needs to be " +
1879                         "more than tag size (" + tagSize + ")");
1880                 }
1881 
1882                 byte[] sn = sequence;
1883                 if (sn == null) {
1884                     sn = authenticator.sequenceNumber();
1885                 }
1886                 byte[] nonce = iv.clone();
1887                 int offset = nonce.length - sn.length;
1888                 for (int i = 0; i < sn.length; i++) {
1889                     nonce[offset + i] ^= sn[i];
1890                 }
1891 
1892                 // initialize the AEAD cipher for the unique IV
1893                 GCMParameterSpec spec =
1894                         new GCMParameterSpec(tagSize * 8, nonce);
1895                 try {
1896                     cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
1897                 } catch (InvalidKeyException |
1898                             InvalidAlgorithmParameterException ikae) {
1899                     // unlikely to happen
1900                     throw new RuntimeException(
1901                                 "invalid key or spec in GCM mode", ikae);
1902                 }
1903 
1904                 // Update the additional authentication data, using the
1905                 // implicit sequence number of the authenticator.
1906                 byte[] aad = authenticator.acquireAuthenticationBytes(
1907                                         contentType, bb.remaining(), sn);
1908                 cipher.updateAAD(aad);
1909 
1910                 int len, pos = bb.position();
1911                 ByteBuffer dup = bb.duplicate();
1912                 try {
1913                     len = cipher.doFinal(dup, bb);
1914                 } catch (IllegalBlockSizeException ibse) {
1915                     // unlikely to happen
1916                     throw new RuntimeException(
1917                         "Cipher error in AEAD mode \"" + ibse.getMessage() +
1918                         " \"in JCE provider " + cipher.getProvider().getName());
1919                 } catch (ShortBufferException sbe) {
1920                     // catch BouncyCastle buffering error
1921                     throw new RuntimeException("Cipher buffering error in " +
1922                         "JCE provider " + cipher.getProvider().getName(), sbe);
1923                 }
1924                 // reset the limit to the end of the decrypted data
1925                 bb.position(pos);
1926                 bb.limit(pos + len);
1927 
1928                 // remove inner plaintext padding
1929                 int i = bb.limit() - 1;
1930                 for (; i > 0 && bb.get(i) == 0; i--) {
1931                     // blank
1932                 }
1933                 if (i < (pos + 1)) {
1934                     throw new BadPaddingException(
1935                             "Incorrect inner plaintext: no content type");
1936                 }
1937                 contentType = bb.get(i);
1938                 bb.limit(i);
1939 
1940                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
1941                     SSLLogger.fine(
1942                             "Plaintext after DECRYPTION", bb.duplicate());
1943                 }
1944                 if (keyLimitEnabled) {
1945                     keyLimitCountdown -= len;
1946                 }
1947 
1948                 return new Plaintext(contentType,
1949                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
1950                         -1, -1L, bb.slice());
1951             }
1952 
1953             @Override
1954             void dispose() {
1955                 if (cipher != null) {
1956                     try {
1957                         cipher.doFinal();
1958                     } catch (Exception e) {
1959                         // swallow all types of exceptions.
1960                     }
1961                 }
1962             }
1963 
1964             @Override
1965             int estimateFragmentSize(int packetSize, int headerSize) {
1966                 return packetSize - headerSize - tagSize;
1967             }
1968         }
1969     }
1970 
1971     private static final
1972             class T13GcmWriteCipherGenerator implements WriteCipherGenerator {
1973         @Override
1974         public SSLWriteCipher createCipher(SSLCipher sslCipher,
1975                 Authenticator authenticator, ProtocolVersion protocolVersion,
1976                 String algorithm, Key key, AlgorithmParameterSpec params,
1977                 SecureRandom random) throws GeneralSecurityException {
1978             return new GcmWriteCipher(authenticator, protocolVersion, sslCipher,
1979                     algorithm, key, params, random);
1980         }
1981 
1982         private static final class GcmWriteCipher extends SSLWriteCipher {
1983             private final Cipher cipher;
1984             private final int tagSize;
1985             private final Key key;
1986             private final byte[] iv;
1987             private final SecureRandom random;
1988 
1989             GcmWriteCipher(Authenticator authenticator,
1990                     ProtocolVersion protocolVersion,
1991                     SSLCipher sslCipher, String algorithm,
1992                     Key key, AlgorithmParameterSpec params,
1993                     SecureRandom random) throws GeneralSecurityException {
1994                 super(authenticator, protocolVersion);
1995                 this.cipher = JsseJce.getCipher(algorithm);
1996                 this.tagSize = sslCipher.tagSize;
1997                 this.key = key;
1998                 this.iv = ((IvParameterSpec)params).getIV();
1999                 this.random = random;
2000 
2001                 keyLimitCountdown = cipherLimits.getOrDefault(
2002                         algorithm.toUpperCase() + ":" + tag[0], 0L);
2003                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
2004                     SSLLogger.fine("KeyLimit write side: algorithm = "
2005                             + algorithm.toUpperCase() + ":" + tag[0] +
2006                             "\ncountdown value = " + keyLimitCountdown);
2007                 }
2008                 if (keyLimitCountdown > 0) {
2009                     keyLimitEnabled = true;
2010                 }
2011 
2012                 // DON'T initialize the cipher for AEAD!
2013             }
2014 
2015             @Override
2016             public int encrypt(byte contentType,
2017                     ByteBuffer bb) {
2018                 byte[] sn = authenticator.sequenceNumber();
2019                 byte[] nonce = iv.clone();
2020                 int offset = nonce.length - sn.length;
2021                 for (int i = 0; i < sn.length; i++) {
2022                     nonce[offset + i] ^= sn[i];
2023                 }
2024 
2025                 // initialize the AEAD cipher for the unique IV
2026                 GCMParameterSpec spec =
2027                         new GCMParameterSpec(tagSize * 8, nonce);
2028                 try {
2029                     cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
2030                 } catch (InvalidKeyException |
2031                             InvalidAlgorithmParameterException ikae) {
2032                     // unlikely to happen
2033                     throw new RuntimeException(
2034                                 "invalid key or spec in GCM mode", ikae);
2035                 }
2036 
2037                 // Update the additional authentication data, using the
2038                 // implicit sequence number of the authenticator.
2039                 int outputSize = cipher.getOutputSize(bb.remaining());
2040                 byte[] aad = authenticator.acquireAuthenticationBytes(
2041                                         contentType, outputSize, sn);
2042                 cipher.updateAAD(aad);
2043 
2044                 int len, pos = bb.position();
2045                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
2046                     SSLLogger.fine(
2047                             "Plaintext before ENCRYPTION",
2048                             bb.duplicate());
2049                 }
2050 
2051                 ByteBuffer dup = bb.duplicate();
2052                 if (outputSize > bb.remaining()) {
2053                     // Need to expand the limit of the output buffer for
2054                     // the authentication tag.
2055                     //
2056                     // DON'T worry about the buffer's capacity, we have
2057                     // reserved space for the authentication tag.
2058                     bb.limit(pos + outputSize);
2059                 }
2060 
2061                 try {
2062                     len = cipher.doFinal(dup, bb);
2063                 } catch (IllegalBlockSizeException |
2064                             BadPaddingException | ShortBufferException ibse) {
2065                     // unlikely to happen
2066                     throw new RuntimeException(
2067                             "Cipher error in AEAD mode in JCE provider " +
2068                             cipher.getProvider().getName(), ibse);
2069                 }
2070 
2071                 if (len != outputSize) {
2072                     throw new RuntimeException(
2073                             "Cipher buffering error in JCE provider " +
2074                             cipher.getProvider().getName());
2075                 }
2076 
2077                 if (keyLimitEnabled) {
2078                     keyLimitCountdown -= len;
2079                 }
2080                 return len;
2081             }
2082 
2083             @Override
2084             void dispose() {
2085                 if (cipher != null) {
2086                     try {
2087                         cipher.doFinal();
2088                     } catch (Exception e) {
2089                         // swallow all types of exceptions.
2090                     }
2091                 }
2092             }
2093 
2094             @Override
2095             int getExplicitNonceSize() {
2096                 return 0;
2097             }
2098 
2099             @Override
2100             int calculateFragmentSize(int packetLimit, int headerSize) {
2101                 return packetLimit - headerSize - tagSize;
2102             }
2103 
2104             @Override
2105             int calculatePacketSize(int fragmentSize, int headerSize) {
2106                 return fragmentSize + headerSize + tagSize;
2107             }
2108         }
2109     }
2110 
2111     private static final class T12CC20P1305ReadCipherGenerator
2112             implements ReadCipherGenerator {
2113 
2114         @Override
2115         public SSLReadCipher createCipher(SSLCipher sslCipher,
2116                 Authenticator authenticator, ProtocolVersion protocolVersion,
2117                 String algorithm, Key key, AlgorithmParameterSpec params,
2118                 SecureRandom random) throws GeneralSecurityException {
2119             return new CC20P1305ReadCipher(authenticator, protocolVersion,
2120                     sslCipher, algorithm, key, params, random);
2121         }
2122 
2123         static final class CC20P1305ReadCipher extends SSLReadCipher {
2124             private final Cipher cipher;
2125             private final int tagSize;
2126             private final Key key;
2127             private final byte[] iv;
2128             private final SecureRandom random;
2129 
2130             CC20P1305ReadCipher(Authenticator authenticator,
2131                     ProtocolVersion protocolVersion,
2132                     SSLCipher sslCipher, String algorithm,
2133                     Key key, AlgorithmParameterSpec params,
2134                     SecureRandom random) throws GeneralSecurityException {
2135                 super(authenticator, protocolVersion);
2136                 this.cipher = JsseJce.getCipher(algorithm);
2137                 this.tagSize = sslCipher.tagSize;
2138                 this.key = key;
2139                 this.iv = ((IvParameterSpec)params).getIV();
2140                 this.random = random;
2141 
2142                 // DON'T initialize the cipher for AEAD!
2143             }
2144 
2145             @Override
2146             public Plaintext decrypt(byte contentType, ByteBuffer bb,
2147                     byte[] sequence) throws GeneralSecurityException {
2148                 if (bb.remaining() <= tagSize) {
2149                     throw new BadPaddingException(
2150                         "Insufficient buffer remaining for AEAD cipher " +
2151                         "fragment (" + bb.remaining() + "). Needs to be " +
2152                         "more than tag size (" + tagSize + ")");
2153                 }
2154 
2155                 byte[] sn = sequence;
2156                 if (sn == null) {
2157                     sn = authenticator.sequenceNumber();
2158                 }
2159                 byte[] nonce = new byte[iv.length];
2160                 System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
2161                         sn.length);
2162                 for (int i = 0; i < nonce.length; i++) {
2163                     nonce[i] ^= iv[i];
2164                 }
2165 
2166                 // initialize the AEAD cipher with the unique IV
2167                 AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
2168                 try {
2169                     cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
2170                 } catch (InvalidKeyException |
2171                             InvalidAlgorithmParameterException ikae) {
2172                     // unlikely to happen
2173                     throw new RuntimeException(
2174                                 "invalid key or spec in AEAD mode", ikae);
2175                 }
2176 
2177                 // update the additional authentication data
2178                 byte[] aad = authenticator.acquireAuthenticationBytes(
2179                         contentType, bb.remaining() - tagSize, sequence);
2180                 cipher.updateAAD(aad);
2181 
2182                 // DON'T decrypt the nonce_explicit for AEAD mode. The buffer
2183                 // position has moved out of the nonce_explicit range.
2184                 int len = bb.remaining();
2185                 int pos = bb.position();
2186                 ByteBuffer dup = bb.duplicate();
2187                 try {
2188                     len = cipher.doFinal(dup, bb);
2189                 } catch (IllegalBlockSizeException ibse) {
2190                     // unlikely to happen
2191                     throw new RuntimeException(
2192                         "Cipher error in AEAD mode \"" + ibse.getMessage() +
2193                         " \"in JCE provider " + cipher.getProvider().getName());
2194                 } catch (ShortBufferException sbe) {
2195                     // catch BouncyCastle buffering error
2196                     throw new RuntimeException("Cipher buffering error in " +
2197                         "JCE provider " + cipher.getProvider().getName(), sbe);
2198                 }
2199                 // reset the limit to the end of the decrypted data
2200                 bb.position(pos);
2201                 bb.limit(pos + len);
2202 
2203                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
2204                     SSLLogger.fine(
2205                             "Plaintext after DECRYPTION", bb.duplicate());
2206                 }
2207 
2208                 return new Plaintext(contentType,
2209                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
2210                         -1, -1L, bb.slice());
2211             }
2212 
2213             @Override
2214             void dispose() {
2215                 if (cipher != null) {
2216                     try {
2217                         cipher.doFinal();
2218                     } catch (Exception e) {
2219                         // swallow all types of exceptions.
2220                     }
2221                 }
2222             }
2223 
2224             @Override
2225             int estimateFragmentSize(int packetSize, int headerSize) {
2226                 return packetSize - headerSize - tagSize;
2227             }
2228         }
2229     }
2230 
2231     private static final class T12CC20P1305WriteCipherGenerator
2232             implements WriteCipherGenerator {
2233         @Override
2234         public SSLWriteCipher createCipher(SSLCipher sslCipher,
2235                 Authenticator authenticator, ProtocolVersion protocolVersion,
2236                 String algorithm, Key key, AlgorithmParameterSpec params,
2237                 SecureRandom random) throws GeneralSecurityException {
2238             return new CC20P1305WriteCipher(authenticator, protocolVersion,
2239                     sslCipher, algorithm, key, params, random);
2240         }
2241 
2242         private static final class CC20P1305WriteCipher extends SSLWriteCipher {
2243             private final Cipher cipher;
2244             private final int tagSize;
2245             private final Key key;
2246             private final byte[] iv;
2247             private final SecureRandom random;
2248 
2249             CC20P1305WriteCipher(Authenticator authenticator,
2250                     ProtocolVersion protocolVersion,
2251                     SSLCipher sslCipher, String algorithm,
2252                     Key key, AlgorithmParameterSpec params,
2253                     SecureRandom random) throws GeneralSecurityException {
2254                 super(authenticator, protocolVersion);
2255                 this.cipher = JsseJce.getCipher(algorithm);
2256                 this.tagSize = sslCipher.tagSize;
2257                 this.key = key;
2258                 this.iv = ((IvParameterSpec)params).getIV();
2259                 this.random = random;
2260 
2261                 keyLimitCountdown = cipherLimits.getOrDefault(
2262                         algorithm.toUpperCase() + ":" + tag[0], 0L);
2263                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
2264                     SSLLogger.fine("algorithm = " + algorithm.toUpperCase() +
2265                             ":" + tag[0] + "\ncountdown value = " +
2266                             keyLimitCountdown);
2267                 }
2268                 if (keyLimitCountdown > 0) {
2269                     keyLimitEnabled = true;
2270                 }
2271 
2272                 // DON'T initialize the cipher for AEAD!
2273             }
2274 
2275             @Override
2276             public int encrypt(byte contentType,
2277                     ByteBuffer bb) {
2278                 byte[] sn = authenticator.sequenceNumber();
2279                 byte[] nonce = new byte[iv.length];
2280                 System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
2281                         sn.length);
2282                 for (int i = 0; i < nonce.length; i++) {
2283                     nonce[i] ^= iv[i];
2284                 }
2285 
2286                 // initialize the AEAD cipher for the unique IV
2287                 AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
2288                 try {
2289                     cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
2290                 } catch (InvalidKeyException |
2291                             InvalidAlgorithmParameterException ikae) {
2292                     // unlikely to happen
2293                     throw new RuntimeException(
2294                                 "invalid key or spec in AEAD mode", ikae);
2295                 }
2296 
2297                 // Update the additional authentication data, using the
2298                 // implicit sequence number of the authenticator.
2299                 byte[] aad = authenticator.acquireAuthenticationBytes(
2300                                         contentType, bb.remaining(), null);
2301                 cipher.updateAAD(aad);
2302 
2303                 // DON'T encrypt the nonce for AEAD mode.
2304                 int len = bb.remaining();
2305                 int pos = bb.position();
2306                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
2307                     SSLLogger.fine(
2308                             "Plaintext before ENCRYPTION",
2309                             bb.duplicate());
2310                 }
2311 
2312                 ByteBuffer dup = bb.duplicate();
2313                 int outputSize = cipher.getOutputSize(dup.remaining());
2314                 if (outputSize > bb.remaining()) {
2315                     // Need to expand the limit of the output buffer for
2316                     // the authentication tag.
2317                     //
2318                     // DON'T worry about the buffer's capacity, we have
2319                     // reserved space for the authentication tag.
2320                     bb.limit(pos + outputSize);
2321                 }
2322 
2323                 try {
2324                     len = cipher.doFinal(dup, bb);
2325                 } catch (IllegalBlockSizeException |
2326                             BadPaddingException | ShortBufferException ibse) {
2327                     // unlikely to happen
2328                     throw new RuntimeException(
2329                             "Cipher error in AEAD mode in JCE provider " +
2330                             cipher.getProvider().getName(), ibse);
2331                 }
2332 
2333                 if (len != outputSize) {
2334                     throw new RuntimeException(
2335                             "Cipher buffering error in JCE provider " +
2336                             cipher.getProvider().getName());
2337                 }
2338 
2339                 return len;
2340             }
2341 
2342             @Override
2343             void dispose() {
2344                 if (cipher != null) {
2345                     try {
2346                         cipher.doFinal();
2347                     } catch (Exception e) {
2348                         // swallow all types of exceptions.
2349                     }
2350                 }
2351             }
2352 
2353             @Override
2354             int getExplicitNonceSize() {
2355                 return 0;
2356             }
2357 
2358             @Override
2359             int calculateFragmentSize(int packetLimit, int headerSize) {
2360                 return packetLimit - headerSize - tagSize;
2361             }
2362 
2363             @Override
2364             int calculatePacketSize(int fragmentSize, int headerSize) {
2365                 return fragmentSize + headerSize + tagSize;
2366             }
2367         }
2368     }
2369 
2370     private static final class T13CC20P1305ReadCipherGenerator
2371             implements ReadCipherGenerator {
2372 
2373         @Override
2374         public SSLReadCipher createCipher(SSLCipher sslCipher,
2375                 Authenticator authenticator, ProtocolVersion protocolVersion,
2376                 String algorithm, Key key, AlgorithmParameterSpec params,
2377                 SecureRandom random) throws GeneralSecurityException {
2378             return new CC20P1305ReadCipher(authenticator, protocolVersion,
2379                     sslCipher, algorithm, key, params, random);
2380         }
2381 
2382         static final class CC20P1305ReadCipher extends SSLReadCipher {
2383             private final Cipher cipher;
2384             private final int tagSize;
2385             private final Key key;
2386             private final byte[] iv;
2387             private final SecureRandom random;
2388 
2389             CC20P1305ReadCipher(Authenticator authenticator,
2390                     ProtocolVersion protocolVersion,
2391                     SSLCipher sslCipher, String algorithm,
2392                     Key key, AlgorithmParameterSpec params,
2393                     SecureRandom random) throws GeneralSecurityException {
2394                 super(authenticator, protocolVersion);
2395                 this.cipher = JsseJce.getCipher(algorithm);
2396                 this.tagSize = sslCipher.tagSize;
2397                 this.key = key;
2398                 this.iv = ((IvParameterSpec)params).getIV();
2399                 this.random = random;
2400 
2401                 // DON'T initialize the cipher for AEAD!
2402             }
2403 
2404             @Override
2405             public Plaintext decrypt(byte contentType, ByteBuffer bb,
2406                     byte[] sequence) throws GeneralSecurityException {
2407                 // An implementation may receive an unencrypted record of type
2408                 // change_cipher_spec consisting of the single byte value 0x01
2409                 // at any time after the first ClientHello message has been
2410                 // sent or received and before the peer's Finished message has
2411                 // been received and MUST simply drop it without further
2412                 // processing.
2413                 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
2414                     return new Plaintext(contentType,
2415                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
2416                         -1, -1L, bb.slice());
2417                 }
2418 
2419                 if (bb.remaining() <= tagSize) {
2420                     throw new BadPaddingException(
2421                         "Insufficient buffer remaining for AEAD cipher " +
2422                         "fragment (" + bb.remaining() + "). Needs to be " +
2423                         "more than tag size (" + tagSize + ")");
2424                 }
2425 
2426                 byte[] sn = sequence;
2427                 if (sn == null) {
2428                     sn = authenticator.sequenceNumber();
2429                 }
2430                 byte[] nonce = new byte[iv.length];
2431                 System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
2432                         sn.length);
2433                 for (int i = 0; i < nonce.length; i++) {
2434                     nonce[i] ^= iv[i];
2435                 }
2436 
2437                 // initialize the AEAD cipher with the unique IV
2438                 AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
2439                 try {
2440                     cipher.init(Cipher.DECRYPT_MODE, key, spec, random);
2441                 } catch (InvalidKeyException |
2442                             InvalidAlgorithmParameterException ikae) {
2443                     // unlikely to happen
2444                     throw new RuntimeException(
2445                                 "invalid key or spec in AEAD mode", ikae);
2446                 }
2447 
2448                 // Update the additional authentication data, using the
2449                 // implicit sequence number of the authenticator.
2450                 byte[] aad = authenticator.acquireAuthenticationBytes(
2451                                         contentType, bb.remaining(), sn);
2452                 cipher.updateAAD(aad);
2453 
2454                 int len = bb.remaining();
2455                 int pos = bb.position();
2456                 ByteBuffer dup = bb.duplicate();
2457                 try {
2458                     len = cipher.doFinal(dup, bb);
2459                 } catch (IllegalBlockSizeException ibse) {
2460                     // unlikely to happen
2461                     throw new RuntimeException(
2462                         "Cipher error in AEAD mode \"" + ibse.getMessage() +
2463                         " \"in JCE provider " + cipher.getProvider().getName());
2464                 } catch (ShortBufferException sbe) {
2465                     // catch BouncyCastle buffering error
2466                     throw new RuntimeException("Cipher buffering error in " +
2467                         "JCE provider " + cipher.getProvider().getName(), sbe);
2468                 }
2469                 // reset the limit to the end of the decrypted data
2470                 bb.position(pos);
2471                 bb.limit(pos + len);
2472 
2473                 // remove inner plaintext padding
2474                 int i = bb.limit() - 1;
2475                 for (; i > 0 && bb.get(i) == 0; i--) {
2476                     // blank
2477                 }
2478                 if (i < (pos + 1)) {
2479                     throw new BadPaddingException(
2480                             "Incorrect inner plaintext: no content type");
2481                 }
2482                 contentType = bb.get(i);
2483                 bb.limit(i);
2484 
2485                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
2486                     SSLLogger.fine(
2487                             "Plaintext after DECRYPTION", bb.duplicate());
2488                 }
2489 
2490                 return new Plaintext(contentType,
2491                         ProtocolVersion.NONE.major, ProtocolVersion.NONE.minor,
2492                         -1, -1L, bb.slice());
2493             }
2494 
2495             @Override
2496             void dispose() {
2497                 if (cipher != null) {
2498                     try {
2499                         cipher.doFinal();
2500                     } catch (Exception e) {
2501                         // swallow all types of exceptions.
2502                     }
2503                 }
2504             }
2505 
2506             @Override
2507             int estimateFragmentSize(int packetSize, int headerSize) {
2508                 return packetSize - headerSize - tagSize;
2509             }
2510         }
2511     }
2512 
2513     private static final class T13CC20P1305WriteCipherGenerator
2514             implements WriteCipherGenerator {
2515         @Override
2516         public SSLWriteCipher createCipher(SSLCipher sslCipher,
2517                 Authenticator authenticator, ProtocolVersion protocolVersion,
2518                 String algorithm, Key key, AlgorithmParameterSpec params,
2519                 SecureRandom random) throws GeneralSecurityException {
2520             return new CC20P1305WriteCipher(authenticator, protocolVersion,
2521                     sslCipher, algorithm, key, params, random);
2522         }
2523 
2524         private static final class CC20P1305WriteCipher extends SSLWriteCipher {
2525             private final Cipher cipher;
2526             private final int tagSize;
2527             private final Key key;
2528             private final byte[] iv;
2529             private final SecureRandom random;
2530 
2531             CC20P1305WriteCipher(Authenticator authenticator,
2532                     ProtocolVersion protocolVersion,
2533                     SSLCipher sslCipher, String algorithm,
2534                     Key key, AlgorithmParameterSpec params,
2535                     SecureRandom random) throws GeneralSecurityException {
2536                 super(authenticator, protocolVersion);
2537                 this.cipher = JsseJce.getCipher(algorithm);
2538                 this.tagSize = sslCipher.tagSize;
2539                 this.key = key;
2540                 this.iv = ((IvParameterSpec)params).getIV();
2541                 this.random = random;
2542 
2543                 keyLimitCountdown = cipherLimits.getOrDefault(
2544                         algorithm.toUpperCase() + ":" + tag[0], 0L);
2545                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
2546                     SSLLogger.fine("algorithm = " + algorithm.toUpperCase() +
2547                             ":" + tag[0] + "\ncountdown value = " +
2548                             keyLimitCountdown);
2549                 }
2550                 if (keyLimitCountdown > 0) {
2551                     keyLimitEnabled = true;
2552                 }
2553 
2554                 // DON'T initialize the cipher for AEAD!
2555             }
2556 
2557             @Override
2558             public int encrypt(byte contentType,
2559                     ByteBuffer bb) {
2560                 byte[] sn = authenticator.sequenceNumber();
2561                 byte[] nonce = new byte[iv.length];
2562                 System.arraycopy(sn, 0, nonce, nonce.length - sn.length,
2563                         sn.length);
2564                 for (int i = 0; i < nonce.length; i++) {
2565                     nonce[i] ^= iv[i];
2566                 }
2567 
2568                 // initialize the AEAD cipher for the unique IV
2569                 AlgorithmParameterSpec spec = new IvParameterSpec(nonce);
2570                 try {
2571                     cipher.init(Cipher.ENCRYPT_MODE, key, spec, random);
2572                 } catch (InvalidKeyException |
2573                             InvalidAlgorithmParameterException ikae) {
2574                     // unlikely to happen
2575                     throw new RuntimeException(
2576                                 "invalid key or spec in AEAD mode", ikae);
2577                 }
2578 
2579                 // Update the additional authentication data, using the
2580                 // implicit sequence number of the authenticator.
2581                 int outputSize = cipher.getOutputSize(bb.remaining());
2582                 byte[] aad = authenticator.acquireAuthenticationBytes(
2583                                         contentType, outputSize, sn);
2584                 cipher.updateAAD(aad);
2585 
2586                 int len = bb.remaining();
2587                 int pos = bb.position();
2588                 if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) {
2589                     SSLLogger.fine(
2590                             "Plaintext before ENCRYPTION",
2591                             bb.duplicate());
2592                 }
2593 
2594                 ByteBuffer dup = bb.duplicate();
2595                 if (outputSize > bb.remaining()) {
2596                     // Need to expand the limit of the output buffer for
2597                     // the authentication tag.
2598                     //
2599                     // DON'T worry about the buffer's capacity, we have
2600                     // reserved space for the authentication tag.
2601                     bb.limit(pos + outputSize);
2602                 }
2603 
2604                 try {
2605                     len = cipher.doFinal(dup, bb);
2606                 } catch (IllegalBlockSizeException |
2607                             BadPaddingException | ShortBufferException ibse) {
2608                     // unlikely to happen
2609                     throw new RuntimeException(
2610                             "Cipher error in AEAD mode in JCE provider " +
2611                             cipher.getProvider().getName(), ibse);
2612                 }
2613 
2614                 if (len != outputSize) {
2615                     throw new RuntimeException(
2616                             "Cipher buffering error in JCE provider " +
2617                             cipher.getProvider().getName());
2618                 }
2619 
2620                 if (keyLimitEnabled) {
2621                     keyLimitCountdown -= len;
2622                 }
2623                 return len;
2624             }
2625 
2626             @Override
2627             void dispose() {
2628                 if (cipher != null) {
2629                     try {
2630                         cipher.doFinal();
2631                     } catch (Exception e) {
2632                         // swallow all types of exceptions.
2633                     }
2634                 }
2635             }
2636 
2637             @Override
2638             int getExplicitNonceSize() {
2639                 return 0;
2640             }
2641 
2642             @Override
2643             int calculateFragmentSize(int packetLimit, int headerSize) {
2644                 return packetLimit - headerSize - tagSize;
2645             }
2646 
2647             @Override
2648             int calculatePacketSize(int fragmentSize, int headerSize) {
2649                 return fragmentSize + headerSize + tagSize;
2650             }
2651         }
2652     }
2653 
2654     private static void addMac(MAC signer,
2655             ByteBuffer destination, byte contentType) {
2656         if (signer.macAlg().size != 0) {
2657             int dstContent = destination.position();
2658             byte[] hash = signer.compute(contentType, destination, false);
2659 
2660             /*
2661              * position was advanced to limit in MAC compute above.
2662              *
2663              * Mark next area as writable (above layers should have
2664              * established that we have plenty of room), then write
2665              * out the hash.
2666              */
2667             destination.limit(destination.limit() + hash.length);
2668             destination.put(hash);
2669 
2670             // reset the position and limit
2671             destination.position(dstContent);
2672         }
2673     }
2674 
2675     // for null and stream cipher
2676     private static void checkStreamMac(MAC signer, ByteBuffer bb,
2677             byte contentType,  byte[] sequence) throws BadPaddingException {
2678         int tagLen = signer.macAlg().size;
2679 
2680         // Requires message authentication code for null, stream and
2681         // block cipher suites.
2682         if (tagLen != 0) {
2683             int contentLen = bb.remaining() - tagLen;
2684             if (contentLen < 0) {
2685                 throw new BadPaddingException("bad record");
2686             }
2687 
2688             // Run MAC computation and comparison on the payload.
2689             //
2690             // MAC data would be stripped off during the check.
2691             if (checkMacTags(contentType, bb, signer, sequence, false)) {
2692                 throw new BadPaddingException("bad record MAC");
2693             }
2694         }
2695     }
2696 
2697     // for CBC cipher
2698     private static void checkCBCMac(MAC signer, ByteBuffer bb,
2699             byte contentType, int cipheredLength,
2700             byte[] sequence) throws BadPaddingException {
2701         BadPaddingException reservedBPE = null;
2702         int tagLen = signer.macAlg().size;
2703         int pos = bb.position();
2704 
2705         if (tagLen != 0) {
2706             int contentLen = bb.remaining() - tagLen;
2707             if (contentLen < 0) {
2708                 reservedBPE = new BadPaddingException("bad record");
2709 
2710                 // set offset of the dummy MAC
2711                 contentLen = cipheredLength - tagLen;
2712                 bb.limit(pos + cipheredLength);
2713             }
2714 
2715             // Run MAC computation and comparison on the payload.
2716             //
2717             // MAC data would be stripped off during the check.
2718             if (checkMacTags(contentType, bb, signer, sequence, false)) {
2719                 if (reservedBPE == null) {
2720                     reservedBPE =
2721                             new BadPaddingException("bad record MAC");
2722                 }
2723             }
2724 
2725             // Run MAC computation and comparison on the remainder.
2726             int remainingLen = calculateRemainingLen(
2727                     signer, cipheredLength, contentLen);
2728 
2729             // NOTE: remainingLen may be bigger (less than 1 block of the
2730             // hash algorithm of the MAC) than the cipheredLength.
2731             //
2732             // Is it possible to use a static buffer, rather than allocate
2733             // it dynamically?
2734             remainingLen += signer.macAlg().size;
2735             ByteBuffer temporary = ByteBuffer.allocate(remainingLen);
2736 
2737             // Won't need to worry about the result on the remainder. And
2738             // then we won't need to worry about what's actual data to
2739             // check MAC tag on.  We start the check from the header of the
2740             // buffer so that we don't need to construct a new byte buffer.
2741             checkMacTags(contentType, temporary, signer, sequence, true);
2742         }
2743 
2744         // Is it a failover?
2745         if (reservedBPE != null) {
2746             throw reservedBPE;
2747         }
2748     }
2749 
2750     /*
2751      * Run MAC computation and comparison
2752      */
2753     private static boolean checkMacTags(byte contentType, ByteBuffer bb,
2754             MAC signer, byte[] sequence, boolean isSimulated) {
2755         int tagLen = signer.macAlg().size;
2756         int position = bb.position();
2757         int lim = bb.limit();
2758         int macOffset = lim - tagLen;
2759 
2760         bb.limit(macOffset);
2761         byte[] hash = signer.compute(contentType, bb, sequence, isSimulated);
2762         if (hash == null || tagLen != hash.length) {
2763             // Something is wrong with MAC implementation.
2764             throw new RuntimeException("Internal MAC error");
2765         }
2766 
2767         bb.position(macOffset);
2768         bb.limit(lim);
2769         try {
2770             int[] results = compareMacTags(bb, hash);
2771             return (results[0] != 0);
2772         } finally {
2773             // reset to the data
2774             bb.position(position);
2775             bb.limit(macOffset);
2776         }
2777     }
2778 
2779     /*
2780      * A constant-time comparison of the MAC tags.
2781      *
2782      * Please DON'T change the content of the ByteBuffer parameter!
2783      */
2784     private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
2785         // An array of hits is used to prevent Hotspot optimization for
2786         // the purpose of a constant-time check.
2787         int[] results = {0, 0};     // {missed #, matched #}
2788 
2789         // The caller ensures there are enough bytes available in the buffer.
2790         // So we won't need to check the remaining of the buffer.
2791         for (byte t : tag) {
2792             if (bb.get() != t) {
2793                 results[0]++;       // mismatched bytes
2794             } else {
2795                 results[1]++;       // matched bytes
2796             }
2797         }
2798 
2799         return results;
2800     }
2801 
2802     /*
2803      * Calculate the length of a dummy buffer to run MAC computation
2804      * and comparison on the remainder.
2805      *
2806      * The caller MUST ensure that the fullLen is not less than usedLen.
2807      */
2808     private static int calculateRemainingLen(
2809             MAC signer, int fullLen, int usedLen) {
2810 
2811         int blockLen = signer.macAlg().hashBlockSize;
2812         int minimalPaddingLen = signer.macAlg().minimalPaddingSize;
2813 
2814         // (blockLen - minimalPaddingLen) is the maximum message size of
2815         // the last block of hash function operation. See FIPS 180-4, or
2816         // MD5 specification.
2817         fullLen += 13 - (blockLen - minimalPaddingLen);
2818         usedLen += 13 - (blockLen - minimalPaddingLen);
2819 
2820         // Note: fullLen is always not less than usedLen, and blockLen
2821         // is always bigger than minimalPaddingLen, so we don't worry
2822         // about negative values. 0x01 is added to the result to ensure
2823         // that the return value is positive.  The extra one byte does
2824         // not impact the overall MAC compression function evaluations.
2825         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
2826                 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen;
2827     }
2828 
2829     private static int addPadding(ByteBuffer bb, int blockSize) {
2830 
2831         int     len = bb.remaining();
2832         int     offset = bb.position();
2833 
2834         int     newlen = len + 1;
2835         byte    pad;
2836         int     i;
2837 
2838         if ((newlen % blockSize) != 0) {
2839             newlen += blockSize - 1;
2840             newlen -= newlen % blockSize;
2841         }
2842         pad = (byte) (newlen - len);
2843 
2844         /*
2845          * Update the limit to what will be padded.
2846          */
2847         bb.limit(newlen + offset);
2848 
2849         /*
2850          * TLS version of the padding works for both SSLv3 and TLSv1
2851          */
2852         for (i = 0, offset += len; i < pad; i++) {
2853             bb.put(offset++, (byte) (pad - 1));
2854         }
2855 
2856         bb.position(offset);
2857         bb.limit(offset);
2858 
2859         return newlen;
2860     }
2861 
2862     private static int removePadding(ByteBuffer bb,
2863             int tagLen, int blockSize,
2864             ProtocolVersion protocolVersion) throws BadPaddingException {
2865         int len = bb.remaining();
2866         int offset = bb.position();
2867 
2868         // last byte is length byte (i.e. actual padding length - 1)
2869         int padOffset = offset + len - 1;
2870         int padLen = bb.get(padOffset) & 0xFF;
2871 
2872         int newLen = len - (padLen + 1);
2873         if ((newLen - tagLen) < 0) {
2874             // If the buffer is not long enough to contain the padding plus
2875             // a MAC tag, do a dummy constant-time padding check.
2876             //
2877             // Note that it is a dummy check, so we won't care about what is
2878             // the actual padding data.
2879             checkPadding(bb.duplicate(), (byte)(padLen & 0xFF));
2880 
2881             throw new BadPaddingException("Invalid Padding length: " + padLen);
2882         }
2883 
2884         // The padding data should be filled with the padding length value.
2885         int[] results = checkPadding(
2886                 bb.duplicate().position(offset + newLen),
2887                 (byte)(padLen & 0xFF));
2888         if (protocolVersion.useTLS10PlusSpec()) {
2889             if (results[0] != 0) {          // padding data has invalid bytes
2890                 throw new BadPaddingException("Invalid TLS padding data");
2891             }
2892         } else { // SSLv3
2893             // SSLv3 requires 0 <= length byte < block size
2894             // some implementations do 1 <= length byte <= block size,
2895             // so accept that as well
2896             // v3 does not require any particular value for the other bytes
2897             if (padLen > blockSize) {
2898                 throw new BadPaddingException("Padding length (" +
2899                 padLen + ") of SSLv3 message should not be bigger " +
2900                 "than the block size (" + blockSize + ")");
2901             }
2902         }
2903 
2904         // Reset buffer limit to remove padding.
2905         bb.limit(offset + newLen);
2906 
2907         return newLen;
2908     }
2909 
2910     /*
2911      * A constant-time check of the padding.
2912      *
2913      * NOTE that we are checking both the padding and the padLen bytes here.
2914      *
2915      * The caller MUST ensure that the bb parameter has remaining.
2916      */
2917     private static int[] checkPadding(ByteBuffer bb, byte pad) {
2918         if (!bb.hasRemaining()) {
2919             throw new RuntimeException("hasRemaining() must be positive");
2920         }
2921 
2922         // An array of hits is used to prevent Hotspot optimization for
2923         // the purpose of a constant-time check.
2924         int[] results = {0, 0};    // {missed #, matched #}
2925         bb.mark();
2926         for (int i = 0; i <= 256; bb.reset()) {
2927             for (; bb.hasRemaining() && i <= 256; i++) {
2928                 if (bb.get() != pad) {
2929                     results[0]++;       // mismatched padding data
2930                 } else {
2931                     results[1]++;       // matched padding data
2932                 }
2933             }
2934         }
2935 
2936         return results;
2937     }
2938 }