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+
27+package sun.security.ssl;
28+
29+import java.io.ByteArrayInputStream;
30+import java.io.IOException;
31+import java.util.Hashtable;
32+
33+import java.security.*;
34+import javax.crypto.*;
35+import javax.crypto.spec.SecretKeySpec;
36+import javax.crypto.spec.IvParameterSpec;
37+
38+import java.nio.*;
39+
40+import sun.security.ssl.CipherSuite.*;
41+import static sun.security.ssl.CipherSuite.*;
42+
43+import 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+ */
91+final 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+}