8049312: AES/CICO test failed with on several modes
authorvaleriep
Tue, 23 Dec 2014 02:58:15 +0000
changeset 28241 b7b95c178b76
parent 28240 0d15a67e8085
child 28242 0cbef7c46996
8049312: AES/CICO test failed with on several modes Summary: Fixed error in calculating data sizes when using feedback modes Reviewed-by: xuelei
jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherFeedback.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java
jdk/src/java.base/share/classes/com/sun/crypto/provider/PCBC.java
jdk/test/ProblemList.txt
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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,8 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
+
 
 /**
  * This class represents ciphers in cipher block chaining (CBC) mode.
@@ -122,31 +124,31 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
      * @return the length of the encrypted data
      */
     int encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset)
     {
-        int i;
+        if ((plainLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int endIndex = plainOffset + plainLen;
 
         for (; plainOffset < endIndex;
              plainOffset+=blockSize, cipherOffset += blockSize) {
-            for (i=0; i<blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ r[i]);
+            for (int i = 0; i < blockSize; i++) {
+                k[i] = (byte)(plain[i + plainOffset] ^ r[i]);
             }
             embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset);
             System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
@@ -159,14 +161,10 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
      * <p>It is also the application's responsibility to make sure that
      * <code>init</code> has been called before this method is called.
      * (This check is omitted here, to avoid double checking.)
@@ -176,23 +174,23 @@
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
      * @return the length of the decrypted data
-     *
-     * @exception IllegalBlockSizeException if input data whose length does
-     * not correspond to the embedded cipher's block size is passed to the
-     * embedded cipher
      */
     int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
                 byte[] plain, int plainOffset)
     {
-        int i;
+        if ((cipherLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int endIndex = cipherOffset + cipherLen;
 
         for (; cipherOffset < endIndex;
              cipherOffset += blockSize, plainOffset += blockSize) {
             embeddedCipher.decryptBlock(cipher, cipherOffset, k, 0);
-            for (i = 0; i < blockSize; i++) {
-                plain[i+plainOffset] = (byte)(k[i] ^ r[i]);
+            for (int i = 0; i < blockSize; i++) {
+                plain[i + plainOffset] = (byte)(k[i] ^ r[i]);
             }
             System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
         }
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java	Tue Dec 23 02:58:15 2014 +0000
@@ -708,7 +708,7 @@
             len -= blockSize;
         }
         // do not count the trailing bytes which do not make up a unit
-        len = (len > 0 ? (len - (len%unitBytes)) : 0);
+        len = (len > 0 ? (len - (len % unitBytes)) : 0);
 
         // check output buffer capacity
         if ((output == null) ||
@@ -747,6 +747,9 @@
                     int bufferCapacity = buffer.length - buffered;
                     if (bufferCapacity != 0) {
                         temp = Math.min(bufferCapacity, inputConsumed);
+                        if (unitBytes != blockSize) {
+                            temp -= ((buffered + temp) % unitBytes);
+                        }
                         System.arraycopy(input, inputOffset, buffer, buffered, temp);
                         inputOffset += temp;
                         inputConsumed -= temp;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherFeedback.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherFeedback.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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 java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in cipher-feedback (CFB) mode.
@@ -133,66 +134,72 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the <code>numBytes</code>
      * @return the length of the encrypted data
      */
     int encrypt(byte[] plain, int plainOffset, int plainLen,
-                byte[] cipher, int cipherOffset)
-    {
-        int i, len;
-        len = blockSize - numBytes;
+                byte[] cipher, int cipherOffset) {
+        if ((plainLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+
+        int nShift = blockSize - numBytes;
         int loopCount = plainLen / numBytes;
-        int oddBytes = plainLen % numBytes;
 
-        if (len == 0) {
-            for (; loopCount > 0 ;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i = 0; i < blockSize; i++)
-                    register[i] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
+        for (; loopCount > 0 ;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            if (nShift != 0) {
+                System.arraycopy(register, numBytes, register, 0, nShift);
+            }
+            for (int i = 0; i < numBytes; i++) {
+                register[nShift + i] = cipher[i + cipherOffset] =
+                        (byte)(k[i] ^ plain[i + plainOffset]);
             }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    register[i] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-            }
-        } else {
-            for (; loopCount > 0 ;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<numBytes; i++)
-                    register[i+len] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
+        }
+        return plainLen;
+    }
 
-            }
-            if (oddBytes != 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<oddBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                }
+    /**
+     * Performs the last encryption operation.
+     *
+     * <p>The input plain text <code>plain</code>, starting at
+     * <code>plainOffset</code> and ending at
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
+     * The result is stored in <code>cipher</code>, starting at
+     * <code>cipherOffset</code>.
+     *
+     * @param plain the buffer with the input data to be encrypted
+     * @param plainOffset the offset in <code>plain</code>
+     * @param plainLen the length of the input data
+     * @param cipher the buffer for the result
+     * @param cipherOffset the offset in <code>cipher</code>
+     * @return the number of bytes placed into <code>cipher</code>
+     */
+    int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                     byte[] cipher, int cipherOffset) {
+
+        int oddBytes = plainLen % numBytes;
+        int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
+                          cipher, cipherOffset);
+        plainOffset += len;
+        cipherOffset += len;
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                 cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[i + plainOffset]);
             }
         }
         return plainLen;
@@ -203,17 +210,52 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
+     * @param cipher the buffer with the input data to be decrypted
+     * @param cipherOffset the offset in <code>cipherOffset</code>
+     * @param cipherLen the length of the input data
+     * @param plain the buffer for the result
+     * @param plainOffset the offset in <code>plain</code>
+     * @exception ProviderException if <code>cipherLen</code> is not
+     * a multiple of the <code>numBytes</code>
+     * @return the length of the decrypted data
+     */
+    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset) {
+        if ((cipherLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+
+        int nShift = blockSize - numBytes;
+        int loopCount = cipherLen / numBytes;
+
+        for (; loopCount > 0;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            if (nShift != 0) {
+                System.arraycopy(register, numBytes, register, 0, nShift);
+            }
+            for (int i = 0; i < numBytes; i++) {
+                register[i + nShift] = cipher[i + cipherOffset];
+                plain[i + plainOffset]
+                    = (byte)(cipher[i + cipherOffset] ^ k[i]);
+            }
+        }
+        return cipherLen;
+    }
+
+    /**
+     * Performs the last decryption operation.
      *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input cipher text <code>cipher</code>, starting at
+     * <code>cipherOffset</code> and ending at
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
+     * The result is stored in <code>plain</code>, starting at
+     * <code>plainOffset</code>.
      *
      * @param cipher the buffer with the input data to be decrypted
      * @param cipherOffset the offset in <code>cipherOffset</code>
@@ -222,53 +264,19 @@
      * @param plainOffset the offset in <code>plain</code>
      * @return the length of the decrypted data
      */
-    int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                byte[] plain, int plainOffset)
-    {
-        int i, len;
-        len = blockSize - numBytes;
-        int loopCount = cipherLen / numBytes;
-        int oddBytes = cipherLen % numBytes;
+    int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                byte[] plain, int plainOffset) {
 
-        if (len == 0) {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i = 0; i < blockSize; i++) {
-                    register[i] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
-            }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++) {
-                    register[i] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
-            }
-        } else {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<numBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
-            }
-            if (oddBytes != 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                System.arraycopy(register, numBytes, register, 0, len);
-                for (i=0; i<oddBytes; i++) {
-                    register[i+len] = cipher[i+cipherOffset];
-                    plain[i+plainOffset]
-                        = (byte)(cipher[i+cipherOffset] ^ k[i]);
-                }
+        int oddBytes = cipherLen % numBytes;
+        int len = decrypt(cipher, cipherOffset, (cipherLen - oddBytes),
+                          plain, plainOffset);
+        cipherOffset += len;
+        plainOffset += len;
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                plain[i + plainOffset]
+                    = (byte)(cipher[i + cipherOffset] ^ k[i]);
             }
         }
         return cipherLen;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 201313, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2014, 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
@@ -27,6 +27,7 @@
 
 import java.security.InvalidKeyException;
 
+
 /**
  * This class represents ciphers in counter (CTR) mode.
  *
@@ -136,14 +137,6 @@
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param in the buffer with the input data to be encrypted
      * @param inOffset the offset in <code>plain</code>
      * @param len the length of the input data
@@ -155,30 +148,7 @@
         return crypt(in, inOff, len, out, outOff);
     }
 
-    /**
-     * Performs decryption operation.
-     *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
-     * @param in the buffer with the input data to be decrypted
-     * @param inOff the offset in <code>cipherOffset</code>
-     * @param len the length of the input data
-     * @param out the buffer for the result
-     * @param outOff the offset in <code>plain</code>
-     * @return the length of the decrypted data
-     */
+    // CTR encrypt and decrypt are identical
     int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
         return crypt(in, inOff, len, out, outOff);
     }
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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 java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in electronic codebook (ECB) mode.
@@ -96,28 +97,24 @@
     /**
      * Performs encryption operation.
      *
-     * <p>The input plain text <code>plain</code>, starting at
-     * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
-     * The result is stored in <code>cipher</code>, starting at
-     * <code>cipherOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input plain text <code>in</code>, starting at
+     * <code>inOff</code> and ending at * <code>(inOff + len - 1)</code>,
+     * is encrypted. The result is stored in <code>out</code>, starting at
+     * <code>outOff</code>.
      *
      * @param in the buffer with the input data to be encrypted
-     * @param inOffset the offset in <code>plain</code>
+     * @param inOff the offset in <code>plain</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOff the offset in <code>cipher</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
      * @return the length of the encrypted data
      */
     int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         for (int i = len; i >= blockSize; i -= blockSize) {
             embeddedCipher.encryptBlock(in, inOff, out, outOff);
             inOff += blockSize;
@@ -129,28 +126,24 @@
     /**
      * Performs decryption operation.
      *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input cipher text <code>in</code>, starting at
+     * <code>inOff</code> and ending at * <code>(inOff + len - 1)</code>,
+     * is decrypted.The result is stored in <code>out</code>, starting at
+     * <code>outOff</code>.
      *
      * @param in the buffer with the input data to be decrypted
      * @param inOff the offset in <code>cipherOffset</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOff the offset in <code>plain</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
      * @return the length of the decrypted data
      */
     int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         for (int i = len; i >= blockSize; i -= blockSize) {
             embeddedCipher.decryptBlock(in, inOff, out, outOff);
             inOff += blockSize;
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -371,21 +371,19 @@
      * and ending at <code>(inOff + len - 1)</code>, is encrypted. The result
      * is stored in <code>out</code>, starting at <code>outOfs</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>len</code> is a multiple of the embedded cipher's block size,
-     * otherwise, a ProviderException will be thrown.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param in the buffer with the input data to be encrypted
      * @param inOfs the offset in <code>in</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOfs the offset in <code>out</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the number of bytes placed into the <code>out</code> buffer
      */
     int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         processAAD();
         if (len > 0) {
             gctrPAndC.update(in, inOfs, len, out, outOfs);
@@ -398,9 +396,6 @@
     /**
      * Performs encryption operation for the last time.
      *
-     * <p>NOTE: <code>len</code> may not be multiple of the embedded
-     * cipher's block size for this call.
-     *
      * @param in the input buffer with the data to be encrypted
      * @param inOfs the offset in <code>in</code>
      * @param len the length of the input data
@@ -439,21 +434,19 @@
      * is decrypted. The result is stored in <code>out</code>, starting at
      * <code>outOfs</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>len</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param in the buffer with the input data to be decrypted
      * @param inOfs the offset in <code>in</code>
      * @param len the length of the input data
      * @param out the buffer for the result
      * @param outOfs the offset in <code>out</code>
+     * @exception ProviderException if <code>len</code> is not
+     * a multiple of the block size
+     * @return the number of bytes placed into the <code>out</code> buffer
      */
     int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+        if ((len % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         processAAD();
 
         if (len > 0) {
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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 java.security.InvalidKeyException;
+import java.security.ProviderException;
 
 /**
  * This class represents ciphers in output-feedback (OFB) mode.
@@ -132,17 +133,52 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
+     * @param plain the buffer with the input data to be encrypted
+     * @param plainOffset the offset in <code>plain</code>
+     * @param plainLen the length of the input data
+     * @param cipher the buffer for the result
+     * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the <code>numBytes</code>
+     * @return the length of the encrypted data
+     */
+    int encrypt(byte[] plain, int plainOffset, int plainLen,
+                byte[] cipher, int cipherOffset) {
+
+        if ((plainLen % numBytes) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
+        int nShift = blockSize - numBytes;
+        int loopCount = plainLen / numBytes;
+
+        for (; loopCount > 0;
+             plainOffset += numBytes, cipherOffset += numBytes,
+             loopCount--) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < numBytes; i++) {
+                cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[i + plainOffset]);
+                if (nShift != 0) {
+                    System.arraycopy(register, numBytes, register, 0, nShift);
+                }
+                System.arraycopy(k, 0, register, nShift, numBytes);
+            }
+        }
+        return plainLen;
+    }
+
+    /**
+     * Performs last encryption operation.
      *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
+     * <p>The input plain text <code>plain</code>, starting at
+     * <code>plainOffset</code> and ending at
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
+     * The result is stored in <code>cipher</code>, starting at
+     * <code>cipherOffset</code>.
      *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
@@ -151,82 +187,34 @@
      * @param cipherOffset the offset in <code>cipher</code>
      * @return the length of the encrypted data
      */
-    int encrypt(byte[] plain, int plainOffset, int plainLen,
-                byte[] cipher, int cipherOffset)
-    {
-        int i;
-        int len = blockSize - numBytes;
-        int loopCount = plainLen / numBytes;
+    int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+                     byte[] cipher, int cipherOffset) {
         int oddBytes = plainLen % numBytes;
+        int len = encrypt(plain, plainOffset, (plainLen - oddBytes),
+                          cipher, cipherOffset);
+        plainOffset += len;
+        cipherOffset += len;
 
-        if (len == 0) {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<numBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(k, 0, register, 0, numBytes);
-            }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(k, 0, register, 0, numBytes);
-            }
-        } else {
-            for (; loopCount > 0;
-                 plainOffset += numBytes, cipherOffset += numBytes,
-                 loopCount--) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<numBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(register, numBytes, register, 0, len);
-                System.arraycopy(k, 0, register, len, numBytes);
-            }
-            if (oddBytes > 0) {
-                embeddedCipher.encryptBlock(register, 0, k, 0);
-                for (i=0; i<oddBytes; i++)
-                    cipher[i+cipherOffset] =
-                        (byte)(k[i] ^ plain[i+plainOffset]);
-                System.arraycopy(register, numBytes, register, 0, len);
-                System.arraycopy(k, 0, register, len, numBytes);
+        if (oddBytes != 0) {
+            embeddedCipher.encryptBlock(register, 0, k, 0);
+            for (int i = 0; i < oddBytes; i++) {
+                cipher[i + cipherOffset] =
+                    (byte)(k[i] ^ plain[ i + plainOffset]);
             }
         }
         return plainLen;
     }
 
-    /**
-     * Performs decryption operation.
-     *
-     * <p>The input cipher text <code>cipher</code>, starting at
-     * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
-     * The result is stored in <code>plain</code>, starting at
-     * <code>plainOffset</code>.
-     *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the stream unit size
-     * <code>numBytes</code>, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
-     * @param cipher the buffer with the input data to be decrypted
-     * @param cipherOffset the offset in <code>cipherOffset</code>
-     * @param cipherLen the length of the input data
-     * @param plain the buffer for the result
-     * @param plainOffset the offset in <code>plain</code>
-     * @return the length of the decrypted data
-     */
+    // OFB encrypt and decrypt are identical
     int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
-                        byte[] plain, int plainOffset)
-    {
-        // OFB encrypt and decrypt are identical
+                byte[] plain, int plainOffset) {
         return encrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
     }
+
+    // OFB encrypt and decrypt are identical
+    int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+                     byte[] plain, int plainOffset) {
+        // OFB encrypt and decrypt are identical
+        return encryptFinal(cipher, cipherOffset, cipherLen, plain, plainOffset);
+    }
 }
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/PCBC.java	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/PCBC.java	Tue Dec 23 02:58:15 2014 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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,8 @@
 package com.sun.crypto.provider;
 
 import java.security.InvalidKeyException;
+import java.security.ProviderException;
+
 
 /**
  * This class represents ciphers in Plaintext Cipher Block Chaining (PCBC)
@@ -118,38 +120,36 @@
      *
      * <p>The input plain text <code>plain</code>, starting at
      * <code>plainOffset</code> and ending at
-     * <code>(plainOffset + len - 1)</code>, is encrypted.
+     * <code>(plainOffset + plainLen - 1)</code>, is encrypted.
      * The result is stored in <code>cipher</code>, starting at
      * <code>cipherOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>plainLen</code> is a multiple of the embedded cipher's block size,
-     * as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param plain the buffer with the input data to be encrypted
      * @param plainOffset the offset in <code>plain</code>
      * @param plainLen the length of the input data
      * @param cipher the buffer for the result
      * @param cipherOffset the offset in <code>cipher</code>
+     * @exception ProviderException if <code>plainLen</code> is not
+     * a multiple of the block size
+     * @return the length of the encrypted data
      */
     int encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset)
     {
+        if ((plainLen % blockSize) != 0) {
+            throw new ProviderException("Internal error in input buffering");
+        }
         int i;
         int endIndex = plainOffset + plainLen;
 
         for (; plainOffset < endIndex;
              plainOffset += blockSize, cipherOffset += blockSize) {
-            for (i=0; i<blockSize; i++) {
-                k[i] ^= plain[i+plainOffset];
+            for (i = 0; i < blockSize; i++) {
+                k[i] ^= plain[i + plainOffset];
             }
             embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset);
             for (i = 0; i < blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ cipher[i+cipherOffset]);
+                k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]);
             }
         }
         return plainLen;
@@ -160,27 +160,25 @@
      *
      * <p>The input cipher text <code>cipher</code>, starting at
      * <code>cipherOffset</code> and ending at
-     * <code>(cipherOffset + len - 1)</code>, is decrypted.
+     * <code>(cipherOffset + cipherLen - 1)</code>, is decrypted.
      * The result is stored in <code>plain</code>, starting at
      * <code>plainOffset</code>.
      *
-     * <p>It is the application's responsibility to make sure that
-     * <code>cipherLen</code> is a multiple of the embedded cipher's block
-     * size, as any excess bytes are ignored.
-     *
-     * <p>It is also the application's responsibility to make sure that
-     * <code>init</code> has been called before this method is called.
-     * (This check is omitted here, to avoid double checking.)
-     *
      * @param cipher the buffer with the input data to be decrypted
      * @param cipherOffset the offset in <code>cipherOffset</code>
      * @param cipherLen the length of the input data
      * @param plain the buffer for the result
      * @param plainOffset the offset in <code>plain</code>
+     * @exception ProviderException if <code>cipherLen</code> is not
+     * a multiple of the block size
+     * @return the length of the decrypted data
      */
     int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
                 byte[] plain, int plainOffset)
     {
+        if ((cipherLen % blockSize) != 0) {
+             throw new ProviderException("Internal error in input buffering");
+        }
         int i;
         int endIndex = cipherOffset + cipherLen;
 
@@ -189,10 +187,10 @@
             embeddedCipher.decryptBlock(cipher, cipherOffset,
                                    plain, plainOffset);
             for (i = 0; i < blockSize; i++) {
-                plain[i+plainOffset] ^= k[i];
+                plain[i + plainOffset] ^= k[i];
             }
             for (i = 0; i < blockSize; i++) {
-                k[i] = (byte)(plain[i+plainOffset] ^ cipher[i+cipherOffset]);
+                k[i] = (byte)(plain[i + plainOffset] ^ cipher[i + cipherOffset]);
             }
         }
         return cipherLen;
--- a/jdk/test/ProblemList.txt	Tue Dec 23 02:36:48 2014 +0000
+++ b/jdk/test/ProblemList.txt	Tue Dec 23 02:58:15 2014 +0000
@@ -239,9 +239,6 @@
 java/security/KeyPairGenerator/SolarisShortDSA.java             solaris-all
 sun/security/tools/keytool/standard.sh                          solaris-all
 
-# 8049312
-com/sun/crypto/provider/Cipher/AES/CICO.java			generic-all
-
 # 8062758
 java/security/Security/ClassLoaderDeadlock/Deadlock2.sh         generic-all