This adds an `update' method to Mac and an `engineUpdate' method to MacSpi that take a ByteBuffer as input. The default implementation of `engineUpdate' works by using a small byte array to get bytes from the buffer, then passes that byte array to another `engineUpdate'. I have a Mauve testlet for this.

This also adds some "security parameters" classes, which handle encryption, MAC verification, and compression of SSL records. I'm also refactoring some classes to use `foo' accessors instead of `getFoo' ones.

Thanks.

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

        * gnu/javax/net/ssl/provider/Record.java
        (getContentType, getFragment, getFragment, getLength, getVersion):
        call new accessors.
        (contentType, fragment, fragment, length, version): new methods.
        * gnu/javax/net/ssl/provider/CipheredStruct.java,
        * gnu/javax/net/ssl/provider/GenericBlockCipher.java,
        * gnu/javax/net/ssl/provider/GenericStreamCipher.java,
        * gnu/javax/net/ssl/provider/InputSecurityParameters.java,      
        * gnu/javax/net/ssl/provider/OutputSecurityParameters.java: new
        files.
        * javax/crypto/Mac.java (update): new method.
        * javax/crypto/MacSpi.java (engineUpdate): new method.

Index: gnu/javax/net/ssl/provider/Record.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/gnu/javax/net/ssl/provider/Attic/Record.java,v
retrieving revision 1.1.2.1
diff -u -B -b -r1.1.2.1 Record.java
--- gnu/javax/net/ssl/provider/Record.java      7 Mar 2006 05:39:54 -0000       
1.1.2.1
+++ gnu/javax/net/ssl/provider/Record.java      27 Mar 2006 18:33:22 -0000
@@ -64,29 +64,47 @@
     this.buffer = buffer;
   }
 
+  // XXX remove
+  ContentType getContentType ()
+  {
+    return contentType ();
+  }
+
   /**
    * Gets the content type field.
    *
    * @return The content type field.
    */
-  ContentType getContentType ()
+  ContentType contentType ()
   {
     return ContentType.forInteger (buffer.get (0) & 0xFF);
   }
 
+  // XXX remove.
+  int getFragment (final ByteBuffer sink)
+  {
+    return fragment (sink);
+  }
+
   /**
    * Get the fragment content, storing it into <code>sink</code>.
    *
    * @param sink The sink for the fragment bytes.
    * @return The number of bytes put into <code>sink</code>
    */
-  int getFragment (final ByteBuffer sink)
+  int fragment (final ByteBuffer sink)
   {
-    int length = getLength ();
+    int length = length ();
     sink.put (((ByteBuffer) buffer.limit (5 + length).position (5)).slice ());
     return length;
   }
 
+  // XXX remove.
+  ByteBuffer getFragment ()
+  {
+    return fragment ();
+  }
+
   /**
    * Returns the fragment field as a ByteBuffer. The returned buffer
    * is shared with this object's underlying buffer, so it will share
@@ -95,28 +113,39 @@
    *
    * @return The fragment buffer.
    */
-  ByteBuffer getFragment ()
+  ByteBuffer fragment ()
   {
     int length = getLength ();
     return ((ByteBuffer) buffer.limit (5 + length).position (5)).slice ();
   }
 
+  // XXX remove.
+  int getLength ()
+  {
+    return length ();
+  }
+
   /**
    * Gets the fragment length.
    *
    * @return The fragment length.
    */
-  int getLength ()
+  int length ()
   {
     return buffer.getShort (3) & 0xFFFF;
   }
 
+  ProtocolVersion getVersion ()
+  {
+    return version ();
+  }
+
   /**
    * Gets the protocol version field.
    *
    * @return The protocol version field.
    */
-  ProtocolVersion getVersion ()
+  ProtocolVersion version ()
   {
     int major = buffer.get (1) & 0xFF;
     int minor = buffer.get (2) & 0xFF;
Index: gnu/javax/net/ssl/provider/CipheredStruct.java
===================================================================
RCS file: gnu/javax/net/ssl/provider/CipheredStruct.java
diff -N gnu/javax/net/ssl/provider/CipheredStruct.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/provider/CipheredStruct.java      27 Mar 2006 18:33:22 
-0000
@@ -0,0 +1,84 @@
+/* CipheredStruct.java -- abstract 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+abstract class CipheredStruct implements Constructed
+{
+  /** The content length. */
+  protected final int length;
+
+  /** The MAC length. */
+  protected final int macLength;
+
+  protected final ByteBuffer buffer;
+
+  protected CipheredStruct (final ByteBuffer buffer, final int length,
+                            final int macLength)
+  {
+    this.buffer = buffer;
+    this.length = length;
+    this.macLength = macLength;
+  }
+
+  ByteBuffer content ()
+  {
+    return ((ByteBuffer) buffer.position (0).limit (length)).slice ();
+  }
+
+  int contentLength ()
+  {
+    return length;
+  }
+
+  byte[] mac ()
+  {
+    buffer.position (length);
+    byte[] mac = new byte[macLength];
+    buffer.get (mac);
+    return mac;
+  }
+
+  void setMac (final byte[] mac, final int offset)
+  {
+    buffer.position (length);
+    buffer.put (mac, offset, macLength);
+  }
+}
\ No newline at end of file
Index: gnu/javax/net/ssl/provider/GenericBlockCipher.java
===================================================================
RCS file: gnu/javax/net/ssl/provider/GenericBlockCipher.java
diff -N gnu/javax/net/ssl/provider/GenericBlockCipher.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/provider/GenericBlockCipher.java  27 Mar 2006 18:33:22 
-0000
@@ -0,0 +1,132 @@
+/* GenericBlockCipher.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+class GenericBlockCipher extends CipheredStruct
+{
+  GenericBlockCipher (final ByteBuffer buffer, final int length,
+                      final int macLength)
+  {
+    super (buffer, length, macLength);
+  }
+
+  GenericBlockCipher (final ByteBuffer buffer, final int macLength)
+  {
+    super (buffer, determineContentLength (buffer, macLength), macLength);
+  }
+
+  private static int determineContentLength (ByteBuffer buffer, int maclen)
+  {
+    int padlen = buffer.get (buffer.limit () - 1) & 0xFF;
+    return buffer.limit () - maclen - padlen - 1;
+  }
+
+  public int getLength ()
+  {
+    return length + macLength + paddingLength () + 1;
+  }
+
+  int paddingLength ()
+  {
+    return buffer.get (buffer.limit () - 1) & 0xFF;
+  }
+
+  void setPaddingLength (final int paddingLength)
+  {
+    buffer.put (length + macLength + paddingLength, (byte) paddingLength);
+  }
+
+  byte[] padding ()
+  {
+    int len = paddingLength ();
+    byte[] pad = new byte[len];
+    buffer.position (length + macLength);
+    buffer.get (pad);
+    return pad;
+  }
+
+  /**
+   * Sets the padding. Note, this assumes that the padding length has
+   * already been set.
+   */
+  void setPadding (final byte[] pad, final int offset)
+  {
+    int len = paddingLength ();
+    buffer.position (length + macLength);
+    buffer.put (pad, offset, len);
+  }
+
+  void setPadding (final byte[] pad)
+  {
+    setPadding (pad, 0);
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.println ("  content =");
+    out.println (Util.hexDump (content (),
+                               prefix != null ? (prefix + "  ") : "  "));
+    if (prefix != null) out.print (prefix);
+    out.print ("  mac = ");
+    out.println (Util.toHexString (mac (), ':'));
+    if (prefix != null) out.print (prefix);
+    out.print ("  padding = ");
+    out.println (Util.toHexString (padding (), ':'));
+    if (prefix != null) out.print (prefix);
+    out.println ("} GenericBlockCipher;");
+
+    return str.toString ();
+  }
+}
\ No newline at end of file
Index: gnu/javax/net/ssl/provider/GenericStreamCipher.java
===================================================================
RCS file: gnu/javax/net/ssl/provider/GenericStreamCipher.java
diff -N gnu/javax/net/ssl/provider/GenericStreamCipher.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/provider/GenericStreamCipher.java 27 Mar 2006 18:33:22 
-0000
@@ -0,0 +1,88 @@
+/* GenericStreamCipher.java -- a stream-ciphered struct
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+class GenericStreamCipher extends CipheredStruct
+{
+  GenericStreamCipher (final ByteBuffer buffer, final int length,
+                       final int macLength)
+  {
+    super (buffer, length, macLength);
+  }
+
+  GenericStreamCipher (final ByteBuffer buffer, final int macLength)
+  {
+    super (buffer, buffer.limit () - macLength, macLength);
+  }
+
+  public int getLength ()
+  {
+    return length + macLength;
+  }
+
+  public String toString ()
+  {
+    return toString (null);
+  }
+
+  public String toString (final String prefix)
+  {
+    StringWriter str = new StringWriter ();
+    PrintWriter out = new PrintWriter (str);
+
+    if (prefix != null) out.print (prefix);
+    out.println ("struct {");
+    if (prefix != null) out.print (prefix);
+    out.println ("  content =");
+    out.println (Util.hexDump (content (),
+                               prefix != null ? (prefix + "  ") : "  "));
+    if (prefix != null) out.print (prefix);
+    out.print ("  mac = ");
+    out.println (Util.toHexString (mac (), ':'));
+    if (prefix != null) out.print (prefix);
+    out.println ("} GenericStreamCipher;");
+
+    return str.toString ();
+  }
+}
\ No newline at end of file
Index: gnu/javax/net/ssl/provider/InputSecurityParameters.java
===================================================================
RCS file: gnu/javax/net/ssl/provider/InputSecurityParameters.java
diff -N gnu/javax/net/ssl/provider/InputSecurityParameters.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/provider/InputSecurityParameters.java     27 Mar 2006 
18:33:22 -0000
@@ -0,0 +1,180 @@
+/* SecurityParameters.java -- SSL security parameters.
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+import javax.net.ssl.SSLException;
+
+class InputSecurityParameters
+{
+  private final Cipher cipher;
+  private final Mac mac;
+  private final Inflater inflater;
+  private final CipherSuite suite;
+  private long sequence;
+
+  InputSecurityParameters (final Cipher cipher, final Mac mac,
+                           final Inflater inflater, final CipherSuite suite)
+  {
+    this.cipher = cipher;
+    this.mac = mac;
+    this.inflater = inflater;
+    this.suite = suite;
+    sequence = 0;
+  }
+
+  void decrypt (Record record, ByteBuffer output)
+    throws BadPaddingException, DataFormatException, IllegalBlockSizeException,
+           MacException, SSLException, ShortBufferException
+  {
+    ByteBuffer fragment;
+    if (cipher != null)
+      {
+        ByteBuffer input = record.getFragment ();
+        fragment = ByteBuffer.allocate (input.limit ());
+        cipher.doFinal (input, fragment);
+      }
+    else
+      fragment = record.getFragment ();
+
+    int maclen = 0;
+    if (mac != null)
+      maclen = mac.getMacLength ();
+    CipheredStruct plaintext;
+
+    // We delay throwing an error for bad padding bytes until after we
+    // verify the MAC; this helps avoid timing attacks.
+    boolean badPadding = false;
+
+    if (suite.isStreamCipher ())
+      plaintext = new GenericStreamCipher (fragment, maclen);
+    else
+      {
+        plaintext = new GenericBlockCipher (fragment, maclen);
+        int padlen = ((GenericBlockCipher) plaintext).paddingLength ();
+
+        if (record.version () == ProtocolVersion.SSL_3)
+          {
+            // In SSLv3, the padding length must not be larger than
+            // the cipher's block size.
+            if (padlen > cipher.getBlockSize ())
+              badPadding = true;
+          }
+        else if (record.version () == ProtocolVersion.TLS_1)
+          {
+            // In TLSv1, the padding must be `padlen' copies of the
+            // value `padlen'.
+            byte[] pad = ((GenericBlockCipher) plaintext).padding ();
+            for (int i = 0; i < pad.length; i++)
+              if ((pad[i] & 0xFF) != padlen)
+                badPadding = true;
+          }
+      }
+
+    // Compute and check the MAC.
+    if (mac != null)
+      {
+        mac.update ((byte) (sequence >>> 56));
+        mac.update ((byte) (sequence >>> 48));
+        mac.update ((byte) (sequence >>> 40));
+        mac.update ((byte) (sequence >>> 32));
+        mac.update ((byte) (sequence >>> 24));
+        mac.update ((byte) (sequence >>> 16));
+        mac.update ((byte) (sequence >>>  8));
+        mac.update ((byte)  sequence);
+        mac.update ((byte) record.getContentType ().getValue ());
+        ProtocolVersion version = record.version ();
+        if (version != ProtocolVersion.SSL_3)
+          {
+            mac.update ((byte) version.getMajor ());
+            mac.update ((byte) version.getMinor ());
+          }
+        mac.update ((byte) (plaintext.contentLength () >>> 8));
+        mac.update ((byte)  plaintext.contentLength ());
+        mac.update (plaintext.content ());
+        byte[] mac1 = mac.doFinal ();
+        byte[] mac2 = plaintext.mac ();
+        if (!Arrays.equals (mac1, mac2))
+          badPadding = true;
+      }
+
+    // We always say "bad MAC" and not "bad padding," because saying
+    // the latter will leak information to an attacker.
+    if (badPadding)
+      throw new MacException ();
+
+    // Inflate the compressed bytes.
+    if (inflater != null)
+      {
+        byte[] inbuffer = new byte[4096];
+        byte[] outbuffer = new byte[4096];
+        boolean done = false;
+        fragment.position (0);
+        while (!done)
+          {
+            int l;
+            if (inflater.needsInput ())
+              {
+                l = Math.min (inbuffer.length, fragment.remaining ());
+                fragment.get (inbuffer, 0, l);
+                inflater.setInput (inbuffer);
+              }
+
+            l = inflater.inflate (outbuffer);
+            output.put (outbuffer, 0, l);
+            done = !fragment.hasRemaining () && inflater.finished ();
+          }
+      }
+    else
+      output.put (plaintext.content ());
+
+    sequence++;
+  }
+}
Index: gnu/javax/net/ssl/provider/OutputSecurityParameters.java
===================================================================
RCS file: gnu/javax/net/ssl/provider/OutputSecurityParameters.java
diff -N gnu/javax/net/ssl/provider/OutputSecurityParameters.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/provider/OutputSecurityParameters.java    27 Mar 2006 
18:33:22 -0000
@@ -0,0 +1,188 @@
+/* OutputSecurityParameters.java -- 
+   Copyright (C) 2006  Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.  */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+class OutputSecurityParameters
+{
+  private final Cipher cipher;
+  private final Mac mac;
+  private final Deflater deflater;
+  private final CipherSuite suite;
+  private long sequence;
+
+  OutputSecurityParameters (final Cipher cipher, final Mac mac,
+                            final Deflater deflater, final CipherSuite suite)
+  {
+    this.cipher = cipher;
+    this.mac = mac;
+    this.deflater = deflater;
+    this.suite = suite;
+    sequence = 0;
+  }
+
+  int encrypt (final Record record, final ByteBuffer output)
+    throws DataFormatException, IllegalBlockSizeException, ShortBufferException
+  {
+    int macLen = 0;
+    if (mac != null)
+      macLen = mac.getMacLength ();
+
+    int padLen = 0;
+    if (!suite.isStreamCipher ())
+      {
+        padLen = (cipher.getBlockSize() -
+                  ((record.length () + macLen + 1) % cipher.getBlockSize()));
+        // For TLSv1 or later, we can use a random amout of padding.
+//         if (version != ProtocolVersion.SSL_3 && session.random != null)
+//           {
+//             padLen += (Math.abs(session.random.nextInt ()) & 7) *
+//               outCipher.currentBlockSize();
+//             while (padLen > 255)
+//               padLen -= outCipher.currentBlockSize();
+//           }
+      }
+
+    int fragmentLength = 0;
+    ByteBuffer fragment = null;
+    // Compress the content, if needed.
+    if (deflater != null)
+      {
+        ByteBuffer in = record.fragment ();
+        fragment = ByteBuffer.allocate (record.length () + macLen + padLen + 
1024);
+        byte[] inbuf = new byte[4096];
+        byte[] outbuf = new byte[4096];
+
+        in.position (0);
+        while (in.hasRemaining ())
+          {
+            int l = Math.min (in.remaining (), inbuf.length);
+            in.get (inbuf, 0, l);
+            deflater.setInput (inbuf, 0, l);
+            if (!in.hasRemaining ())
+              deflater.finish ();
+            l = deflater.deflate (outbuf);
+            fragment.put (outbuf, 0, l);
+          }
+        fragmentLength = deflater.getTotalOut () + macLen + padLen;
+        fragment = ((ByteBuffer) fragment.position (0).limit 
(fragmentLength)).slice ();
+      }
+    else
+      {
+        fragmentLength = record.length () + macLen + padLen;
+        fragment = ByteBuffer.allocate (fragmentLength);
+        fragment.put (record.fragment ());
+      }
+
+    CipheredStruct plaintext = null;
+    if (suite.isStreamCipher ())
+      plaintext = new GenericStreamCipher (fragment, fragmentLength - macLen - 
padLen,
+                                           macLen);
+    else
+      plaintext = new GenericBlockCipher (fragment, fragmentLength - macLen - 
padLen,
+                                          macLen);
+
+    // If there is a MAC, compute it.
+    if (mac != null)
+      {
+        mac.update ((byte) (sequence >>> 56));
+        mac.update ((byte) (sequence >>> 48));
+        mac.update ((byte) (sequence >>> 40));
+        mac.update ((byte) (sequence >>> 32));
+        mac.update ((byte) (sequence >>> 24));
+        mac.update ((byte) (sequence >>> 16));
+        mac.update ((byte) (sequence >>>  8));
+        mac.update ((byte)  sequence);
+        mac.update ((byte) record.getContentType ().getValue ());
+        ProtocolVersion version = record.version ();
+        if (version != ProtocolVersion.SSL_3)
+          {
+            mac.update ((byte) version.getMajor ());
+            mac.update ((byte) version.getMinor ());
+          }
+        mac.update ((byte) (plaintext.contentLength () >>> 8));
+        mac.update ((byte)  plaintext.contentLength ());
+        mac.update (plaintext.content ());
+        plaintext.setMac (mac.doFinal (), 0);
+      }
+
+    Record outrecord = new Record (output);
+    outrecord.setContentType (record.contentType ());
+    outrecord.setVersion (record.getVersion ());
+    outrecord.setLength (fragmentLength);
+
+    if (cipher != null)
+      {
+        if (padLen > 0)
+          {
+            int x = padLen - 1;
+            byte[] padding = new byte[x];
+            for (int i = 0; i < padding.length; i++)
+              padding[i] = (byte) x;
+            ((GenericBlockCipher) plaintext).setPaddingLength (x);
+            ((GenericBlockCipher) plaintext).setPadding (padding);
+          }
+
+        try
+          {
+            cipher.doFinal (fragment, outrecord.fragment ());
+          }
+        catch (BadPaddingException bpe)
+          {
+            throw new RuntimeException ("caught BadPaddingException; this 
should not happen", bpe);
+          }
+      }
+    else
+      outrecord.fragment ().put (fragment);
+
+    sequence++;
+
+    return fragmentLength + 5;
+  }
+}
\ No newline at end of file
Index: javax/crypto/Mac.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/crypto/Mac.java,v
retrieving revision 1.4
diff -u -B -b -r1.4 Mac.java
--- javax/crypto/Mac.java       2 Jul 2005 20:32:45 -0000       1.4
+++ javax/crypto/Mac.java       27 Mar 2006 18:33:22 -0000
@@ -41,6 +41,7 @@
 import gnu.java.security.Engine;
 
 import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
@@ -398,6 +399,24 @@
   }
 
   /**
+   * Updates this MAC with the <code>remaining()</input> bytes from
+   * the given byte buffer, starting at <code>position()</code>.
+   *
+   * @param input The input bytes.
+   * @throws IllegalStateException If this instance has not been
+   *  initialized.
+   */
+  public final void update (ByteBuffer input)
+    throws IllegalStateException
+  {
+    if (virgin)
+      {
+        throw new IllegalStateException ("not initialized");
+      }
+    macSpi.engineUpdate (input);
+  }
+
+  /**
    * Clone this instance, if the underlying implementation supports it.
    *
    * @return A clone of this instance.
Index: javax/crypto/MacSpi.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/crypto/MacSpi.java,v
retrieving revision 1.4
diff -u -B -b -r1.4 MacSpi.java
--- javax/crypto/MacSpi.java    2 Jul 2005 20:32:45 -0000       1.4
+++ javax/crypto/MacSpi.java    27 Mar 2006 18:33:22 -0000
@@ -38,6 +38,7 @@
 
 package javax.crypto;
 
+import java.nio.ByteBuffer;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
@@ -142,4 +143,27 @@
    * @param length The number of bytes to update.
    */
   protected abstract void engineUpdate(byte[] input, int offset, int length);
+
+  /**
+   * Update this MAC with a byte buffer.
+   *
+   * <p>Note that the default implementation uses a byte array to
+   * repeatedly <code>get</code> bytes from the buffer, then passes
+   * that byte array to [EMAIL PROTECTED]
+   * engineUpdate(byte[],int,int)}. Subclasses are encouraged to
+   * override this implementation if they can operate more efficiently
+   * on byte buffers.
+   *
+   * @param input The input buffer.
+   */
+  protected void engineUpdate (ByteBuffer input)
+  {
+    byte[] buf = new byte[256];
+    while (input.hasRemaining ())
+      {
+        int l = Math.min (input.remaining (), 256);
+        input.get (buf, 0, l);
+        engineUpdate (buf, 0, l);
+      }
+  }
 }

Reply via email to