Hi,

This patch adds the NIO methods to Cipher and CipherSpi, which translate one byte buffer into another. Also, there's also some fixes to the API, which should fix PR 23768.

Since this fixes a bug, and is otherwise harmless, I'll commit it to main too.

2006-03-10  Casey Marshall  <[EMAIL PROTECTED]>

        Fixes PR 23768.
        * javax/crypto/Cipher.java (doFinal, doFinal, doFinal): don't
        reset `state.'
        (doFinal, update): new methods.
        (init, init, init, init): initialize `state' after trying the
        implementation, which can throw an exception.
        * javax/crypto/CipherSpi.java (engineDoFinal, engineUpdate): new
        methods.

Thanks.

Index: javax/crypto/Cipher.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/crypto/Cipher.java,v
retrieving revision 1.4
diff -u -B -b -r1.4 Cipher.java
--- javax/crypto/Cipher.java    2 Jul 2005 20:32:45 -0000       1.4
+++ javax/crypto/Cipher.java    11 Mar 2006 04:49:47 -0000
@@ -1,5 +1,5 @@
 /* Cipher.java -- Interface to a cryptographic cipher.
-   Copyright (C) 2004  Free Software Foundation, Inc.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -40,6 +40,9 @@
 
 import gnu.java.security.Engine;
 
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -496,7 +499,6 @@
       {
         throw new IllegalStateException("neither encrypting nor decrypting");
       }
-    state = INITIAL_STATE;
     return cipherSpi.engineDoFinal(input, inputOffset, inputLength);
   }
 
@@ -532,7 +534,6 @@
       {
         throw new IllegalStateException("neither encrypting nor decrypting");
       }
-    state = INITIAL_STATE;
     return cipherSpi.engineDoFinal(new byte[0], 0, 0, output, outputOffset);
   }
 
@@ -576,7 +577,6 @@
       {
         throw new IllegalStateException("neither encrypting nor decrypting");
       }
-    state = INITIAL_STATE;
     return cipherSpi.engineDoFinal(input, inputOffset, inputLength,
                                    output, outputOffset);
   }
@@ -590,6 +590,43 @@
   }
 
   /**
+   * Finishes a multi-part transformation with, or completely
+   * transforms, a byte buffer, and stores the result into the output
+   * buffer.
+   *
+   * @param input  The input buffer.
+   * @param output The output buffer.
+   * @return The number of bytes stored into the output buffer.
+   * @throws IllegalArgumentException If the input and output buffers
+   *  are the same object.
+   * @throws IllegalStateException If this cipher was not initialized
+   *  for encryption or decryption.
+   * @throws ReadOnlyBufferException If the output buffer is not
+   *  writable.
+   * @throws IllegalBlockSizeException If this cipher requires a total
+   *  input that is a multiple of its block size to complete this
+   *  transformation.
+   * @throws ShortBufferException If the output buffer is not large
+   *  enough to hold the transformed bytes.
+   * @throws BadPaddingException If the cipher is a block cipher with
+   *  a padding scheme, and the decrypted bytes do not end with a
+   *  valid padding.
+   * @since 1.5
+   */
+  public final int doFinal (ByteBuffer input, ByteBuffer output)
+    throws ReadOnlyBufferException, ShortBufferException,
+           BadPaddingException, IllegalBlockSizeException
+  {
+    if (input == output)
+      throw new IllegalArgumentException
+        ("input and output buffers cannot be the same");
+    if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
+      throw new IllegalStateException
+        ("not initialized for encrypting or decrypting");
+    return cipherSpi.engineDoFinal (input, output);
+  }
+
+  /**
    * Returns the size an output buffer needs to be if this cipher is
    * updated with a number of bytes.
    *
@@ -672,11 +709,11 @@
    */
   public final void init(int opmode, Key key) throws InvalidKeyException
   {
-    state = opmode;
     if (cipherSpi != null)
       {
         cipherSpi.engineInit(opmode, key, new SecureRandom());
       }
+    state = opmode;
   }
 
   /**
@@ -791,11 +828,11 @@
   public final void init(int opmode, Key key, SecureRandom random)
     throws InvalidKeyException
   {
-    state = opmode;
     if (cipherSpi != null)
       {
         cipherSpi.engineInit(opmode, key, random);
       }
+    state = opmode;
   }
 
   /**
@@ -890,11 +927,11 @@
                          SecureRandom random)
     throws InvalidKeyException, InvalidAlgorithmParameterException
   {
-    state = opmode;
     if (cipherSpi != null)
       {
         cipherSpi.engineInit(opmode, key, params, random);
       }
+    state = opmode;
   }
 
   /**
@@ -925,11 +962,11 @@
                          SecureRandom random)
     throws InvalidKeyException, InvalidAlgorithmParameterException
   {
-    state = opmode;
     if (cipherSpi != null)
       {
         cipherSpi.engineInit(opmode, key, params, random);
       }
+    state = opmode;
   }
 
   /**
@@ -1068,6 +1105,35 @@
   }
 
   /**
+   * Continue a multi-part transformation on a byte buffer, storing
+   * the transformed bytes into another buffer.
+   *
+   * @param input  The input buffer.
+   * @param output The output buffer.
+   * @return The number of bytes stored in <i>output</i>.
+   * @throws IllegalArgumentException If the two buffers are the same
+   *  object.
+   * @throws IllegalStateException If this cipher was not initialized
+   *  for encrypting or decrypting.
+   * @throws ReadOnlyBufferException If the output buffer is not
+   *  writable.
+   * @throws ShortBufferException If the output buffer does not have
+   *  enough available space for the transformed bytes.
+   * @since 1.5
+   */
+  public final int update (ByteBuffer input, ByteBuffer output)
+    throws ReadOnlyBufferException, ShortBufferException
+  {
+    if (input == output)
+      throw new IllegalArgumentException
+        ("input and output buffers must be different");
+    if (state != ENCRYPT_MODE && state != DECRYPT_MODE)
+      throw new IllegalStateException
+        ("not initialized for encryption or decryption");
+    return cipherSpi.engineUpdate (input, output);
+  }
+
+  /**
    * Wrap a key.
    *
    * @param key The key to wrap.
Index: javax/crypto/CipherSpi.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/crypto/CipherSpi.java,v
retrieving revision 1.2
diff -u -B -b -r1.2 CipherSpi.java
--- javax/crypto/CipherSpi.java 2 Jul 2005 20:32:45 -0000       1.2
+++ javax/crypto/CipherSpi.java 11 Mar 2006 04:49:47 -0000
@@ -1,5 +1,5 @@
 /* CipherSpi.java -- The cipher service provider interface.
-   Copyright (C) 2004  Free Software Foundation, Inc.
+   Copyright (C) 2004, 2006  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,6 +38,8 @@
 
 package javax.crypto;
 
+import java.nio.ByteBuffer;
+
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -179,6 +181,31 @@
   throws IllegalBlockSizeException, BadPaddingException, ShortBufferException;
 
   /**
+   * @since 1.5
+   */
+  protected int engineDoFinal (ByteBuffer input, ByteBuffer output)
+    throws BadPaddingException, IllegalBlockSizeException,
+           ShortBufferException
+  {
+    int total = 0;
+    byte[] inbuf = new byte[256];
+    while (input.hasRemaining ())
+      {
+        int in = Math.min (inbuf.length, input.remaining ());
+        input.get (inbuf, 0, in);
+        byte[] outbuf = new byte[engineGetOutputSize (in)];
+        int out = 0;
+        if (input.hasRemaining ()) // i.e., we have more 'update' calls
+          out = engineUpdate (inbuf, 0, in, outbuf, 0);
+        else
+          out = engineDoFinal (inbuf, 0, in, outbuf, 0);
+        output.put (outbuf, 0, out);
+        total += out;
+      }
+    return total;
+  }
+
+  /**
    * Returns the block size of the underlying cipher.
    *
    * @return The block size.
@@ -380,6 +407,26 @@
   throws ShortBufferException;
 
   /**
+   * @since 1.5
+   */
+  protected int engineUpdate (ByteBuffer input, ByteBuffer output)
+    throws ShortBufferException
+  {
+    int total = 0;
+    byte[] inbuf = new byte[256];
+    while (input.hasRemaining ())
+      {
+        int in = Math.min (inbuf.length, input.remaining ());
+        input.get (inbuf, 0, in);
+        byte[] outbuf = new byte[engineGetOutputSize (in)];
+        int out = engineUpdate (inbuf, 0, in, outbuf, 0);
+        output.put (outbuf, 0, out);
+        total += out;
+      }
+    return total;
+  }
+
+  /**
    * <p>Wrap a key.</p>
    *
    * <p>For compatibility this method is not declared

Reply via email to