History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/ssl/CipherBox.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/ssl/CipherBox.java+694−0
@@ -0,0 +1,694 @@
1/*
2 * Copyright (c) 1996, 2010, 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
27package sun.security.ssl;
28
29import java.io.ByteArrayInputStream;
30import java.io.IOException;
31import java.util.Hashtable;
32
33import java.security.*;
34import javax.crypto.*;
35import javax.crypto.spec.SecretKeySpec;
36import javax.crypto.spec.IvParameterSpec;
37
38import java.nio.*;
39
40import sun.security.ssl.CipherSuite.*;
41import static sun.security.ssl.CipherSuite.*;
42
43import sun.misc.HexDumpEncoder;
44
45
46/**
47 * This class handles bulk data enciphering/deciphering for each SSLv3
48 * message. This provides data confidentiality. Stream ciphers (such
49 * as RC4) don't need to do padding; block ciphers (e.g. DES) need it.
50 *
51 * Individual instances are obtained by calling the static method
52 * newCipherBox(), which should only be invoked by BulkCipher.newCipher().
53 *
54 * In RFC 2246, with bock ciphers in CBC mode, the Initialization
55 * Vector (IV) for the first record is generated with the other keys
56 * and secrets when the security parameters are set. The IV for
57 * subsequent records is the last ciphertext block from the previous
58 * record.
59 *
60 * In RFC 4346, the implicit Initialization Vector (IV) is replaced
61 * with an explicit IV to protect against CBC attacks. RFC 4346
62 * recommends two algorithms used to generated the per-record IV.
63 * The implementation uses the algorithm (2)(b), as described at
64 * section 6.2.3.2 of RFC 4346.
65 *
66 * The usage of IV in CBC block cipher can be illustrated in
67 * the following diagrams.
68 *
69 * (random)
70 * R P1 IV C1
71 * | | | |
72 * SIV---+ |-----+ |-... |----- |------
73 * | | | | | | | |
74 * +----+ | +----+ | +----+ | +----+ |
75 * | Ek | | + Ek + | | Dk | | | Dk | |
76 * +----+ | +----+ | +----+ | +----+ |
77 * | | | | | | | |
78 * |----| |----| SIV--+ |----| |-...
79 * | | | |
80 * IV C1 R P1
81 * (discard)
82 *
83 * CBC Encryption CBC Decryption
84 *
85 * NOTE that any ciphering involved in key exchange (e.g. with RSA) is
86 * handled separately.
87 *
88 * @author David Brownell
89 * @author Andreas Sterbenz
90 */
91final class CipherBox {
92
93 // A CipherBox that implements the identity operation
94 final static CipherBox NULL = new CipherBox();
95
96 /* Class and subclass dynamic debugging support */
97 private static final Debug debug = Debug.getInstance("ssl");
98
99 // the protocol version this cipher conforms to
100 private final ProtocolVersion protocolVersion;
101
102 // cipher object
103 private final Cipher cipher;
104
105 /**
106 * Cipher blocksize, 0 for stream ciphers
107 */
108 private int blockSize;
109
110 /**
111 * secure random
112 */
113 private SecureRandom random;
114
115 /**
116 * Fixed masks of various block size, as the initial decryption IVs
117 * for TLS 1.1 or later.
118 *
119 * For performance, we do not use random IVs. As the initial decryption
120 * IVs will be discarded by TLS decryption processes, so the fixed masks
121 * do not hurt cryptographic strength.
122 */
123 private static Hashtable<Integer, IvParameterSpec> masks;
124
125 /**
126 * NULL cipherbox. Identity operation, no encryption.
127 */
128 private CipherBox() {
129 this.protocolVersion = ProtocolVersion.DEFAULT;
130 this.cipher = null;
131 }
132
133 /**
134 * Construct a new CipherBox using the cipher transformation.
135 *
136 * @exception NoSuchAlgorithmException if no appropriate JCE Cipher
137 * implementation could be found.
138 */
139 private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher,
140 SecretKey key, IvParameterSpec iv, SecureRandom random,
141 boolean encrypt) throws NoSuchAlgorithmException {
142 try {
143 this.protocolVersion = protocolVersion;
144 this.cipher = JsseJce.getCipher(bulkCipher.transformation);
145 int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
146
147 if (random == null) {
148 random = JsseJce.getSecureRandom();
149 }
150 this.random = random;
151
152 /*
153 * RFC 4346 recommends two algorithms used to generated the
154 * per-record IV. The implementation uses the algorithm (2)(b),
155 * as described at section 6.2.3.2 of RFC 4346.
156 *
157 * As we don't care about the initial IV value for TLS 1.1 or
158 * later, so if the "iv" parameter is null, we use the default
159 * value generated by Cipher.init() for encryption, and a fixed
160 * mask for decryption.
161 */
162 if (iv == null && bulkCipher.ivSize != 0 &&
163 mode == Cipher.DECRYPT_MODE &&
164 protocolVersion.v >= ProtocolVersion.TLS11.v) {
165 iv = getFixedMask(bulkCipher.ivSize);
166 }
167
168 cipher.init(mode, key, iv, random);
169
170 // Do not call getBlockSize until after init()
171 // otherwise we would disrupt JCE delayed provider selection
172 blockSize = cipher.getBlockSize();
173 // some providers implement getBlockSize() incorrectly
174 if (blockSize == 1) {
175 blockSize = 0;
176 }
177 } catch (NoSuchAlgorithmException e) {
178 throw e;
179 } catch (Exception e) {
180 throw new NoSuchAlgorithmException
181 ("Could not create cipher " + bulkCipher, e);
182 } catch (ExceptionInInitializerError e) {
183 throw new NoSuchAlgorithmException
184 ("Could not create cipher " + bulkCipher, e);
185 }
186 }
187
188 /*
189 * Factory method to obtain a new CipherBox object.
190 */
191 static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher,
192 SecretKey key, IvParameterSpec iv, SecureRandom random,
193 boolean encrypt) throws NoSuchAlgorithmException {
194 if (cipher.allowed == false) {
195 throw new NoSuchAlgorithmException("Unsupported cipher " + cipher);
196 }
197
198 if (cipher == B_NULL) {
199 return NULL;
200 } else {
201 return new CipherBox(version, cipher, key, iv, random, encrypt);
202 }
203 }
204
205 /*
206 * Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later.
207 */
208 private static IvParameterSpec getFixedMask(int ivSize) {
209 if (masks == null) {
210 masks = new Hashtable<Integer, IvParameterSpec>(5);
211 }
212
213 IvParameterSpec iv = masks.get(ivSize);
214 if (iv == null) {
215 iv = new IvParameterSpec(new byte[ivSize]);
216 masks.put(ivSize, iv);
217 }
218
219 return iv;
220 }
221
222 /*
223 * Encrypts a block of data, returning the size of the
224 * resulting block.
225 */
226 int encrypt(byte[] buf, int offset, int len) {
227 if (cipher == null) {
228 return len;
229 }
230
231 try {
232 if (blockSize != 0) {
233 // TLSv1.1 needs a IV block
234 if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
235 // generate a random number
236 byte[] prefix = new byte[blockSize];
237 random.nextBytes(prefix);
238
239 // move forward the plaintext
240 System.arraycopy(buf, offset,
241 buf, offset + prefix.length, len);
242
243 // prefix the plaintext
244 System.arraycopy(prefix, 0,
245 buf, offset, prefix.length);
246
247 len += prefix.length;
248 }
249
250 len = addPadding(buf, offset, len, blockSize);
251 }
252 if (debug != null && Debug.isOn("plaintext")) {
253 try {
254 HexDumpEncoder hd = new HexDumpEncoder();
255
256 System.out.println(
257 "Padded plaintext before ENCRYPTION: len = "
258 + len);
259 hd.encodeBuffer(
260 new ByteArrayInputStream(buf, offset, len),
261 System.out);
262 } catch (IOException e) { }
263 }
264 int newLen = cipher.update(buf, offset, len, buf, offset);
265 if (newLen != len) {
266 // catch BouncyCastle buffering error
267 throw new RuntimeException("Cipher buffering error " +
268 "in JCE provider " + cipher.getProvider().getName());
269 }
270 return newLen;
271 } catch (ShortBufferException e) {
272 throw new ArrayIndexOutOfBoundsException(e.toString());
273 }
274 }
275
276 /*
277 * Encrypts a ByteBuffer block of data, returning the size of the
278 * resulting block.
279 *
280 * The byte buffers position and limit initially define the amount
281 * to encrypt. On return, the position and limit are
282 * set to last position padded/encrypted. The limit may have changed
283 * because of the added padding bytes.
284 */
285 int encrypt(ByteBuffer bb) {
286
287 int len = bb.remaining();
288
289 if (cipher == null) {
290 bb.position(bb.limit());
291 return len;
292 }
293
294 try {
295 int pos = bb.position();
296
297 if (blockSize != 0) {
298 // TLSv1.1 needs a IV block
299 if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
300 // generate a random number
301 byte[] prefix = new byte[blockSize];
302 random.nextBytes(prefix);
303
304 // move forward the plaintext
305 byte[] buf = null;
306 int limit = bb.limit();
307 if (bb.hasArray()) {
308 buf = bb.array();
309 System.arraycopy(buf, pos,
310 buf, pos + prefix.length, limit - pos);
311 bb.limit(limit + prefix.length);
312 } else {
313 buf = new byte[limit - pos];
314 bb.get(buf, 0, limit - pos);
315 bb.position(pos + prefix.length);
316 bb.limit(limit + prefix.length);
317 bb.put(buf);
318 }
319 bb.position(pos);
320
321 // prefix the plaintext
322 bb.put(prefix);
323 bb.position(pos);
324 }
325
326 // addPadding adjusts pos/limit
327 len = addPadding(bb, blockSize);
328 bb.position(pos);
329 }
330 if (debug != null && Debug.isOn("plaintext")) {
331 try {
332 HexDumpEncoder hd = new HexDumpEncoder();
333
334 System.out.println(
335 "Padded plaintext before ENCRYPTION: len = "
336 + len);
337 hd.encodeBuffer(bb, System.out);
338
339 } catch (IOException e) { }
340 /*
341 * reset back to beginning
342 */
343 bb.position(pos);
344 }
345
346 /*
347 * Encrypt "in-place". This does not add its own padding.
348 */
349 ByteBuffer dup = bb.duplicate();
350 int newLen = cipher.update(dup, bb);
351
352 if (bb.position() != dup.position()) {
353 throw new RuntimeException("bytebuffer padding error");
354 }
355
356 if (newLen != len) {
357 // catch BouncyCastle buffering error
358 throw new RuntimeException("Cipher buffering error " +
359 "in JCE provider " + cipher.getProvider().getName());
360 }
361 return newLen;
362 } catch (ShortBufferException e) {
363 RuntimeException exc = new RuntimeException(e.toString());
364 exc.initCause(e);
365 throw exc;
366 }
367 }
368
369
370 /*
371 * Decrypts a block of data, returning the size of the
372 * resulting block if padding was required.
373 *
374 * For SSLv3 and TLSv1.0, with block ciphers in CBC mode the
375 * Initialization Vector (IV) for the first record is generated by
376 * the handshake protocol, the IV for subsequent records is the
377 * last ciphertext block from the previous record.
378 *
379 * From TLSv1.1, the implicit IV is replaced with an explicit IV to
380 * protect against CBC attacks.
381 *
382 * Differentiating between bad_record_mac and decryption_failed alerts
383 * may permit certain attacks against CBC mode. It is preferable to
384 * uniformly use the bad_record_mac alert to hide the specific type of
385 * the error.
386 */
387 int decrypt(byte[] buf, int offset, int len) throws BadPaddingException {
388 if (cipher == null) {
389 return len;
390 }
391
392 try {
393 int newLen = cipher.update(buf, offset, len, buf, offset);
394 if (newLen != len) {
395 // catch BouncyCastle buffering error
396 throw new RuntimeException("Cipher buffering error " +
397 "in JCE provider " + cipher.getProvider().getName());
398 }
399 if (debug != null && Debug.isOn("plaintext")) {
400 try {
401 HexDumpEncoder hd = new HexDumpEncoder();
402
403 System.out.println(
404 "Padded plaintext after DECRYPTION: len = "
405 + newLen);
406 hd.encodeBuffer(
407 new ByteArrayInputStream(buf, offset, newLen),
408 System.out);
409 } catch (IOException e) { }
410 }
411 if (blockSize != 0) {
412 newLen = removePadding(buf, offset, newLen,
413 blockSize, protocolVersion);
414
415 if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
416 if (newLen < blockSize) {
417 throw new BadPaddingException("invalid explicit IV");
418 }
419
420 // discards the first cipher block, the IV component.
421 System.arraycopy(buf, offset + blockSize,
422 buf, offset, newLen - blockSize);
423
424 newLen -= blockSize;
425 }
426 }
427 return newLen;
428 } catch (ShortBufferException e) {
429 throw new ArrayIndexOutOfBoundsException(e.toString());
430 }
431 }
432
433
434 /*
435 * Decrypts a block of data, returning the size of the
436 * resulting block if padding was required. position and limit
437 * point to the end of the decrypted/depadded data. The initial
438 * limit and new limit may be different, given we may
439 * have stripped off some padding bytes.
440 *
441 * @see decrypt(byte[], int, int)
442 */
443 int decrypt(ByteBuffer bb) throws BadPaddingException {
444
445 int len = bb.remaining();
446
447 if (cipher == null) {
448 bb.position(bb.limit());
449 return len;
450 }
451
452 try {
453 /*
454 * Decrypt "in-place".
455 */
456 int pos = bb.position();
457 ByteBuffer dup = bb.duplicate();
458 int newLen = cipher.update(dup, bb);
459 if (newLen != len) {
460 // catch BouncyCastle buffering error
461 throw new RuntimeException("Cipher buffering error " +
462 "in JCE provider " + cipher.getProvider().getName());
463 }
464
465 if (debug != null && Debug.isOn("plaintext")) {
466 bb.position(pos);
467 try {
468 HexDumpEncoder hd = new HexDumpEncoder();
469
470 System.out.println(
471 "Padded plaintext after DECRYPTION: len = "
472 + newLen);
473
474 hd.encodeBuffer(bb, System.out);
475 } catch (IOException e) { }
476 }
477
478 /*
479 * Remove the block padding.
480 */
481 if (blockSize != 0) {
482 bb.position(pos);
483 newLen = removePadding(bb, blockSize, protocolVersion);
484
485 if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
486 if (newLen < blockSize) {
487 throw new BadPaddingException("invalid explicit IV");
488 }
489
490 // discards the first cipher block, the IV component.
491 byte[] buf = null;
492 int limit = bb.limit();
493 if (bb.hasArray()) {
494 buf = bb.array();
495 System.arraycopy(buf, pos + blockSize,
496 buf, pos, limit - pos - blockSize);
497 bb.limit(limit - blockSize);
498 } else {
499 buf = new byte[limit - pos - blockSize];
500 bb.position(pos + blockSize);
501 bb.get(buf);
502 bb.position(pos);
503 bb.put(buf);
504 bb.limit(limit - blockSize);
505 }
506
507 // reset the position to the end of the decrypted data
508 limit = bb.limit();
509 bb.position(limit);
510 }
511 }
512 return newLen;
513 } catch (ShortBufferException e) {
514 RuntimeException exc = new RuntimeException(e.toString());
515 exc.initCause(e);
516 throw exc;
517 }
518 }
519
520 private static int addPadding(byte[] buf, int offset, int len,
521 int blockSize) {
522 int newlen = len + 1;
523 byte pad;
524 int i;
525
526 if ((newlen % blockSize) != 0) {
527 newlen += blockSize - 1;
528 newlen -= newlen % blockSize;
529 }
530 pad = (byte) (newlen - len);
531
532 if (buf.length < (newlen + offset)) {
533 throw new IllegalArgumentException("no space to pad buffer");
534 }
535
536 /*
537 * TLS version of the padding works for both SSLv3 and TLSv1
538 */
539 for (i = 0, offset += len; i < pad; i++) {
540 buf [offset++] = (byte) (pad - 1);
541 }
542 return newlen;
543 }
544
545 /*
546 * Apply the padding to the buffer.
547 *
548 * Limit is advanced to the new buffer length.
549 * Position is equal to limit.
550 */
551 private static int addPadding(ByteBuffer bb, int blockSize) {
552
553 int len = bb.remaining();
554 int offset = bb.position();
555
556 int newlen = len + 1;
557 byte pad;
558 int i;
559
560 if ((newlen % blockSize) != 0) {
561 newlen += blockSize - 1;
562 newlen -= newlen % blockSize;
563 }
564 pad = (byte) (newlen - len);
565
566 /*
567 * Update the limit to what will be padded.
568 */
569 bb.limit(newlen + offset);
570
571 /*
572 * TLS version of the padding works for both SSLv3 and TLSv1
573 */
574 for (i = 0, offset += len; i < pad; i++) {
575 bb.put(offset++, (byte) (pad - 1));
576 }
577
578 bb.position(offset);
579 bb.limit(offset);
580
581 return newlen;
582 }
583
584
585 /*
586 * Typical TLS padding format for a 64 bit block cipher is as follows:
587 * xx xx xx xx xx xx xx 00
588 * xx xx xx xx xx xx 01 01
589 * ...
590 * xx 06 06 06 06 06 06 06
591 * 07 07 07 07 07 07 07 07
592 * TLS also allows any amount of padding from 1 and 256 bytes as long
593 * as it makes the data a multiple of the block size
594 */
595 private static int removePadding(byte[] buf, int offset, int len,
596 int blockSize, ProtocolVersion protocolVersion)
597 throws BadPaddingException {
598 // last byte is length byte (i.e. actual padding length - 1)
599 int padOffset = offset + len - 1;
600 int pad = buf[padOffset] & 0x0ff;
601
602 int newlen = len - (pad + 1);
603 if (newlen < 0) {
604 throw new BadPaddingException("Padding length invalid: " + pad);
605 }
606
607 if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
608 for (int i = 1; i <= pad; i++) {
609 int val = buf[padOffset - i] & 0xff;
610 if (val != pad) {
611 throw new BadPaddingException
612 ("Invalid TLS padding: " + val);
613 }
614 }
615 } else { // SSLv3
616 // SSLv3 requires 0 <= length byte < block size
617 // some implementations do 1 <= length byte <= block size,
618 // so accept that as well
619 // v3 does not require any particular value for the other bytes
620 if (pad > blockSize) {
621 throw new BadPaddingException("Invalid SSLv3 padding: " + pad);
622 }
623 }
624 return newlen;
625 }
626
627 /*
628 * Position/limit is equal the removed padding.
629 */
630 private static int removePadding(ByteBuffer bb,
631 int blockSize, ProtocolVersion protocolVersion)
632 throws BadPaddingException {
633
634 int len = bb.remaining();
635 int offset = bb.position();
636
637 // last byte is length byte (i.e. actual padding length - 1)
638 int padOffset = offset + len - 1;
639 int pad = bb.get(padOffset) & 0x0ff;
640
641 int newlen = len - (pad + 1);
642 if (newlen < 0) {
643 throw new BadPaddingException("Padding length invalid: " + pad);
644 }
645
646 /*
647 * We could zero the padding area, but not much useful
648 * information there.
649 */
650 if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
651 bb.put(padOffset, (byte)0); // zero the padding.
652 for (int i = 1; i <= pad; i++) {
653 int val = bb.get(padOffset - i) & 0xff;
654 if (val != pad) {
655 throw new BadPaddingException
656 ("Invalid TLS padding: " + val);
657 }
658 }
659 } else { // SSLv3
660 // SSLv3 requires 0 <= length byte < block size
661 // some implementations do 1 <= length byte <= block size,
662 // so accept that as well
663 // v3 does not require any particular value for the other bytes
664 if (pad > blockSize) {
665 throw new BadPaddingException("Invalid SSLv3 padding: " + pad);
666 }
667 }
668
669 /*
670 * Reset buffer limit to remove padding.
671 */
672 bb.position(offset + newlen);
673 bb.limit(offset + newlen);
674
675 return newlen;
676 }
677
678 /*
679 * Dispose of any intermediate state in the underlying cipher.
680 * For PKCS11 ciphers, this will release any attached sessions, and
681 * thus make finalization faster.
682 */
683 void dispose() {
684 try {
685 if (cipher != null) {
686 // ignore return value.
687 cipher.doFinal();
688 }
689 } catch (GeneralSecurityException e) {
690 // swallow for now.
691 }
692 }
693
694}