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 
SSLCipher(String transformation, CipherType cipherType, int keySize, int expandedKeySize, int ivSize, int fixedIvSize, boolean allowed, boolean exportable, Map.Entry<ReadCipherGenerator, ProtocolVersion[]>[] readCipherGenerators, Map.Entry<WriteCipherGenerator, ProtocolVersion[]>[] writeCipherGenerators)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 
createReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SecretKey key, IvParameterSpec iv, SecureRandom random)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 
createWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SecretKey key, IvParameterSpec iv, SecureRandom random)529     SSLWriteCipher createWriteCipher(Authenticator authenticator,
530             ProtocolVersion protocolVersion,
531             SecretKey key, IvParameterSpec iv,
532             SecureRandom random) throws GeneralSecurityException {
533         if (writeCipherGenerators.length == 0) {
534             return null;
535         }
536 
537         WriteCipherGenerator wcg = null;
538         for (Map.Entry<WriteCipherGenerator,
539                 ProtocolVersion[]> me : writeCipherGenerators) {
540             for (ProtocolVersion pv : me.getValue()) {
541                 if (protocolVersion == pv) {
542                     wcg = me.getKey();
543                 }
544             }
545         }
546 
547         if (wcg != null) {
548             return wcg.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      */
isAvailable()557     boolean isAvailable() {
558         return this.isAvailable;
559     }
560 
isUnlimited(int keySize, String transformation)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
toString()579     public String toString() {
580         return description;
581     }
582 
583     interface ReadCipherGenerator {
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
SSLReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion)598         SSLReadCipher(Authenticator authenticator,
599                 ProtocolVersion protocolVersion) {
600             this.authenticator = authenticator;
601             this.protocolVersion = protocolVersion;
602         }
603 
nullTlsReadCipher()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 
nullDTlsReadCipher()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 
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)626         abstract Plaintext decrypt(byte contentType, ByteBuffer bb,
627                     byte[] sequence) throws GeneralSecurityException;
628 
dispose()629         void dispose() {
630             // blank
631         }
632 
estimateFragmentSize(int packetSize, int headerSize)633         abstract int estimateFragmentSize(int packetSize, int headerSize);
634 
isNullCipher()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          */
atKeyLimit()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 {
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
SSLWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion)669         SSLWriteCipher(Authenticator authenticator,
670                 ProtocolVersion protocolVersion) {
671             this.authenticator = authenticator;
672             this.protocolVersion = protocolVersion;
673         }
674 
encrypt(byte contentType, ByteBuffer bb)675         abstract int encrypt(byte contentType, ByteBuffer bb);
676 
nullTlsWriteCipher()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 
nullDTlsWriteCipher()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 
dispose()701         void dispose() {
702             // blank
703         }
704 
getExplicitNonceSize()705         abstract int getExplicitNonceSize();
calculateFragmentSize(int packetLimit, int headerSize)706         abstract int calculateFragmentSize(int packetLimit, int headerSize);
calculatePacketSize(int fragmentSize, int headerSize)707         abstract int calculatePacketSize(int fragmentSize, int headerSize);
708 
isCBCMode()709         boolean isCBCMode() {
710             return false;
711         }
712 
isNullCipher()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          */
atKeyLimit()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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 {
NullReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion)744             NullReadCipher(Authenticator authenticator,
745                     ProtocolVersion protocolVersion) {
746                 super(authenticator, protocolVersion);
747             }
748 
749             @Override
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
estimateFragmentSize(int packetSize, int headerSize)765             int estimateFragmentSize(int packetSize, int headerSize) {
766                 int macLen = ((MAC)authenticator).macAlg().size;
767                 return packetSize - headerSize - macLen;
768             }
769 
770             @Override
isNullCipher()771             boolean isNullCipher() {
772                 return true;
773             }
774         }
775     }
776 
777     private static final
778             class NullWriteCipherGenerator implements WriteCipherGenerator {
779         @Override
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 {
NullWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion)789             NullWriteCipher(Authenticator authenticator,
790                     ProtocolVersion protocolVersion) {
791                 super(authenticator, protocolVersion);
792             }
793 
794             @Override
encrypt(byte contentType, ByteBuffer bb)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
getExplicitNonceSize()811             int getExplicitNonceSize() {
812                 return 0;
813             }
814 
815             @Override
calculateFragmentSize(int packetLimit, int headerSize)816             int calculateFragmentSize(int packetLimit, int headerSize) {
817                 int macLen = ((MAC)authenticator).macAlg().size;
818                 return packetLimit - headerSize - macLen;
819             }
820 
821             @Override
calculatePacketSize(int fragmentSize, int headerSize)822             int calculatePacketSize(int fragmentSize, int headerSize) {
823                 int macLen = ((MAC)authenticator).macAlg().size;
824                 return fragmentSize + headerSize + macLen;
825             }
826 
827             @Override
isNullCipher()828             boolean isNullCipher() {
829                 return true;
830             }
831         }
832     }
833 
834     private static final
835             class StreamReadCipherGenerator implements ReadCipherGenerator {
836         @Override
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
StreamReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
StreamWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()988             int getExplicitNonceSize() {
989                 return 0;
990             }
991 
992             @Override
calculateFragmentSize(int packetLimit, int headerSize)993             int calculateFragmentSize(int packetLimit, int headerSize) {
994                 int macLen = ((MAC)authenticator).macAlg().size;
995                 return packetLimit - headerSize - macLen;
996             }
997 
998             @Override
calculatePacketSize(int fragmentSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
BlockReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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              */
sanityCheck(int tagLen, int fragmentLen)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
BlockWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()1237             int getExplicitNonceSize() {
1238                 return 0;
1239             }
1240 
1241             @Override
calculateFragmentSize(int packetLimit, int headerSize)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
calculatePacketSize(int fragmentSize, int headerSize)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
isCBCMode()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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
BlockReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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              */
sanityCheck(int tagLen, int fragmentLen)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
BlockWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()1531             int getExplicitNonceSize() {
1532                 return cipher.getBlockSize();
1533             }
1534 
1535             @Override
calculateFragmentSize(int packetLimit, int headerSize)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
calculatePacketSize(int fragmentSize, int headerSize)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
isCBCMode()1561             boolean isCBCMode() {
1562                 return true;
1563             }
1564         }
1565     }
1566 
1567     private static final
1568             class T12GcmReadCipherGenerator implements ReadCipherGenerator {
1569         @Override
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
GcmReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
GcmWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()1800             int getExplicitNonceSize() {
1801                 return recordIvSize;
1802             }
1803 
1804             @Override
calculateFragmentSize(int packetLimit, int headerSize)1805             int calculateFragmentSize(int packetLimit, int headerSize) {
1806                 return packetLimit - headerSize - recordIvSize - tagSize;
1807             }
1808 
1809             @Override
calculatePacketSize(int fragmentSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
GcmReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
GcmWriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()2095             int getExplicitNonceSize() {
2096                 return 0;
2097             }
2098 
2099             @Override
calculateFragmentSize(int packetLimit, int headerSize)2100             int calculateFragmentSize(int packetLimit, int headerSize) {
2101                 return packetLimit - headerSize - tagSize;
2102             }
2103 
2104             @Override
calculatePacketSize(int fragmentSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
CC20P1305ReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
CC20P1305WriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()2354             int getExplicitNonceSize() {
2355                 return 0;
2356             }
2357 
2358             @Override
calculateFragmentSize(int packetLimit, int headerSize)2359             int calculateFragmentSize(int packetLimit, int headerSize) {
2360                 return packetLimit - headerSize - tagSize;
2361             }
2362 
2363             @Override
calculatePacketSize(int fragmentSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
CC20P1305ReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
decrypt(byte contentType, ByteBuffer bb, byte[] sequence)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
dispose()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
estimateFragmentSize(int packetSize, int headerSize)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
createCipher(SSLCipher sslCipher, Authenticator authenticator, ProtocolVersion protocolVersion, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
CC20P1305WriteCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SSLCipher sslCipher, String algorithm, Key key, AlgorithmParameterSpec params, SecureRandom random)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
encrypt(byte contentType, ByteBuffer bb)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
dispose()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
getExplicitNonceSize()2638             int getExplicitNonceSize() {
2639                 return 0;
2640             }
2641 
2642             @Override
calculateFragmentSize(int packetLimit, int headerSize)2643             int calculateFragmentSize(int packetLimit, int headerSize) {
2644                 return packetLimit - headerSize - tagSize;
2645             }
2646 
2647             @Override
calculatePacketSize(int fragmentSize, int headerSize)2648             int calculatePacketSize(int fragmentSize, int headerSize) {
2649                 return fragmentSize + headerSize + tagSize;
2650             }
2651         }
2652     }
2653 
addMac(MAC signer, ByteBuffer destination, byte contentType)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
checkStreamMac(MAC signer, ByteBuffer bb, byte contentType, byte[] sequence)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
checkCBCMac(MAC signer, ByteBuffer bb, byte contentType, int cipheredLength, byte[] sequence)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      */
checkMacTags(byte contentType, ByteBuffer bb, MAC signer, byte[] sequence, boolean isSimulated)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      */
compareMacTags(ByteBuffer bb, byte[] tag)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      */
calculateRemainingLen( MAC signer, int fullLen, int usedLen)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 
addPadding(ByteBuffer bb, int blockSize)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 
removePadding(ByteBuffer bb, int tagLen, int blockSize, ProtocolVersion protocolVersion)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      */
checkPadding(ByteBuffer bb, byte pad)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 }
2939