changeset 8764:219100e82eb2

8171252: Improve exception checking 8158517: Minor optimizations to ISO10126PADDING Reviewed-by: ascarpino, mschoene
author igerasim
date Fri, 10 Nov 2017 19:04:43 +0000
parents 227722ebc440
children 913bf28ef6e7
files src/share/classes/com/sun/crypto/provider/AESCipher.java src/share/classes/com/sun/crypto/provider/AESWrapCipher.java src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java src/share/classes/com/sun/crypto/provider/BlowfishCipher.java src/share/classes/com/sun/crypto/provider/CipherCore.java src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java src/share/classes/com/sun/crypto/provider/ISO10126Padding.java src/share/classes/com/sun/crypto/provider/PBECipherCore.java src/share/classes/com/sun/crypto/provider/PKCS5Padding.java
diffstat 9 files changed, 141 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/crypto/provider/AESCipher.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/AESCipher.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -140,7 +140,7 @@
                 throw new InvalidKeyException("Key encoding must not be null");
             } else if (value.length != fixedKeySize) {
                 throw new InvalidKeyException("The key must be " +
-                    fixedKeySize*8 + " bits");
+                    fixedKeySize + " bytes");
             }
         }
     }
@@ -479,7 +479,7 @@
             throw new InvalidKeyException("Invalid AES key length: " +
                                           encoded.length + " bytes");
         }
-        return encoded.length * 8;
+        return CipherCore.multiplyExact(encoded.length, 8);
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/AESWrapCipher.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/AESWrapCipher.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,7 +156,7 @@
         if (decrypting) {
             result = inputLen - 8;
         } else {
-            result = inputLen + 8;
+            result = CipherCore.addExact(inputLen, 8);
         }
         return (result < 0? 0:result);
     }
@@ -378,7 +378,7 @@
             throw new InvalidKeyException("Invalid key length: " +
                                           encoded.length + " bytes");
         }
-        return encoded.length * 8;
+        return CipherCore.multiplyExact(encoded.length, 8);
     }
 
     /**
@@ -404,7 +404,7 @@
             throw new InvalidKeyException("Cannot get an encoding of " +
                                           "the key to be wrapped");
         }
-        byte[] out = new byte[keyVal.length + 8];
+        byte[] out = new byte[CipherCore.addExact(keyVal.length, 8)];
 
         if (keyVal.length == 8) {
             System.arraycopy(IV, 0, out, 0, IV.length);
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -257,7 +257,7 @@
     // see JCE spec
     protected int engineGetKeySize(Key key) throws InvalidKeyException {
         byte[] encodedKey = getEncodedKey(key);
-        return encodedKey.length << 3;
+        return CipherCore.multiplyExact(encodedKey.length, 8);
     }
 
 }
--- a/src/share/classes/com/sun/crypto/provider/BlowfishCipher.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/BlowfishCipher.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -373,7 +373,7 @@
      * @exception InvalidKeyException if <code>key</code> is invalid.
      */
     protected int engineGetKeySize(Key key) throws InvalidKeyException {
-        return (key.getEncoded().length * 8);
+        return CipherCore.multiplyExact(key.getEncoded().length, 8);
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/CipherCore.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/CipherCore.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -270,7 +270,8 @@
     }
 
     private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) {
-        int totalLen = buffered + inputLen + cipher.getBufferedLength();
+        int totalLen = addExact(buffered, cipher.getBufferedLength());
+        totalLen = addExact(totalLen, inputLen);
         switch (cipherMode) {
         default:
             if (padding != null && !decrypting) {
@@ -279,10 +280,10 @@
                         totalLen = diffBlocksize;
                     } else {
                         int residue = (totalLen - diffBlocksize) % blockSize;
-                        totalLen += (blockSize - residue);
+                        totalLen = addExact(totalLen, (blockSize - residue));
                     }
                 } else {
-                    totalLen += padding.padLength(totalLen);
+                    totalLen = addExact(totalLen, padding.padLength(totalLen));
                 }
             }
             break;
@@ -578,7 +579,8 @@
     int update(byte[] input, int inputOffset, int inputLen, byte[] output,
                int outputOffset) throws ShortBufferException {
         // figure out how much can be sent to crypto function
-        int len = buffered + inputLen - minBytes;
+        int len = addExact(buffered, inputLen);
+        len -= minBytes;
         if (padding != null && decrypting) {
             // do not include the padding bytes when decrypting
             len -= blockSize;
@@ -597,12 +599,12 @@
         int outLen = 0;
         if (len != 0) { // there is some work to do
             if ((input == output)
-                 && (outputOffset < (inputOffset + inputLen))
-                 && (inputOffset < (outputOffset + buffer.length))) {
+                 && (outputOffset - inputOffset < inputLen)
+                 && (inputOffset - outputOffset < buffer.length)) {
                 // copy 'input' out to avoid its content being
                 // overwritten prematurely.
                 input = Arrays.copyOfRange(input, inputOffset,
-                    inputOffset + inputLen);
+                    addExact(inputOffset, inputLen));
                 inputOffset = 0;
             }
             if (len <= buffered) {
@@ -624,13 +626,13 @@
                     if (bufferCapacity != 0) {
                         temp = Math.min(bufferCapacity, inputConsumed);
                         if (unitBytes != blockSize) {
-                            temp -= ((buffered + temp) % unitBytes);
+                            temp -= (addExact(buffered, temp) % unitBytes);
                         }
                         System.arraycopy(input, inputOffset, buffer, buffered, temp);
-                        inputOffset += temp;
+                        inputOffset = addExact(inputOffset, temp);
                         inputConsumed -= temp;
                         inputLen -= temp;
-                        buffered += temp;
+                        buffered = addExact(buffered, temp);
                     }
                     // process 'buffer'
                     if (decrypting) {
@@ -638,7 +640,7 @@
                     } else {
                          outLen = cipher.encrypt(buffer, 0, buffered, output, outputOffset);
                     }
-                    outputOffset += outLen;
+                    outputOffset = addExact(outputOffset, outLen);
                     buffered = 0;
                 }
                 if (inputConsumed > 0) { // still has input to process
@@ -670,7 +672,7 @@
         if (inputLen > 0) {
             System.arraycopy(input, inputOffset, buffer, buffered,
                              inputLen);
-            buffered += inputLen;
+            buffered = addExact(buffered, inputLen);
         }
         return outLen;
     }
@@ -776,10 +778,10 @@
         }
 
         // calculate total input length
-        int len = buffered + inputLen;
+        int len = addExact(buffered, inputLen);
 
         // calculate padding length
-        int totalLen = len + cipher.getBufferedLength();
+        int totalLen = addExact(len, cipher.getBufferedLength());
         int paddingLen = 0;
         // will the total input length be a multiple of blockSize?
         if (unitBytes != blockSize) {
@@ -812,12 +814,12 @@
         int finalBufLen = inputLen;
         if ((buffered != 0) || (!decrypting && padding != null) ||
             ((input == output)
-              && (outputOffset < (inputOffset + inputLen))
-              && (inputOffset < (outputOffset + buffer.length)))) {
+              && (outputOffset - inputOffset < inputLen)
+              && (inputOffset - outputOffset < buffer.length))) {
             if (decrypting || padding == null) {
                 paddingLen = 0;
             }
-            finalBuf = new byte[len + paddingLen];
+            finalBuf = new byte[addExact(len, paddingLen)];
             finalOffset = 0;
             if (buffered != 0) {
                 System.arraycopy(buffer, 0, finalBuf, 0, buffered);
@@ -827,7 +829,7 @@
                                  buffered, inputLen);
             }
             if (paddingLen != 0) {
-                padding.padWithLen(finalBuf, (buffered+inputLen), paddingLen);
+                padding.padWithLen(finalBuf, addExact(buffered, inputLen), paddingLen);
             }
             finalBufLen = finalBuf.length;
         }
@@ -981,4 +983,88 @@
         return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
                                           wrappedKeyType);
     }
+
+    /* Taken from java.lang.Math in OpenJDK 8 */
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    static int addExact(int x, int y) {
+        int r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    static long addExact(long x, long y) {
+        long r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    static int multiplyExact(int x, int y) {
+        long r = (long)x * (long)y;
+        if ((int)r != r) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return (int)r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    static long multiplyExact(long x, long y) {
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+           if (((y != 0) && (r / y != x)) ||
+               (x == Long.MIN_VALUE && y == -1)) {
+                throw new ArithmeticException("long overflow");
+            }
+        }
+        return r;
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -140,7 +140,7 @@
         if (decrypting) {
             result = inputLen - 16; // CHECKSUM_LEN + IV_LEN;
         } else {
-            result = inputLen + 16;
+            result = CipherCore.addExact(inputLen, 16);
         }
         return (result < 0? 0:result);
     }
@@ -456,11 +456,11 @@
         }
 
         byte[] cks = getChecksum(keyVal);
-        byte[] in = new byte[keyVal.length + CHECKSUM_LEN];
+        byte[] in = new byte[CipherCore.addExact(keyVal.length, CHECKSUM_LEN)];
         System.arraycopy(keyVal, 0, in, 0, keyVal.length);
         System.arraycopy(cks, 0, in, keyVal.length, CHECKSUM_LEN);
 
-        byte[] out = new byte[iv.length + in.length];
+        byte[] out = new byte[CipherCore.addExact(iv.length, in.length)];
         System.arraycopy(iv, 0, out, 0, iv.length);
 
         cipher.encrypt(in, 0, in.length, out, iv.length);
--- a/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,15 +63,16 @@
         if (in == null)
             return;
 
-        if ((off + len) > in.length) {
+        int idx = CipherCore.addExact(off, len);
+        if (idx > in.length) {
             throw new ShortBufferException("Buffer too small to hold padding");
         }
 
         byte paddingOctet = (byte) (len & 0xff);
-        byte[] padding = new byte[len];
+        byte[] padding = new byte[len - 1];
         SunJCE.RANDOM.nextBytes(padding);
-        padding[len-1] = paddingOctet;
-        System.arraycopy(padding, 0, in, off, len);
+        System.arraycopy(padding, 0, in, off, len - 1);
+        in[idx - 1] = paddingOctet;
         return;
     }
 
@@ -94,14 +95,15 @@
             return 0;
         }
 
-        byte lastByte = in[off + len - 1];
+        int idx = CipherCore.addExact(off, len);
+        byte lastByte = in[idx - 1];
         int padValue = (int)lastByte & 0x0ff;
         if ((padValue < 0x01)
             || (padValue > blockSize)) {
             return -1;
         }
 
-        int start = off + len - ((int)lastByte & 0x0ff);
+        int start = idx - padValue;
         if (start < off) {
             return -1;
         }
--- a/src/share/classes/com/sun/crypto/provider/PBECipherCore.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBECipherCore.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -264,7 +264,7 @@
 
         if (algo.equals("DES")) {
             // P || S (password concatenated with salt)
-            byte[] concat = new byte[passwdBytes.length + salt.length];
+            byte[] concat = new byte[CipherCore.addExact(passwdBytes.length, salt.length)];
             System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length);
             java.util.Arrays.fill(passwdBytes, (byte)0x00);
             System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length);
--- a/src/share/classes/com/sun/crypto/provider/PKCS5Padding.java	Fri Nov 10 17:31:46 2017 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PKCS5Padding.java	Fri Nov 10 19:04:43 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import javax.crypto.ShortBufferException;
+import java.util.Arrays;
 
 /**
  * This class implements padding as specified in the PKCS#5 standard.
@@ -63,14 +64,13 @@
         if (in == null)
             return;
 
-        if ((off + len) > in.length) {
+        int idx = CipherCore.addExact(off, len);
+        if (idx > in.length) {
             throw new ShortBufferException("Buffer too small to hold padding");
         }
 
         byte paddingOctet = (byte) (len & 0xff);
-        for (int i = 0; i < len; i++) {
-            in[i + off] = paddingOctet;
-        }
+        Arrays.fill(in, off, idx, paddingOctet);
         return;
     }
 
@@ -92,25 +92,24 @@
             (len == 0)) { // this can happen if input is really a padded buffer
             return 0;
         }
-
-        byte lastByte = in[off + len - 1];
+        int idx = CipherCore.addExact(off, len);
+        byte lastByte = in[idx - 1];
         int padValue = (int)lastByte & 0x0ff;
         if ((padValue < 0x01)
             || (padValue > blockSize)) {
             return -1;
         }
 
-        int start = off + len - ((int)lastByte & 0x0ff);
+        int start = idx - padValue;
         if (start < off) {
             return -1;
         }
 
-        for (int i = 0; i < ((int)lastByte & 0x0ff); i++) {
-            if (in[start+i] != lastByte) {
+        for (int i = start; i < idx; i++) {
+            if (in[i] != lastByte) {
                 return -1;
             }
         }
-
         return start;
     }