src/java.base/share/classes/sun/security/ssl/SSLCipher.java
changeset 51773 720fd6544b03
parent 51574 ed52ea83f830
child 52690 cecba555360c
equal deleted inserted replaced
51772:5432cebf6627 51773:720fd6544b03
   327                 ProtocolVersion[]>[])(new Map.Entry[] {
   327                 ProtocolVersion[]>[])(new Map.Entry[] {
   328             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
   328             new SimpleImmutableEntry<WriteCipherGenerator, ProtocolVersion[]>(
   329                 new T13GcmWriteCipherGenerator(),
   329                 new T13GcmWriteCipherGenerator(),
   330                 ProtocolVersion.PROTOCOLS_OF_13
   330                 ProtocolVersion.PROTOCOLS_OF_13
   331             )
   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             )
   332         }));
   358         }));
   333 
   359 
   334     // descriptive name including key size, e.g. AES/128
   360     // descriptive name including key size, e.g. AES/128
   335     final String description;
   361     final String description;
   336 
   362 
  2080                 return fragmentSize + headerSize + tagSize;
  2106                 return fragmentSize + headerSize + tagSize;
  2081             }
  2107             }
  2082         }
  2108         }
  2083     }
  2109     }
  2084 
  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 
  2085     private static void addMac(MAC signer,
  2654     private static void addMac(MAC signer,
  2086             ByteBuffer destination, byte contentType) {
  2655             ByteBuffer destination, byte contentType) {
  2087         if (signer.macAlg().size != 0) {
  2656         if (signer.macAlg().size != 0) {
  2088             int dstContent = destination.position();
  2657             int dstContent = destination.position();
  2089             byte[] hash = signer.compute(contentType, destination, false);
  2658             byte[] hash = signer.compute(contentType, destination, false);
  2365         }
  2934         }
  2366 
  2935 
  2367         return results;
  2936         return results;
  2368     }
  2937     }
  2369 }
  2938 }
  2370