summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/javax/crypto/key
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/javax/crypto/key')
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java95
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java131
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java100
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java318
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java143
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java234
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java240
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java336
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java255
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java119
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java117
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java126
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java115
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java99
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java112
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java174
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java235
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java200
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java196
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java217
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java161
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java141
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java155
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java177
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java163
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java131
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java147
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java282
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java334
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java227
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java175
35 files changed, 6171 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java
new file mode 100644
index 000000000..3f4e0a22c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java
@@ -0,0 +1,168 @@
+/* BaseKeyAgreementParty.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+/**
+ * A base abstract class to facilitate implementations of concrete key agreement
+ * protocol handlers.
+ */
+public abstract class BaseKeyAgreementParty
+ implements IKeyAgreementParty
+{
+ protected static final BigInteger TWO = BigInteger.valueOf(2L);
+ /** The canonical name of the protocol. */
+ protected String name;
+ /** Whether the instance is initialised or not. */
+ protected boolean initialised = false;
+ /** The current step index of the protocol exchange. */
+ protected int step = -1;
+ /** Whether the exchange has concluded or not. */
+ protected boolean complete = false;
+ /** The optional {@link SecureRandom} instance to use. */
+ protected SecureRandom rnd = null;
+ /** The optional {@link IRandom} instance to use. */
+ protected IRandom irnd = null;
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ protected BaseKeyAgreementParty(String name)
+ {
+ super();
+
+ this.name = name;
+ }
+
+ public String name()
+ {
+ return name;
+ }
+
+ public void init(Map attributes) throws KeyAgreementException
+ {
+ if (initialised)
+ throw new IllegalStateException("already initialised");
+ this.engineInit(attributes);
+ initialised = true;
+ this.step = -1;
+ this.complete = false;
+ }
+
+ public OutgoingMessage processMessage(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ if (! initialised)
+ throw new IllegalStateException("not initialised");
+ if (complete)
+ throw new IllegalStateException("exchange has already concluded");
+ step++;
+ return this.engineProcessMessage(in);
+ }
+
+ public boolean isComplete()
+ {
+ return complete;
+ }
+
+ public byte[] getSharedSecret() throws KeyAgreementException
+ {
+ if (! initialised)
+ throw new KeyAgreementException("not yet initialised");
+ if (! isComplete())
+ throw new KeyAgreementException("not yet computed");
+ return engineSharedSecret();
+ }
+
+ public void reset()
+ {
+ if (initialised)
+ {
+ this.engineReset();
+ initialised = false;
+ }
+ }
+
+ protected abstract void engineInit(Map attributes)
+ throws KeyAgreementException;
+
+ protected abstract OutgoingMessage engineProcessMessage(IncomingMessage in)
+ throws KeyAgreementException;
+
+ protected abstract byte[] engineSharedSecret() throws KeyAgreementException;
+
+ protected abstract void engineReset();
+
+ /**
+ * Fills the designated byte array with random data.
+ *
+ * @param buffer the byte array to fill with random data.
+ */
+ protected void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else if (irnd != null)
+ try
+ {
+ irnd.nextBytes(buffer, 0, buffer.length);
+ }
+ catch (LimitReachedException lre)
+ {
+ irnd = null;
+ getDefaultPRNG().nextBytes(buffer);
+ }
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java
new file mode 100644
index 000000000..5642e59ed
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java
@@ -0,0 +1,95 @@
+/* GnuPBEKey.java -- A password-based encryption key.
+ 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.crypto.key;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * An implementation of a password-based encryption key.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GnuPBEKey
+ implements PBEKey
+{
+ private final PBEKeySpec spec;
+
+ public GnuPBEKey (final PBEKeySpec spec)
+ {
+ if (spec == null)
+ throw new NullPointerException ();
+ this.spec = spec;
+ }
+
+ public GnuPBEKey (char[] password, byte[] salt, int iterationCount)
+ {
+ this (new PBEKeySpec (password, salt, iterationCount));
+ }
+
+ public int getIterationCount ()
+ {
+ return spec.getIterationCount ();
+ }
+
+ public char[] getPassword ()
+ {
+ return spec.getPassword ();
+ }
+
+ public byte[] getSalt ()
+ {
+ return spec.getSalt ();
+ }
+
+ public String getAlgorithm ()
+ {
+ return "PBE";
+ }
+
+ public String getFormat ()
+ {
+ return "NONE"; // FIXME?
+ }
+
+ public byte[] getEncoded ()
+ {
+ return null; // FIXME?
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java
new file mode 100644
index 000000000..c8ca1edab
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java
@@ -0,0 +1,131 @@
+/* GnuSecretKey.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.security.util.Util;
+import java.security.Key;
+
+/**
+ * A secret key composed of a sequence of raw, unformatted octets. This class is
+ * analogous to the {@link javax.crypto.spec.SecretKeySpec} class, but is
+ * provided for platforms that do not or cannot contain that class.
+ */
+public class GnuSecretKey
+ implements Key
+{
+ private final byte[] key;
+ private final String algorithm;
+
+ /**
+ * Creates a new secret key. The supplied byte array is copied by this
+ * constructor.
+ *
+ * @param key The raw, secret key.
+ * @param algorithm The algorithm name, which can be null or empty.
+ */
+ public GnuSecretKey(byte[] key, String algorithm)
+ {
+ this(key, 0, key.length, algorithm);
+ }
+
+ /**
+ * Creates a new secret key from a portion of a byte array.
+ *
+ * @param key The raw, secret key.
+ * @param offset The offset at which the key begins.
+ * @param length The number of bytes that comprise the key.
+ * @param algorithm The algorithm name, which can be null or empty.
+ */
+ public GnuSecretKey(byte[] key, int offset, int length, String algorithm)
+ {
+ this.key = new byte[length];
+ System.arraycopy(key, offset, this.key, 0, length);
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns the algorithm name, if any.
+ *
+ * @return The algorithm name.
+ */
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the encoded key, which is merely the byte array this class was
+ * created with. A reference to the internal byte array is returned, so the
+ * caller can delete this key from memory by modifying the returned array.
+ *
+ * @return The raw key.
+ */
+ public byte[] getEncoded()
+ {
+ return key;
+ }
+
+ /**
+ * Returns the string "RAW".
+ *
+ * @return The string "RAW".
+ */
+ public String getFormat()
+ {
+ return "RAW";
+ }
+
+ public boolean equals(Object o)
+ {
+ if (! (o instanceof GnuSecretKey))
+ return false;
+ if (key.length != ((GnuSecretKey) o).key.length)
+ return false;
+ byte[] key2 = ((GnuSecretKey) o).key;
+ for (int i = 0; i < key.length; i++)
+ if (key[i] != key2[i])
+ return false;
+ return true;
+ }
+
+ public String toString()
+ {
+ return "GnuSecretKey [ " + algorithm + " " + Util.toString(key) + " ]";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java
new file mode 100644
index 000000000..64434212f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java
@@ -0,0 +1,100 @@
+/* IKeyAgreementParty.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import java.util.Map;
+
+/**
+ * The visible methods of an key agreement protocol participating party.
+ */
+public interface IKeyAgreementParty
+{
+ /**
+ * Returns the canonical name of the key agreement protocol.
+ *
+ * @return the canonical name of the key agreement protocol.
+ */
+ String name();
+
+ /**
+ * Sets up the instance to operate with specific attributes.
+ *
+ * @param attributes a map of name-values used by concrete implementations.
+ * @throws KeyAgreementException if an exception occurs during the setup.
+ */
+ void init(Map attributes) throws KeyAgreementException;
+
+ /**
+ * Processes an incoming message at one end, generating a message that will be
+ * processed by the other party(ies).
+ *
+ * @param in the incoming message.
+ * @return an outgoing message, or <code>null</code> if this is an
+ * intermediary step that does not cause any output.
+ * @throws KeyAgreementException if an exception occurs during the processing
+ * of the incoming message, or during the generation of the outgoing
+ * message.
+ */
+ OutgoingMessage processMessage(IncomingMessage in)
+ throws KeyAgreementException;
+
+ /**
+ * Returns <code>true</code> if the party in the key agreement protocol
+ * exchange has completed its part of the exchange. If this is the case an
+ * {@link IllegalStateException} is thrown for any method invocation except
+ * <code>init()</code> or <code>reset()</code>.
+ *
+ * @return <code>true</code> if this party has completed its part of the key
+ * agreement protocol exchange; <code>false</code> otherwise.
+ */
+ boolean isComplete();
+
+ /**
+ * Returns the byte array containing the shared secret as generated by this
+ * party.
+ *
+ * @return the generated shared secret.
+ * @throws KeyAgreementException if the key agreement is not yet initialised,
+ * or is initialised but the exchange is still in progress.
+ */
+ byte[] getSharedSecret() throws KeyAgreementException;
+
+ /** Resets this instance for re-use with another set of attributes. */
+ void reset();
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java
new file mode 100644
index 000000000..3b68392d6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java
@@ -0,0 +1,318 @@
+/* IncomingMessage.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec;
+import gnu.java.security.key.dss.DSSKeyPairRawCodec;
+import gnu.java.security.key.dss.DSSKeyPairX509Codec;
+import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec;
+import gnu.java.security.key.rsa.RSAKeyPairRawCodec;
+import gnu.java.security.key.rsa.RSAKeyPairX509Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairRawCodec;
+import gnu.javax.crypto.key.dh.DHKeyPairX509Codec;
+import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec;
+
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An implementation of an incoming message for use with key agreement
+ * protocols.
+ */
+public class IncomingMessage
+{
+ /** The internal buffer stream containing the message's contents. */
+ protected ByteArrayInputStream in;
+ /** The length of the message contents, according to its 4-byte header. */
+ protected int length;
+
+ /**
+ * Constructs an incoming message given the message's encoded form, including
+ * its header bytes.
+ *
+ * @param b the encoded form, including the header bytes, of an incoming
+ * message.
+ * @throws KeyAgreementException if the buffer is malformed.
+ */
+ public IncomingMessage(byte[] b) throws KeyAgreementException
+ {
+ this();
+
+ if (b.length < 4)
+ throw new KeyAgreementException("message header too short");
+ length = b[0] << 24
+ | (b[1] & 0xFF) << 16
+ | (b[2] & 0xFF) << 8
+ | (b[3] & 0xFF);
+ if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+ throw new KeyAgreementException("message size limit exceeded");
+ in = new ByteArrayInputStream(b, 4, length);
+ }
+
+ /** Trivial private constructor for use by the class method. */
+ private IncomingMessage()
+ {
+ super();
+ }
+
+ /**
+ * Returns an instance of a message given its encoded contents, excluding the
+ * message's header bytes.
+ * <p>
+ * Calls the method with the same name and three arguments as:
+ * <code>getInstance(raw, 0, raw.length)</code>.
+ *
+ * @param raw the encoded form, excluding the header bytes.
+ * @return a new instance of <code>IncomingMessage</code>.
+ */
+ public static IncomingMessage getInstance(byte[] raw)
+ {
+ return getInstance(raw, 0, raw.length);
+ }
+
+ /**
+ * Returns an instance of a message given its encoded contents, excluding the
+ * message's header bytes.
+ *
+ * @param raw the encoded form, excluding the header bytes.
+ * @param offset offset where to start using raw bytes from.
+ * @param len number of bytes to use.
+ * @return a new instance of <code>IncomingMessage</code>.
+ */
+ public static IncomingMessage getInstance(byte[] raw, int offset, int len)
+ {
+ IncomingMessage result = new IncomingMessage();
+ result.in = new ByteArrayInputStream(raw, offset, len);
+ return result;
+ }
+
+ /**
+ * Converts two octets into the number that they represent.
+ *
+ * @param b the two octets.
+ * @return the length.
+ */
+ public static int twoBytesToLength(byte[] b) throws KeyAgreementException
+ {
+ int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
+ if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+ throw new KeyAgreementException("encoded MPI size limit exceeded");
+ return result;
+ }
+
+ /**
+ * Converts four octets into the number that they represent.
+ *
+ * @param b the four octets.
+ * @return the length.
+ */
+ public static int fourBytesToLength(byte[] b) throws KeyAgreementException
+ {
+ int result = b[0] << 24
+ | (b[1] & 0xFF) << 16
+ | (b[2] & 0xFF) << 8
+ | (b[3] & 0xFF);
+ if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0)
+ throw new KeyAgreementException("encoded entity size limit exceeded");
+ return result;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return (in.available() > 0);
+ }
+
+ /**
+ * Decodes a public key from the message.
+ * <p>
+ * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for
+ * more details on the internal format.
+ *
+ * @throws KeyAgreementException if an encoding size constraint is violated or
+ * a mismatch was detected in the encoding.
+ */
+ public PublicKey readPublicKey() throws KeyAgreementException
+ {
+ if (in.available() < 5)
+ throw new KeyAgreementException("not enough bytes for a public key in message");
+ byte[] elementLengthBytes = new byte[4];
+ in.read(elementLengthBytes, 0, 4);
+ int elementLength = fourBytesToLength(elementLengthBytes);
+ if (in.available() < elementLength)
+ throw new KeyAgreementException("illegal public key encoding");
+ int keyTypeAndFormatID = in.read() & 0xFF;
+ elementLength--;
+ byte[] kb = new byte[elementLength];
+ in.read(kb, 0, elementLength);
+ // instantiate the right codec and decode
+ IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
+ return kpc.decodePublicKey(kb);
+ }
+
+ /**
+ * Decodes a private key from the message.
+ * <p>
+ * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for
+ * more details.
+ *
+ * @throws KeyAgreementException if an encoding size constraint is violated or
+ * a mismatch was detected in the encoding.
+ */
+ public PrivateKey readPrivateKey() throws KeyAgreementException
+ {
+ if (in.available() < 5)
+ throw new KeyAgreementException("not enough bytes for a private key in message");
+ byte[] elementLengthBytes = new byte[4];
+ in.read(elementLengthBytes, 0, 4);
+ int elementLength = fourBytesToLength(elementLengthBytes);
+ if (in.available() < elementLength)
+ throw new KeyAgreementException("illegal private key encoding");
+ int keyTypeAndFormatID = in.read() & 0xFF;
+ elementLength--;
+ byte[] kb = new byte[elementLength];
+ in.read(kb, 0, elementLength);
+ // instantiate the right codec and decode
+ IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID);
+ return kpc.decodePrivateKey(kb);
+ }
+
+ /**
+ * Decodes an MPI from the current message's contents.
+ *
+ * @return a native representation of an MPI.
+ * @throws KeyAgreementException if an encoding exception occurs during the
+ * operation.
+ */
+ public BigInteger readMPI() throws KeyAgreementException
+ {
+ if (in.available() < 2)
+ throw new KeyAgreementException("not enough bytes for an MPI in message");
+ byte[] elementLengthBytes = new byte[2];
+ in.read(elementLengthBytes, 0, 2);
+ int elementLength = twoBytesToLength(elementLengthBytes);
+ if (in.available() < elementLength)
+ throw new KeyAgreementException("illegal MPI encoding");
+ byte[] element = new byte[elementLength];
+ in.read(element, 0, element.length);
+ return new BigInteger(1, element);
+ }
+
+ public String readString() throws KeyAgreementException
+ {
+ if (in.available() < 2)
+ throw new KeyAgreementException("not enough bytes for a text in message");
+ byte[] elementLengthBytes = new byte[2];
+ in.read(elementLengthBytes, 0, 2);
+ int elementLength = twoBytesToLength(elementLengthBytes);
+ if (in.available() < elementLength)
+ throw new KeyAgreementException("illegal text encoding");
+ byte[] element = new byte[elementLength];
+ in.read(element, 0, element.length);
+ String result = null;
+ try
+ {
+ result = new String(element, "UTF8");
+ }
+ catch (UnsupportedEncodingException x)
+ {
+ throw new KeyAgreementException("unxupported UTF8 encoding", x);
+ }
+ return result;
+ }
+
+ private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID)
+ throws KeyAgreementException
+ {
+ int keyType = (keyTypeAndFormatID >>> 4) & 0x0F;
+ int formatID = keyTypeAndFormatID & 0x0F;
+ switch (formatID)
+ {
+ case Registry.RAW_ENCODING_ID:
+ switch (keyType)
+ {
+ case 0:
+ return new DSSKeyPairRawCodec();
+ case 1:
+ return new RSAKeyPairRawCodec();
+ case 2:
+ return new DHKeyPairRawCodec();
+ case 3:
+ return new SRPKeyPairRawCodec();
+ default:
+ throw new KeyAgreementException("Unknown key-type for Raw format: "
+ + keyType);
+ }
+ case Registry.X509_ENCODING_ID:
+ switch (keyType)
+ {
+ case 0:
+ return new DSSKeyPairX509Codec();
+ case 1:
+ return new RSAKeyPairX509Codec();
+ case 2:
+ return new DHKeyPairX509Codec();
+ default:
+ throw new KeyAgreementException("Unknown key-type for X.509 format: "
+ + keyType);
+ }
+ case Registry.PKCS8_ENCODING_ID:
+ switch (keyType)
+ {
+ case 0:
+ return new DSSKeyPairPKCS8Codec();
+ case 1:
+ return new RSAKeyPairPKCS8Codec();
+ case 2:
+ return new DHKeyPairPKCS8Codec();
+ default:
+ throw new KeyAgreementException("Unknown key-type for PKCS#8 format: "
+ + keyType);
+ }
+ default:
+ throw new KeyAgreementException("Unknown format identifier: "
+ + formatID);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java
new file mode 100644
index 000000000..06a7db70b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java
@@ -0,0 +1,168 @@
+/* KeyAgreementException.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.security.KeyManagementException;
+
+/**
+ * A generic exception indicating that an unexpected condition has been detected
+ * during the setup and/or processing of a key agreement protocol exchange.
+ */
+public class KeyAgreementException
+ extends KeyManagementException
+ implements Serializable
+{
+ /** @serial The possibly <code>null</code> <i>root</i> cause exception. */
+ private Throwable cause = null;
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code>. The
+ * root exception and the detailed message are <code>null</code>.
+ */
+ public KeyAgreementException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code> with a
+ * detailed message. The <i>root</i> exception is <code>null</code>.
+ *
+ * @param detail a possibly <code>null</code> string containing details of
+ * the exception.
+ * @see Throwable#getMessage()
+ */
+ public KeyAgreementException(String detail)
+ {
+ super(detail);
+ }
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code> with a
+ * detailed message and a <i>root</i> exception.
+ *
+ * @param detail a possibly <code>null</code> string containing details of
+ * the exception.
+ * @param cause a possibly <code>null</code> root exception that caused this
+ * exception.
+ * @see Throwable#getMessage()
+ * @see #getCause()
+ */
+ public KeyAgreementException(String detail, Throwable cause)
+ {
+ super(detail);
+ this.cause = cause;
+ }
+
+ /**
+ * Returns the cause of this throwable or <code>null</code> if the cause is
+ * nonexistent or unknown. The <i>cause</i> is the throwable that caused this
+ * exception to be thrown.
+ *
+ * @return the possibly <code>null</code> exception that caused this one.
+ */
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Prints this exception's stack trace to <code>System.err</code>. If this
+ * exception has a <i>root</i> exception; the stack trace of the <i>root</i>
+ * exception is also printed to <code>System.err</code>.
+ */
+ public void printStackTrace()
+ {
+ super.printStackTrace();
+ if (cause != null)
+ cause.printStackTrace();
+ }
+
+ /**
+ * Prints this exception's stack trace to a print stream. If this exception
+ * has a <i>root</i> exception; the stack trace of the <i>root</i> exception
+ * is also printed to the print stream.
+ *
+ * @param ps the non-null print stream to which to print.
+ */
+ public void printStackTrace(PrintStream ps)
+ {
+ super.printStackTrace(ps);
+ if (cause != null)
+ cause.printStackTrace(ps);
+ }
+
+ /**
+ * Prints this exception's stack trace to a print writer. If this exception
+ * has a <i>root</i> exception; the stack trace of the <i>root</i> exception
+ * is also printed to the print writer.
+ *
+ * @param pw the non-null print writer to use for output.
+ */
+ public void printStackTrace(PrintWriter pw)
+ {
+ super.printStackTrace(pw);
+ if (cause != null)
+ cause.printStackTrace(pw);
+ }
+
+ /**
+ * Returns the string representation of this exception. The string
+ * representation contains this exception's class name, its detailed messsage,
+ * and if it has a <i>root</i> exception, the string representation of the
+ * root exception. This string representation is meant for debugging and is
+ * not meant to be interpreted programmatically.
+ *
+ * @return the non-null string representation of this exception.
+ * @see Throwable#getMessage()
+ */
+ public String toString()
+ {
+ CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()).append(": ")
+ .append(super.toString());
+ if (cause != null)
+ sb.append("; caused by: ").append(cause.toString());
+ return sb.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java
new file mode 100644
index 000000000..a4e14bc69
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java
@@ -0,0 +1,143 @@
+/* KeyAgreementFactory.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.security.Registry;
+
+import gnu.javax.crypto.key.dh.DiffieHellmanSender;
+import gnu.javax.crypto.key.dh.DiffieHellmanReceiver;
+import gnu.javax.crypto.key.dh.ElGamalSender;
+import gnu.javax.crypto.key.dh.ElGamalReceiver;
+import gnu.javax.crypto.key.srp6.SRP6Host;
+import gnu.javax.crypto.key.srp6.SRP6User;
+import gnu.javax.crypto.key.srp6.SRP6SaslClient;
+import gnu.javax.crypto.key.srp6.SRP6SaslServer;
+import gnu.javax.crypto.key.srp6.SRP6TLSClient;
+import gnu.javax.crypto.key.srp6.SRP6TLSServer;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A <i>Factory</i> class to generate key agreement protocol handlers.
+ */
+public class KeyAgreementFactory
+{
+ /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+ private KeyAgreementFactory()
+ {
+ super();
+ }
+
+ /**
+ * Returns an instance of a key agreeent protocol handler, for party
+ * <code>A</code> in a two-party <code>A..B</code> exchange, given the
+ * canonical name of this protocol. Party <code>A</code> is usually the
+ * initiator of the exchange.
+ *
+ * @param name the case-insensitive key agreement protocol name.
+ * @return an instance of the key agreement protocol handler for party
+ * <code>A</code>, or <code>null</code> if none found.
+ */
+ public static IKeyAgreementParty getPartyAInstance(String name)
+ {
+ if (name == null)
+ return null;
+ name = name.trim();
+ IKeyAgreementParty result = null;
+ if (name.equalsIgnoreCase(Registry.DH_KA))
+ result = new DiffieHellmanSender();
+ else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA))
+ result = new ElGamalSender();
+ else if (name.equalsIgnoreCase(Registry.SRP6_KA))
+ result = new SRP6User();
+ else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA))
+ result = new SRP6SaslClient();
+ else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA))
+ result = new SRP6TLSClient();
+ return result;
+ }
+
+ /**
+ * Returns an instance of a key agreeent protocol handler, for party
+ * <code>B</code> in a two-party <code>A..B</code> exchange, given the
+ * canonical name of this protocol.
+ *
+ * @param name the case-insensitive key agreement protocol name.
+ * @return an instance of the key agreement protocol handler for party
+ * <code>B</code>, or <code>null</code> if none found.
+ */
+ public static IKeyAgreementParty getPartyBInstance(String name)
+ {
+ if (name == null)
+ return null;
+ name = name.trim();
+ IKeyAgreementParty result = null;
+ if (name.equalsIgnoreCase(Registry.DH_KA))
+ result = new DiffieHellmanReceiver();
+ else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA))
+ result = new ElGamalReceiver();
+ else if (name.equalsIgnoreCase(Registry.SRP6_KA))
+ result = new SRP6Host();
+ else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA))
+ result = new SRP6SaslServer();
+ else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA))
+ result = new SRP6TLSServer();
+ return result;
+ }
+
+ /**
+ * Returns a {@link Set} of key agreement protocol names supported by this
+ * <i>Factory</i>.
+ *
+ * @return a {@link Set} of key agreement protocol names (Strings).
+ */
+ public static final Set getNames()
+ {
+ HashSet hs = new HashSet();
+ hs.add(Registry.DH_KA);
+ hs.add(Registry.ELGAMAL_KA);
+ hs.add(Registry.SRP6_KA);
+ hs.add(Registry.SRP_SASL_KA);
+ hs.add(Registry.SRP_TLS_KA);
+
+ return Collections.unmodifiableSet(hs);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java
new file mode 100644
index 000000000..e011330fe
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java
@@ -0,0 +1,234 @@
+/* OutgoingMessage.java --
+ Copyright (C) 2003, 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.crypto.key;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.dss.DSSKey;
+import gnu.java.security.key.rsa.GnuRSAKey;
+import gnu.java.security.util.FormatUtil;
+import gnu.javax.crypto.key.dh.GnuDHKey;
+import gnu.javax.crypto.key.srp6.SRPKey;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.math.BigInteger;
+
+/**
+ * An implementation of outgoing messages for use with key agreement protocols.
+ */
+public class OutgoingMessage
+{
+ /** The internal output stream. */
+ private ByteArrayOutputStream out;
+
+ public OutgoingMessage()
+ {
+ super();
+
+ out = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Returns the encoded form of the current message including the 4-byte length
+ * header.
+ *
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ public byte[] toByteArray() throws KeyAgreementException
+ {
+ byte[] buffer = wrap();
+ int length = buffer.length;
+ byte[] result = new byte[length + 4];
+ result[0] = (byte)(length >>> 24);
+ result[1] = (byte)(length >>> 16);
+ result[2] = (byte)(length >>> 8);
+ result[3] = (byte) length;
+ System.arraycopy(buffer, 0, result, 4, length);
+ return result;
+ }
+
+ /**
+ * Returns the encoded form of the current message excluding the 4-byte length
+ * header.
+ *
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ public byte[] wrap() throws KeyAgreementException
+ {
+ int length = out.size();
+ if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
+ throw new KeyAgreementException("message content is too long");
+ return out.toByteArray();
+ }
+
+ /**
+ * Encodes a public key into the message.
+ * <p>
+ * When a public key is encoded into an outgoing message, the byte array of
+ * the encoded key --according to its encoding/decoding format specified when
+ * the key was first instantiated-- are put in the message (a) preceeded by
+ * one byte representing both the type of key (upper 4-bit) and the identifier
+ * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
+ * representing the total length, excluding these 4 bytes, of the bytes
+ * representing the encoded key and the one-byte representing the key-type and
+ * format; i.e.
+ * <pre>
+ * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+ * </pre>
+ *
+ * @param k the public key to encode.
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ public void writePublicKey(PublicKey k) throws KeyAgreementException
+ {
+ writeKey(k);
+ }
+
+ /**
+ * Encodes a private key into the message.
+ * <p>
+ * When a private key is encoded into an outgoing message, the byte array of
+ * the encoded key --according to its encoding/decoding format specified when
+ * the key was first instantiated-- are put in the message (a) preceeded by
+ * one byte representing both the type of key (upper 4-bit) and the identifier
+ * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity
+ * representing the total length, excluding these 4 bytes, of the bytes
+ * representing the encoded key and the one-byte representing the key-type and
+ * format; i.e.
+ * <pre>
+ * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+ * </pre>
+ *
+ * @param k the private key to encode.
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ public void writePrivateKey(PrivateKey k) throws KeyAgreementException
+ {
+ writeKey(k);
+ }
+
+ /**
+ * Encodes an MPI into the message.
+ *
+ * @param val the MPI to encode.
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ public void writeMPI(BigInteger val) throws KeyAgreementException
+ {
+ byte[] b = val.toByteArray();
+ int length = b.length;
+ if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+ throw new KeyAgreementException("MPI is too long");
+ byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+ out.write(lengthBytes, 0, 2);
+ out.write(b, 0, b.length);
+ }
+
+ /**
+ * Encodes a string into the message.
+ *
+ * @param s the string to encode.
+ * @throws KeyAgreementException if the UTF8 encoding is not supported on this
+ * platform, or if an encoding size constraint is violated.
+ */
+ public void writeString(String s) throws KeyAgreementException
+ {
+ byte[] b = null;
+ try
+ {
+ b = s.getBytes("UTF8");
+ }
+ catch (UnsupportedEncodingException x)
+ {
+ throw new KeyAgreementException("unxupported UTF8 encoding", x);
+ }
+ int length = b.length;
+ if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT)
+ throw new KeyAgreementException("text too long");
+ byte[] lengthBytes = { (byte)(length >>> 8), (byte) length };
+ out.write(lengthBytes, 0, 2);
+ out.write(b, 0, b.length);
+ }
+
+ /**
+ * @param k the key to encode.
+ * @throws KeyAgreementException if an encoding size constraint is violated.
+ */
+ private void writeKey(Key k) throws KeyAgreementException
+ {
+ byte[] b = k.getEncoded();
+ int keyType = getKeyType(k);
+ int formatID = FormatUtil.getFormatID(k.getFormat());
+ int length = b.length + 1;
+ if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT)
+ throw new KeyAgreementException("Encoded key is too long");
+ byte[] lengthBytes = {
+ (byte)(length >>> 24),
+ (byte)(length >>> 16),
+ (byte)(length >>> 8),
+ (byte) length };
+ out.write(lengthBytes, 0, 4);
+ out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F));
+ out.write(b, 0, b.length);
+ }
+
+ /**
+ * @param k the key to find an identifier for.
+ * @return an integer from <code>0</code> to <code>3</code> identifying
+ * the type of key.
+ * @throws KeyAgreementException if the designated key is of unknown or
+ * unsupported type.
+ */
+ private int getKeyType(Key k) throws KeyAgreementException
+ {
+ if (k instanceof DSSKey)
+ return 0;
+ if (k instanceof GnuRSAKey)
+ return 1;
+ if (k instanceof GnuDHKey)
+ return 2;
+ if (k instanceof SRPKey)
+ return 3;
+ throw new KeyAgreementException("Unknown or unsupported key type: "
+ + k.getClass().getName());
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java
new file mode 100644
index 000000000..8c03cbb00
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java
@@ -0,0 +1,240 @@
+/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is 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, 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; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, 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.crypto.key.dh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+import gnu.java.security.util.Util;
+
+public class DHKeyPairPKCS8Codec
+ implements IKeyPairCodec
+{
+ private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return PKCS8_FORMAT;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ throw new InvalidParameterException("Wrong format for public keys");
+ }
+
+ /**
+ * Returns the DER-encoded form of the PKCS#8 ASN.1 <i>PrivateKeyInfo</i>
+ * representation of a DH private key. The ASN.1 specification is as follows:
+ *
+ * <pre>
+ * PrivateKeyInfo ::= SEQUENCE {
+ * version INTEGER, -- MUST be 0
+ * privateKeyAlgorithm AlgorithmIdentifier,
+ * privateKey OCTET STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DhParams ::= SEQUENCE {
+ * p INTEGER, -- odd prime, p=jq +1
+ * g INTEGER, -- generator, g
+ * q INTEGER -- factor of p-1
+ * }
+ * </pre>
+ * <p>
+ * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec}
+ * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with
+ * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code>
+ * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+ * parameter, hence we replace such null values with <code>0</code>, and do
+ * the reverse in the corresponding decode method.
+ *
+ * @return the DER encoded form of the ASN.1 representation of the
+ * <i>PrivateKeyInfo</i> field in an X.509 certificate.
+ * @throw InvalidParameterException if an error occurs during the marshalling
+ * process.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ if (! (key instanceof GnuDHPrivateKey))
+ throw new InvalidParameterException("Wrong key type");
+
+ DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+ DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+ GnuDHPrivateKey pk = (GnuDHPrivateKey) key;
+ BigInteger p = pk.getParams().getP();
+ BigInteger g = pk.getParams().getG();
+ BigInteger q = pk.getQ();
+ if (q == null)
+ q = BigInteger.ZERO;
+ BigInteger x = pk.getX();
+
+ ArrayList params = new ArrayList(3);
+ params.add(new DERValue(DER.INTEGER, p));
+ params.add(new DERValue(DER.INTEGER, g));
+ params.add(new DERValue(DER.INTEGER, q));
+ DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+ ArrayList algorithmID = new ArrayList(2);
+ algorithmID.add(derOID);
+ algorithmID.add(derParams);
+ DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ algorithmID);
+
+ DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x));
+
+ ArrayList pki = new ArrayList(3);
+ pki.add(derVersion);
+ pki.add(derAlgorithmID);
+ pki.add(derPrivateKey);
+ DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
+
+ byte[] result;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ DERWriter.write(baos, derPKI);
+ result = baos.toByteArray();
+ }
+ catch (IOException e)
+ {
+ InvalidParameterException y = new InvalidParameterException();
+ y.initCause(e);
+ throw y;
+ }
+
+ return result;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public PublicKey decodePublicKey(byte[] input)
+ {
+ throw new InvalidParameterException("Wrong format for public keys");
+ }
+
+ /**
+ * @param input the byte array to unmarshall into a valid DH
+ * {@link PrivateKey} instance. MUST NOT be null.
+ * @return a new instance of a {@link GnuDHPrivateKey} decoded from the
+ * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+ * @throw InvalidParameterException if an exception occurs during the
+ * unmarshalling process.
+ */
+ public PrivateKey decodePrivateKey(byte[] input)
+ {
+ if (input == null)
+ throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+ BigInteger version, p, q, g, x;
+ DERReader der = new DERReader(input);
+ try
+ {
+ DERValue derPKI = der.read();
+ DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+ DERValue derVersion = der.read();
+ if (! (derVersion.getValue() instanceof BigInteger))
+ throw new InvalidParameterException("Wrong Version field");
+
+ version = (BigInteger) derVersion.getValue();
+ if (version.compareTo(BigInteger.ZERO) != 0)
+ throw new InvalidParameterException("Unexpected Version: " + version);
+
+ DERValue derAlgoritmID = der.read();
+ DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+ DERValue derOID = der.read();
+ OID algOID = (OID) derOID.getValue();
+ if (! algOID.equals(DH_ALG_OID))
+ throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+ DERValue derParams = der.read();
+ DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+ DERValue val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong P field");
+ p = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong G field");
+ g = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Q field");
+ q = (BigInteger) val.getValue();
+ if (q.compareTo(BigInteger.ZERO) == 0)
+ q = null;
+
+ val = der.read();
+ byte[] xBytes = (byte[]) val.getValue();
+ x = new BigInteger(1, xBytes);
+ }
+ catch (IOException e)
+ {
+ InvalidParameterException y = new InvalidParameterException();
+ y.initCause(e);
+ throw y;
+ }
+
+ return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java
new file mode 100644
index 000000000..4275389ce
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java
@@ -0,0 +1,336 @@
+/* DHKeyPairRawCodec.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with Diffie-Hellman keypairs.
+ */
+public class DHKeyPairRawCodec
+ implements IKeyPairCodec
+{
+ public int getFormatID()
+ {
+ return RAW_FORMAT;
+ }
+
+ /**
+ * Returns the encoded form of the designated Diffie-Hellman public key
+ * according to the <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DH public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>q</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not a DH one.
+ * @see Registry#MAGIC_RAW_DH_PUBLIC_KEY
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ if (! (key instanceof GnuDHPublicKey))
+ throw new IllegalArgumentException("key");
+ GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]);
+ // version
+ baos.write(0x01);
+ // q
+ byte[] buffer = dhKey.getQ().toByteArray();
+ int length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // p
+ buffer = dhKey.getParams().getP().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = dhKey.getParams().getG().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // y
+ buffer = dhKey.getY().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ return baos.toByteArray();
+ }
+
+ public PublicKey decodePublicKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[3])
+ throw new IllegalArgumentException("magic");
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // q
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger q = new BigInteger(1, buffer);
+ // p
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger p = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // y
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger y = new BigInteger(1, buffer);
+ return new GnuDHPublicKey(q, p, g, y);
+ }
+
+ /**
+ * Returns the encoded form of the designated Diffie-Hellman private key
+ * according to the <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DH private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>x</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not a DH one.
+ * @see Registry#MAGIC_RAW_DH_PRIVATE_KEY
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ if (! (key instanceof GnuDHPrivateKey))
+ throw new IllegalArgumentException("key");
+ GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]);
+ // version
+ baos.write(0x01);
+ // q
+ byte[] buffer = dhKey.getQ().toByteArray();
+ int length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // p
+ buffer = dhKey.getParams().getP().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = dhKey.getParams().getG().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // x
+ buffer = dhKey.getX().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ return baos.toByteArray();
+ }
+
+ public PrivateKey decodePrivateKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3])
+ throw new IllegalArgumentException("magic");
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // q
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger q = new BigInteger(1, buffer);
+ // p
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger p = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // x
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger x = new BigInteger(1, buffer);
+ return new GnuDHPrivateKey(q, p, g, x);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java
new file mode 100644
index 000000000..893716eef
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java
@@ -0,0 +1,255 @@
+/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is 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, 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; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, 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.crypto.key.dh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+public class DHKeyPairX509Codec
+ implements IKeyPairCodec
+{
+ private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return X509_FORMAT;
+ }
+
+ /**
+ * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i>
+ * representation of a DH public key. The ASN.1 specification, as defined in
+ * RFC-3280, and RFC-2459, is as follows:
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DhParams ::= SEQUENCE {
+ * p INTEGER, -- odd prime, p=jq +1
+ * g INTEGER, -- generator, g
+ * q INTEGER -- factor of p-1
+ * }
+ * </pre>
+ *
+ * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+ * DER-encoded form of the DH public key as an INTEGER.</p>
+ *
+ * <pre>
+ * DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+ * </pre>
+ * <p>
+ * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec}
+ * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with
+ * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code>
+ * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+ * parameter, hence we replace such null values with <code>0</code>, and do
+ * the reverse in the corresponding decode method.
+ *
+ * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+ * {@link GnuDHPublicKey}.
+ * @return the DER-encoded form of the ASN.1 representation of the
+ * <i>SubjectPublicKeyInfo</i> in an X.509 certificate.
+ * @throw InvalidParameterException if <code>key</code> is not an instance
+ * of {@link GnuDHPublicKey} or if an exception occurs during the
+ * marshalling process.
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ if (! (key instanceof GnuDHPublicKey))
+ throw new InvalidParameterException("Wrong key type");
+
+ DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+ GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+ BigInteger p = dhKey.getParams().getP();
+ BigInteger g = dhKey.getParams().getG();
+ BigInteger q = dhKey.getQ();
+ if (q == null)
+ q = BigInteger.ZERO;
+ BigInteger y = dhKey.getY();
+
+ DERValue derP = new DERValue(DER.INTEGER, p);
+ DERValue derG = new DERValue(DER.INTEGER, g);
+ DERValue derQ = new DERValue(DER.INTEGER, q);
+
+ ArrayList params = new ArrayList(3);
+ params.add(derP);
+ params.add(derG);
+ params.add(derQ);
+ DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+ ArrayList algorithmID = new ArrayList(2);
+ algorithmID.add(derOID);
+ algorithmID.add(derParams);
+ DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ algorithmID);
+
+ DERValue derDHPublicKey = new DERValue(DER.INTEGER, y);
+ byte[] yBytes = derDHPublicKey.getEncoded();
+ DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
+
+ ArrayList spki = new ArrayList(2);
+ spki.add(derAlgorithmID);
+ spki.add(derSPK);
+ DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
+
+ byte[] result;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ DERWriter.write(baos, derSPKI);
+ result = baos.toByteArray();
+ }
+ catch (IOException x)
+ {
+ InvalidParameterException e = new InvalidParameterException();
+ e.initCause(x);
+ throw e;
+ }
+
+ return result;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ throw new InvalidParameterException("Wrong format for private keys");
+ }
+
+ /**
+ * @param input the byte array to unmarshall into a valid DH
+ * {@link PublicKey} instance. MUST NOT be null.
+ * @return a new instance of a {@link GnuDHPublicKey} decoded from the
+ * <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
+ * @throw InvalidParameterException if an exception occurs during the
+ * unmarshalling process.
+ */
+ public PublicKey decodePublicKey(byte[] input)
+ {
+ if (input == null)
+ throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+ BigInteger p, g, q, y;
+ DERReader der = new DERReader(input);
+ try
+ {
+ DERValue derSPKI = der.read();
+ DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+ DERValue derAlgorithmID = der.read();
+ DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
+
+ DERValue derOID = der.read();
+ if (! (derOID.getValue() instanceof OID))
+ throw new InvalidParameterException("Wrong Algorithm field");
+
+ OID algOID = (OID) derOID.getValue();
+ if (! algOID.equals(DH_ALG_OID))
+ throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+ DERValue derParams = der.read();
+ DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field");
+
+ DERValue val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong P field");
+ p = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong G field");
+ g = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Q field");
+ q = (BigInteger) val.getValue();
+ if (q.compareTo(BigInteger.ZERO) == 0)
+ q = null;
+
+ val = der.read();
+ if (! (val.getValue() instanceof BitString))
+ throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+ byte[] yBytes = ((BitString) val.getValue()).toByteArray();
+
+ DERReader dhPub = new DERReader(yBytes);
+ val = dhPub.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Y field");
+ y = (BigInteger) val.getValue();
+ }
+ catch (IOException x)
+ {
+ InvalidParameterException e = new InvalidParameterException();
+ e.initCause(x);
+ throw e;
+ }
+
+ return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y);
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public PrivateKey decodePrivateKey(byte[] input)
+ {
+ throw new InvalidParameterException("Wrong format for private keys");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java
new file mode 100644
index 000000000..893d84d32
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java
@@ -0,0 +1,119 @@
+/* DiffieHellmanKeyAgreement.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * The basic version of the Diffie-Hellman key agreement is described in the
+ * Handbook of Applied Cryptography [HAC] as follows:
+ * <ul>
+ * <li>An appropriate prime p and generator g of Z<sub>p</sub><sup>*</sup>
+ * (2 &lt;= g &lt;= p-2) are selected and published.</li>
+ * <li>A and B each send the other one message over an open channel; as a
+ * result, they both can then compute a shared secret key K which they can use
+ * to protect their future communication.</li>
+ * <li>A chooses a random secret x, 1 &lt;= x &lt;= p-2, and sends B message
+ * (1) which is g^x mod p.</li>
+ * <li>B chooses a random secret y, 1 &lt;= y &lt;= p-2, and sends A message
+ * (2) which is g^y mod p.</li>
+ * <li>B receives message (1) and computes the shared key as K = (g^x)^y mod p.
+ * </li>
+ * <li>A receives message (2) and computes the shared key as K = (g^y)^x mod p.
+ * </li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes a <i>Static-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ * &quot;In Static-Static mode, both the sender and the recipient have a
+ * static (and certified) key pair. Since the sender's and recipient's
+ * keys are therefore the same for each message, ZZ will be the same for
+ * each message. Thus, partyAInfo MUST be used (and different for each
+ * message) in order to ensure that different messages use different
+ * KEKs. Implementations MAY implement Static-Static mode.&quot;
+ * </pre>
+ *
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public abstract class DiffieHellmanKeyAgreement
+ extends BaseKeyAgreementParty
+{
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.ka.prng";
+ public static final String KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY =
+ "gnu.crypto.dh.ka.owner.private.key";
+ /** The key agreement party's private key. */
+ protected DHPrivateKey ownerKey;
+ /** The shared secret key. */
+ protected BigInteger ZZ;
+
+ protected DiffieHellmanKeyAgreement()
+ {
+ super(Registry.DH_KA);
+ }
+
+ protected byte[] engineSharedSecret() throws KeyAgreementException
+ {
+ return Util.trim(ZZ);
+ }
+
+ protected void engineReset()
+ {
+ ownerKey = null;
+ ZZ = null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java
new file mode 100644
index 000000000..3194f682d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java
@@ -0,0 +1,117 @@
+/* DiffieHellmanReceiver.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.prng.IRandom;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the receiver's part of the basic version of the
+ * Diffie-Hellman key agreement exchange (B in [HAC]).
+ *
+ * @see DiffieHellmanKeyAgreement
+ */
+public class DiffieHellmanReceiver
+ extends DiffieHellmanKeyAgreement
+{
+ private BigInteger y; // the receiver's random secret
+
+ // default 0-arguments constructor
+
+ protected void engineInit(Map attributes) throws KeyAgreementException
+ {
+ Object random = attributes.get(SOURCE_OF_RANDOMNESS);
+ rnd = null;
+ irnd = null;
+ if (random instanceof SecureRandom)
+ rnd = (SecureRandom) random;
+ else if (random instanceof IRandom)
+ irnd = (IRandom) random;
+ ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY);
+ if (ownerKey == null)
+ throw new KeyAgreementException("missing owner's private key");
+ }
+
+ protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ private OutgoingMessage computeSharedSecret(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ BigInteger m1 = in.readMPI();
+ if (m1 == null)
+ throw new KeyAgreementException("missing message (1)");
+ BigInteger p = ownerKey.getParams().getP();
+ BigInteger g = ownerKey.getParams().getG();
+ // B chooses a random integer y, 1 <= y <= p-2
+ // rfc-2631 restricts y to only be in [2, p-1]
+ BigInteger p_minus_2 = p.subtract(TWO);
+ byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+ do
+ {
+ nextRandomBytes(xBytes);
+ y = new BigInteger(1, xBytes);
+ }
+ while (! (y.compareTo(TWO) >= 0 && y.compareTo(p_minus_2) <= 0));
+ ZZ = m1.modPow(y, p); // ZZ = (yb ^ xa) mod p
+ complete = true;
+ // B sends A the message: g^y mod p
+ OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(g.modPow(y, p)); // message (2)
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java
new file mode 100644
index 000000000..7fc997354
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java
@@ -0,0 +1,126 @@
+/* DiffieHellmanSender.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.prng.IRandom;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the sender's part of the basic version of the
+ * Diffie-Hellman key agreement exchange (A in [HAC]).
+ *
+ * @see DiffieHellmanKeyAgreement
+ */
+public class DiffieHellmanSender
+ extends DiffieHellmanKeyAgreement
+{
+ private BigInteger x; // the sender's random secret
+
+ // default 0-arguments constructor
+
+ protected void engineInit(Map attributes) throws KeyAgreementException
+ {
+ Object random = attributes.get(SOURCE_OF_RANDOMNESS);
+ rnd = null;
+ irnd = null;
+ if (random instanceof SecureRandom)
+ rnd = (SecureRandom) random;
+ else if (random instanceof IRandom)
+ irnd = (IRandom) random;
+ ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY);
+ if (ownerKey == null)
+ throw new KeyAgreementException("missing owner's private key");
+ }
+
+ protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return sendRandomSecret(in);
+ case 1:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ private OutgoingMessage sendRandomSecret(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ BigInteger p = ownerKey.getParams().getP();
+ BigInteger g = ownerKey.getParams().getG();
+ // A chooses a random integer x, 1 <= x <= p-2
+ // rfc-2631 restricts x to only be in [2, p-1]
+ BigInteger p_minus_2 = p.subtract(TWO);
+ byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+ do
+ {
+ nextRandomBytes(xBytes);
+ x = new BigInteger(1, xBytes);
+ }
+ while (! (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0));
+ // A sends B the message: g^x mod p
+ OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(g.modPow(x, p));
+ return result;
+ }
+
+ private OutgoingMessage computeSharedSecret(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ BigInteger m1 = in.readMPI();
+ if (m1 == null)
+ throw new KeyAgreementException("missing message (2)");
+ BigInteger p = ownerKey.getParams().getP();
+ ZZ = m1.modPow(x, p); // ZZ = (yb ^ xa) mod p
+ complete = true;
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java
new file mode 100644
index 000000000..4283dc59b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java
@@ -0,0 +1,115 @@
+/* ElGamalKeyAgreement.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+
+import java.math.BigInteger;
+
+/**
+ * The ElGamal key agreement, also known as the half-certified Diffie-Hellman
+ * key agreement, is described in the Handbook of Applied Cryptography [HAC] as
+ * follows:
+ * <ul>
+ * <li>A sends to B a single message allowing one-pass key agreement.</li>
+ * <li>A obtains an authentic copy of B's public key (p, g, yb), where yb =
+ * g**xb.</li>
+ * <li>A chooses a random integer x, 1 &lt;= x &lt;= p-2, and sends B the
+ * message g**x. A computes the shared secret key K as yb**x.</li>
+ * <li>B computes the same key K on receipt of the previous message as
+ * (g**x)**xb.</li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes an <i>Ephemeral-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ * &quot;In Ephemeral-Static mode, the recipient has a static (and certified)
+ * key pair, but the sender generates a new key pair for each message
+ * and sends it using the originatorKey production. If the sender's key
+ * is freshly generated for each message, the shared secret ZZ will be
+ * similarly different for each message and partyAInfo MAY be omitted,
+ * since it serves merely to decouple multiple KEKs generated by the
+ * same set of pairwise keys. If, however, the same ephemeral sender key
+ * is used for multiple messages (e.g. it is cached as a performance
+ * optimization) then a separate partyAInfo MUST be used for each
+ * message. All implementations of this standard MUST implement
+ * Ephemeral-Static mode.&quot;
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+public abstract class ElGamalKeyAgreement
+ extends BaseKeyAgreementParty
+{
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.elgamal.ka.prng";
+ public static final String KA_ELGAMAL_RECIPIENT_PRIVATE_KEY =
+ "gnu.crypto.elgamal.ka.recipient.private.key";
+ public static final String KA_ELGAMAL_RECIPIENT_PUBLIC_KEY =
+ "gnu.crypto.elgamal.ka.recipient.public.key";
+ /** The shared secret key. */
+ protected BigInteger ZZ;
+
+ protected ElGamalKeyAgreement()
+ {
+ super(Registry.ELGAMAL_KA);
+ }
+
+ protected byte[] engineSharedSecret() throws KeyAgreementException
+ {
+ return Util.trim(ZZ);
+ }
+
+ protected void engineReset()
+ {
+ ZZ = null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java
new file mode 100644
index 000000000..ad606f6c9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java
@@ -0,0 +1,99 @@
+/* ElGamalReceiver.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * This implementation is the receiver's part of the ElGamal key agreement
+ * exchange (B in [HAC]).
+ *
+ * @see ElGamalKeyAgreement
+ */
+public class ElGamalReceiver
+ extends ElGamalKeyAgreement
+{
+ /** The recipient's private key. */
+ private DHPrivateKey B;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ // One-time setup (key generation and publication). Each user B generates
+ // a keypair and publishes its public key
+ B = (DHPrivateKey) attributes.get(KA_ELGAMAL_RECIPIENT_PRIVATE_KEY);
+ if (B == null)
+ throw new KeyAgreementException("missing recipient private key");
+ }
+
+ protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ private OutgoingMessage computeSharedSecret(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ // (b) B computes the same key on receipt of message (1) as
+ // K = (g^x)^xb mod p
+ BigInteger m1 = in.readMPI();
+ if (m1 == null)
+ throw new KeyAgreementException("missing message (1)");
+ ZZ = m1.modPow(B.getX(), B.getParams().getP()); // ZZ = (ya ^ xb) mod p
+ complete = true;
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java
new file mode 100644
index 000000000..bc9643500
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java
@@ -0,0 +1,112 @@
+/* ElGamalSender.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+/**
+ * This implementation is the sender's part of the ElGamal key agreement
+ * exchange (A in [HAC]).
+ *
+ * @see ElGamalKeyAgreement
+ */
+public class ElGamalSender
+ extends ElGamalKeyAgreement
+{
+ /** The recipient's public key. */
+ private DHPublicKey B;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ // One-time setup (key generation and publication). Each user B generates
+ // a keypair and publishes its public key
+ B = (DHPublicKey) attributes.get(KA_ELGAMAL_RECIPIENT_PUBLIC_KEY);
+ if (B == null)
+ throw new KeyAgreementException("missing recipient public key");
+ }
+
+ protected OutgoingMessage engineProcessMessage(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ private OutgoingMessage computeSharedSecret(IncomingMessage in)
+ throws KeyAgreementException
+ {
+ BigInteger p = B.getParams().getP();
+ BigInteger g = B.getParams().getG();
+ BigInteger yb = B.getY();
+ // A chooses a random integer x, 1 <= x <= p-2
+ // rfc-2631 restricts x to only be in [2, p-1]
+ BigInteger p_minus_2 = p.subtract(TWO);
+ byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8];
+ BigInteger x;
+ do
+ {
+ nextRandomBytes(xBytes);
+ x = new BigInteger(1, xBytes);
+ }
+ while (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0);
+ // A sends B the message: g^x mod p
+ OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(g.modPow(x, p));
+ // A computes the key as K = (yb)^x mod p
+ ZZ = yb.modPow(x, p); // ZZ = (yb ^ xa) mod p
+ complete = true;
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java
new file mode 100644
index 000000000..03a18c310
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java
@@ -0,0 +1,174 @@
+/* GnuDHKey.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.util.FormatUtil;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Key;
+
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * A base asbtract class for both public and private Diffie-Hellman keys. It
+ * encapsulates the two DH numbers: <code>p</code>, and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, and basically
+ * consists of the raw byte sequences of algorithm parameters. The exact order
+ * of the byte sequences and the implementation details are given in each of the
+ * relevant <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public abstract class GnuDHKey
+ implements Key, DHKey
+{
+ /** The public prime q. A prime divisor of p-1. */
+ protected BigInteger q;
+ /** The public prime p. */
+ protected BigInteger p;
+ /** The generator g. */
+ protected BigInteger g;
+ /**
+ * Identifier of the default encoding format to use when externalizing the key
+ * material.
+ */
+ protected final int defaultFormat;
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Trivial protected constructor.
+ *
+ * @param defaultFormat the identifier of the encoding format to use by
+ * default when externalizing the key.
+ * @param q a prime divisor of p-1.
+ * @param p the public prime.
+ * @param g the generator of the group.
+ */
+ protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g)
+ {
+ super();
+
+ this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+ : defaultFormat;
+ this.q = q;
+ this.p = p;
+ this.g = g;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ if (q == null)
+ return new DHParameterSpec(p, g);
+ return new DHParameterSpec(p, g, q.bitLength());
+ }
+
+ public String getAlgorithm()
+ {
+ return Registry.DH_KPG;
+ }
+
+ /** @deprecated see getEncoded(int). */
+ public byte[] getEncoded()
+ {
+ return getEncoded(defaultFormat);
+ }
+
+ public String getFormat()
+ {
+ return FormatUtil.getEncodingShortName(defaultFormat);
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DHKey} and has the same Diffie-Hellman parameter values as this one.
+ *
+ * @param obj the other non-null DH key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+ if (! (obj instanceof DHKey))
+ return false;
+ DHKey that = (DHKey) obj;
+ return p.equals(that.getParams().getP())
+ && g.equals(that.getParams().getG());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged
+ (new GetPropertyAction("line.separator"));
+ StringBuilder sb = new StringBuilder(ls)
+ .append("defaultFormat=").append(defaultFormat).append(",").append(ls);
+ if (q == null)
+ sb.append("q=null,");
+ else
+ sb.append("q=0x").append(q.toString(16)).append(",");
+ sb.append(ls).append("p=0x").append(p.toString(16)).append(",").append(ls)
+ .append("g=0x").append(g.toString(16));
+ str = sb.toString();
+ }
+ return str;
+ }
+
+ public abstract byte[] getEncoded(int format);
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java
new file mode 100644
index 000000000..89e9c4c80
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java
@@ -0,0 +1,235 @@
+/* GnuDHKeyPairGenerator.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * An implementation of a Diffie-Hellman keypair generator.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHKeyPairGenerator
+ implements IKeyPairGenerator
+{
+ private static final Logger log = Logger.getLogger(GnuDHKeyPairGenerator.class.getName());
+ /**
+ * Property name of an optional {@link SecureRandom} instance to use. The
+ * default is to use a classloader singleton from {@link PRNG}.
+ */
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng";
+ /**
+ * Property name of an optional {@link DHGenParameterSpec} or
+ * {@link DHParameterSpec} instance to use for this generator.
+ */
+ public static final String DH_PARAMETERS = "gnu.crypto.dh.params";
+ /** Property name of the size in bits (Integer) of the public prime (p). */
+ public static final String PRIME_SIZE = "gnu.crypto.dh.L";
+ /** Property name of the size in bits (Integer) of the private exponent (x). */
+ public static final String EXPONENT_SIZE = "gnu.crypto.dh.m";
+ /**
+ * Property name of the preferred encoding format to use when externalizing
+ * generated instance of key-pairs from this generator. The property is taken
+ * to be an {@link Integer} that encapsulates an encoding format identifier.
+ */
+ public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding";
+ /** Default value for the size in bits of the public prime (p). */
+ public static final int DEFAULT_PRIME_SIZE = 512;
+ /** Default value for the size in bits of the private exponent (x). */
+ public static final int DEFAULT_EXPONENT_SIZE = 160;
+ /** Default encoding format to use when none was specified. */
+ private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+ /** The SHA instance to use. */
+ private Sha160 sha = new Sha160();
+ /** The optional {@link SecureRandom} instance to use. */
+ private SecureRandom rnd = null;
+ /** The desired size in bits of the public prime (p). */
+ private int l;
+ /** The desired size in bits of the private exponent (x). */
+ private int m;
+ private BigInteger seed;
+ private BigInteger counter;
+ private BigInteger q;
+ private BigInteger p;
+ private BigInteger j;
+ private BigInteger g;
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+ /** Preferred encoding format of generated keys. */
+ private int preferredFormat;
+
+ // default 0-arguments constructor
+
+ public String name()
+ {
+ return Registry.DH_KPG;
+ }
+
+ public void setup(Map attributes)
+ {
+ // do we have a SecureRandom, or should we use our own?
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ // are we given a set of Diffie-Hellman generation parameters or we shall
+ // use our own?
+ Object params = attributes.get(DH_PARAMETERS);
+ // find out the desired sizes
+ if (params instanceof DHGenParameterSpec)
+ {
+ DHGenParameterSpec jceSpec = (DHGenParameterSpec) params;
+ l = jceSpec.getPrimeSize();
+ m = jceSpec.getExponentSize();
+ }
+ else if (params instanceof DHParameterSpec)
+ {
+ // FIXME: I'm not sure this is correct. It seems to behave the
+ // same way as Sun's RI, but I don't know if this behavior is
+ // documented anywhere.
+ DHParameterSpec jceSpec = (DHParameterSpec) params;
+ p = jceSpec.getP();
+ g = jceSpec.getG();
+ l = p.bitLength();
+ m = jceSpec.getL();
+ // If no exponent size was given, generate an exponent as
+ // large as the prime.
+ if (m == 0)
+ m = l;
+ }
+ else
+ {
+ Integer bi = (Integer) attributes.get(PRIME_SIZE);
+ l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue());
+ bi = (Integer) attributes.get(EXPONENT_SIZE);
+ m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue());
+ }
+ if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE)
+ throw new IllegalArgumentException("invalid modulus size");
+ if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE)
+ throw new IllegalArgumentException("invalid exponent size");
+ if (m > l)
+ throw new IllegalArgumentException("exponent size > modulus size");
+ // what is the preferred encoding format
+ Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+ preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+ : formatID.intValue();
+ }
+
+ public KeyPair generate()
+ {
+ if (p == null)
+ {
+ BigInteger[] params = new RFC2631(m, l, rnd).generateParameters();
+ seed = params[RFC2631.DH_PARAMS_SEED];
+ counter = params[RFC2631.DH_PARAMS_COUNTER];
+ q = params[RFC2631.DH_PARAMS_Q];
+ p = params[RFC2631.DH_PARAMS_P];
+ j = params[RFC2631.DH_PARAMS_J];
+ g = params[RFC2631.DH_PARAMS_G];
+ if (Configuration.DEBUG)
+ {
+ log.fine("seed: 0x" + seed.toString(16));
+ log.fine("counter: " + counter.intValue());
+ log.fine("q: 0x" + q.toString(16));
+ log.fine("p: 0x" + p.toString(16));
+ log.fine("j: 0x" + j.toString(16));
+ log.fine("g: 0x" + g.toString(16));
+ }
+ }
+ // generate a private number x of length m such as: 1 < x < q - 1
+ BigInteger q_minus_1 = null;
+ if (q != null)
+ q_minus_1 = q.subtract(BigInteger.ONE);
+ // We already check if m is modulo 8 in `setup.' This could just
+ // be m >>> 3.
+ byte[] mag = new byte[(m + 7) / 8];
+ BigInteger x;
+ while (true)
+ {
+ nextRandomBytes(mag);
+ x = new BigInteger(1, mag);
+ if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0
+ && (q_minus_1 == null || x.compareTo(q_minus_1) < 0))
+ break;
+ }
+ BigInteger y = g.modPow(x, p);
+ PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x);
+ PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y);
+ return new KeyPair(pubK, secK);
+ }
+
+ /**
+ * Fills the designated byte array with random data.
+ *
+ * @param buffer the byte array to fill with random data.
+ */
+ private void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java
new file mode 100644
index 000000000..881421a74
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java
@@ -0,0 +1,200 @@
+/* GnuDHPrivateKey.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+
+import javax.crypto.interfaces.DHPrivateKey;
+
+/**
+ * An implementation of the Diffie-Hellman private key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHPrivateKey
+ extends GnuDHKey
+ implements DHPrivateKey
+{
+ /** The private exponent. */
+ private final BigInteger x;
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Convenience constructor. Calls the constructor with five arguments passing
+ * {@link Registry#RAW_ENCODING_ID} as the value of its first argument.
+ *
+ * @param q a prime divisor of p-1.
+ * @param p the public prime.
+ * @param g the generator of the group.
+ * @param x the private value x.
+ */
+ public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x)
+ {
+ this(Registry.RAW_ENCODING_ID, q, p, g, x);
+ }
+
+ /**
+ * Constructs a new instance of <code>GnuDHPrivateKey</code> given the
+ * designated parameters.
+ *
+ * @param preferredFormat the identifier of the encoding format to use by
+ * default when externalizing the key.
+ * @param q a prime divisor of p-1.
+ * @param p the public prime.
+ * @param g the generator of the group.
+ * @param x the private value x.
+ */
+ public GnuDHPrivateKey(int preferredFormat, BigInteger q, BigInteger p,
+ BigInteger g, BigInteger x)
+ {
+ super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+ : preferredFormat,
+ q, p, g);
+ this.x = x;
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePrivateKey()</code>
+ * method of a DH keypair codec object (an instance implementing
+ * {@link IKeyPairCodec} for DH keys, and re-constructs an instance of this
+ * object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an
+ * instance of this object.
+ * @exception IllegalArgumentException if the byte sequence does not represent
+ * a valid encoding of an instance of this object.
+ */
+ public static GnuDHPrivateKey valueOf(byte[] k)
+ {
+ // try RAW codec
+ if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0])
+ try
+ {
+ return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k);
+ }
+ catch (IllegalArgumentException ignored)
+ {
+ }
+ // try PKCS#8 codec
+ return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k);
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ /**
+ * Returns the encoded form of this private key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @exception IllegalArgumentException if the format is not supported.
+ * @see DHKeyPairRawCodec
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new DHKeyPairRawCodec().encodePrivateKey(this);
+ break;
+ case IKeyPairCodec.PKCS8_FORMAT:
+ result = new DHKeyPairPKCS8Codec().encodePrivateKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported encoding format: "
+ + format);
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DHPrivateKey} and has the same parameter values as this one.
+ *
+ * @param obj the other non-null DH key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (! (obj instanceof DHPrivateKey))
+ return false;
+
+ DHPrivateKey that = (DHPrivateKey) obj;
+ return super.equals(that) && x.equals(that.getX());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged
+ (new GetPropertyAction("line.separator"));
+ str = new StringBuilder(this.getClass().getName()).append("(")
+ .append(super.toString()).append(",").append(ls)
+ .append("x=0x").append(Configuration.DEBUG ? x.toString(16)
+ : "**...*").append(ls)
+ .append(")")
+ .toString();
+ }
+ return str;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java
new file mode 100644
index 000000000..5f1771bb0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java
@@ -0,0 +1,196 @@
+/* GnuDHPublicKey.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+/**
+ * An implementation of the Diffie-Hellman public key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class GnuDHPublicKey
+ extends GnuDHKey
+ implements DHPublicKey
+{
+ private BigInteger y;
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Convenience constructor. Calls the constructor with five arguments passing
+ * {@link Registry#RAW_ENCODING_ID} as the value of its first argument.
+ *
+ * @param q a prime divisor of p-1.
+ * @param p the public prime.
+ * @param g the generator of the group.
+ * @param y the public value y.
+ */
+ public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y)
+ {
+ this(Registry.RAW_ENCODING_ID, q, p, g, y);
+ }
+
+ /**
+ * Constructs a new instance of <code>GnuDHPublicKey</code> given the
+ * designated parameters.
+ *
+ * @param preferredFormat the identifier of the encoding format to use by
+ * default when externalizing the key.
+ * @param q a prime divisor of p-1.
+ * @param p the public prime.
+ * @param g the generator of the group.
+ * @param y the public value y.
+ */
+ public GnuDHPublicKey(int preferredFormat, BigInteger q, BigInteger p,
+ BigInteger g, BigInteger y)
+ {
+ super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+ : preferredFormat,
+ q, p, g);
+ this.y = y;
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePublicKey()</code>
+ * method of a DH keypair codec object (an instance implementing
+ * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this
+ * object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an
+ * instance of this object.
+ * @exception IllegalArgumentException if the byte sequence does not represent
+ * a valid encoding of an instance of this object.
+ */
+ public static GnuDHPublicKey valueOf(byte[] k)
+ {
+ // try RAW codec
+ if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0])
+ try
+ {
+ return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k);
+ }
+ catch (IllegalArgumentException ignored)
+ {
+ }
+ // try X.509 codec
+ return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k);
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ /**
+ * Returns the encoded form of this public key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @exception IllegalArgumentException if the format is not supported.
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new DHKeyPairRawCodec().encodePublicKey(this);
+ break;
+ case IKeyPairCodec.X509_FORMAT:
+ result = new DHKeyPairX509Codec().encodePublicKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported encoding format: "
+ + format);
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DHPublicKey} and has the same parameter values as this one.
+ *
+ * @param obj the other non-null DH key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (! (obj instanceof DHPublicKey))
+ return false;
+
+ DHPublicKey that = (DHPublicKey) obj;
+ return super.equals(that) && y.equals(that.getY());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged
+ (new GetPropertyAction("line.separator"));
+ str = new StringBuilder(this.getClass().getName()).append("(")
+ .append(super.toString()).append(",").append(ls)
+ .append("y=0x").append(y.toString(16)).append(ls)
+ .append(")")
+ .toString();
+ }
+ return str;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java
new file mode 100644
index 000000000..60ef49409
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java
@@ -0,0 +1,217 @@
+/* RFC2631.java --
+ Copyright (C) 2003, 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.crypto.key.dh;
+
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * An implementation of the Diffie-Hellman parameter generation as defined in
+ * RFC-2631.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+public class RFC2631
+{
+ public static final int DH_PARAMS_SEED = 0;
+ public static final int DH_PARAMS_COUNTER = 1;
+ public static final int DH_PARAMS_Q = 2;
+ public static final int DH_PARAMS_P = 3;
+ public static final int DH_PARAMS_J = 4;
+ public static final int DH_PARAMS_G = 5;
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+ /** The SHA instance to use. */
+ private Sha160 sha = new Sha160();
+ /** Length of private modulus and of q. */
+ private int m;
+ /** Length of public modulus p. */
+ private int L;
+ /** The optional {@link SecureRandom} instance to use. */
+ private SecureRandom rnd = null;
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ public RFC2631(int m, int L, SecureRandom rnd)
+ {
+ super();
+
+ this.m = m;
+ this.L = L;
+ this.rnd = rnd;
+ }
+
+ public BigInteger[] generateParameters()
+ {
+ int i, j, counter;
+ byte[] u1, u2, v;
+ byte[] seedBytes = new byte[m / 8];
+ BigInteger SEED, U, q, R, V, W, X, p, g;
+ // start by genrating p and q, where q is of length m and p is of length L
+ // 1. Set m' = m/160 where / represents integer division with rounding
+ // upwards. I.e. 200/160 = 2.
+ int m_ = (m + 159) / 160;
+ // 2. Set L'= L/160
+ int L_ = (L + 159) / 160;
+ // 3. Set N'= L/1024
+ int N_ = (L + 1023) / 1024;
+ algorithm: while (true)
+ {
+ step4: while (true)
+ {
+ // 4. Select an arbitrary bit string SEED such that length of
+ // SEED >= m
+ nextRandomBytes(seedBytes);
+ SEED = new BigInteger(1, seedBytes).setBit(m - 1).setBit(0);
+ // 5. Set U = 0
+ U = BigInteger.ZERO;
+ // 6. For i = 0 to m' - 1
+ // U = U + (SHA1[SEED + i] XOR SHA1[(SEED + m' + i)) * 2^(160 * i)
+ // Note that for m=160, this reduces to the algorithm of FIPS-186
+ // U = SHA1[SEED] XOR SHA1[(SEED+1) mod 2^160 ].
+ for (i = 0; i < m_; i++)
+ {
+ u1 = SEED.add(BigInteger.valueOf(i)).toByteArray();
+ u2 = SEED.add(BigInteger.valueOf(m_ + i)).toByteArray();
+ sha.update(u1, 0, u1.length);
+ u1 = sha.digest();
+ sha.update(u2, 0, u2.length);
+ u2 = sha.digest();
+ for (j = 0; j < u1.length; j++)
+ u1[j] ^= u2[j];
+ U = U.add(new BigInteger(1, u1).multiply(TWO.pow(160 * i)));
+ }
+ // 5. Form q from U by computing U mod (2^m) and setting the most
+ // significant bit (the 2^(m-1) bit) and the least significant
+ // bit to 1. In terms of boolean operations, q = U OR 2^(m-1) OR
+ // 1. Note that 2^(m-1) < q < 2^m
+ q = U.setBit(m - 1).setBit(0);
+ // 6. Use a robust primality algorithm to test whether q is prime.
+ // 7. If q is not prime then go to 4.
+ if (q.isProbablePrime(80))
+ break step4;
+ }
+ // 8. Let counter = 0
+ counter = 0;
+ while (true)
+ {
+ // 9. Set R = seed + 2*m' + (L' * counter)
+ R = SEED
+ .add(BigInteger.valueOf(2 * m_))
+ .add(BigInteger.valueOf(L_ * counter));
+ // 10. Set V = 0
+ V = BigInteger.ZERO;
+ // 12. For i = 0 to L'-1 do: V = V + SHA1(R + i) * 2^(160 * i)
+ for (i = 0; i < L_; i++)
+ {
+ v = R.toByteArray();
+ sha.update(v, 0, v.length);
+ v = sha.digest();
+ V = V.add(new BigInteger(1, v).multiply(TWO.pow(160 * i)));
+ }
+ // 13. Set W = V mod 2^L
+ W = V.mod(TWO.pow(L));
+ // 14. Set X = W OR 2^(L-1)
+ // Note that 0 <= W < 2^(L-1) and hence X >= 2^(L-1)
+ X = W.setBit(L - 1);
+ // 15. Set p = X - (X mod (2*q)) + 1
+ p = X.add(BigInteger.ONE).subtract(X.mod(TWO.multiply(q)));
+ // 16. If p > 2^(L-1) use a robust primality test to test whether p
+ // is prime. Else go to 18.
+ // 17. If p is prime output p, q, seed, counter and stop.
+ if (p.isProbablePrime(80))
+ {
+ break algorithm;
+ }
+ // 18. Set counter = counter + 1
+ counter++;
+ // 19. If counter < (4096 * N) then go to 8.
+ // 20. Output "failure"
+ if (counter >= 4096 * N_)
+ continue algorithm;
+ }
+ }
+ // compute g. from FIPS-186, Appendix 4:
+ // 1. Generate p and q as specified in Appendix 2.
+ // 2. Let e = (p - 1) / q
+ BigInteger e = p.subtract(BigInteger.ONE).divide(q);
+ BigInteger h = TWO;
+ BigInteger p_minus_1 = p.subtract(BigInteger.ONE);
+ g = TWO;
+ // 3. Set h = any integer, where 1 < h < p - 1 and h differs from any
+ // value previously tried
+ for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE))
+ {
+ // 4. Set g = h**e mod p
+ g = h.modPow(e, p);
+ // 5. If g = 1, go to step 3
+ if (! g.equals(BigInteger.ONE))
+ break;
+ }
+ return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g };
+ }
+
+ /**
+ * Fills the designated byte array with random data.
+ *
+ * @param buffer the byte array to fill with random data.
+ */
+ private void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java
new file mode 100644
index 000000000..2c8e66fa2
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java
@@ -0,0 +1,161 @@
+/* SRP6Host.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the Host in the SRP-6 key agreement protocol.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6Host
+ extends SRP6KeyAgreement
+{
+ /** The user's ephemeral key pair. */
+ private KeyPair hostKeyPair;
+
+ /** The SRP password database. */
+ private SRPAuthInfoProvider passwordDB;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(final Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ N = (BigInteger) attributes.get(SHARED_MODULUS);
+ if (N == null)
+ throw new KeyAgreementException("missing shared modulus");
+ g = (BigInteger) attributes.get(GENERATOR);
+ if (g == null)
+ throw new KeyAgreementException("missing generator");
+ final String md = (String) attributes.get(HASH_FUNCTION);
+ if (md == null || md.trim().length() == 0)
+ throw new KeyAgreementException("missing hash function");
+ srp = SRP.instance(md);
+ passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB);
+ if (passwordDB == null)
+ throw new KeyAgreementException("missing SRP password database");
+ }
+
+ protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ protected void engineReset()
+ {
+ hostKeyPair = null;
+ super.engineReset();
+ }
+
+ private OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final String I = in.readString();
+ final BigInteger A = in.readMPI();
+ // get s and v for user identified by I
+ // ----------------------------------------------------------------------
+ final Map credentials;
+ try
+ {
+ final Map userID = new HashMap();
+ userID.put(Registry.SASL_USERNAME, I);
+ userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm());
+ credentials = passwordDB.lookup(userID);
+ }
+ catch (IOException x)
+ {
+ throw new KeyAgreementException("computeSharedSecret()", x);
+ }
+ final BigInteger s = new BigInteger(
+ 1,Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD)));
+ final BigInteger v = new BigInteger(
+ 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD)));
+ final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+ final Map attributes = new HashMap();
+ if (rnd != null)
+ attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+ attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+ attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+ attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+ kpg.setup(attributes);
+ hostKeyPair = kpg.generate();
+ final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+ final BigInteger u = uValue(A, B); // u = H(A | B)
+ // compute S = (Av^u) ^ b
+ final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX();
+ final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N);
+ final byte[] sBytes = Util.trim(S);
+ final IMessageDigest hash = srp.newDigest();
+ hash.update(sBytes, 0, sBytes.length);
+ K = new BigInteger(1, hash.digest());
+ final OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(s);
+ result.writeMPI(B);
+ complete = true;
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java
new file mode 100644
index 000000000..d3d27b381
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java
@@ -0,0 +1,141 @@
+/* SRP6KeyAgreement.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.BaseKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+
+/**
+ * The Secure Remote Password (SRP) key agreement protocol, also known as SRP-6,
+ * is designed by Thomas J. Wu (see references). The protocol, and its elements
+ * are described as follows:
+ * <pre>
+ * N A large safe prime (N = 2q+1, where q is prime)
+ * All arithmetic is done modulo N.
+ * g A generator modulo N
+ * s User's salt
+ * I Username
+ * p Cleartext Password
+ * H() One-way hash function
+ * &circ; (Modular) Exponentiation
+ * u Random scrambling parameter
+ * a,b Secret ephemeral values
+ * A,B Public ephemeral values
+ * x Private key (derived from p and s)
+ * v Password verifier
+ *
+ * The host stores passwords using the following formula:
+ * x = H(s | H(I &quot;:&quot; p)) (s is chosen randomly)
+ * v = g&circ;x (computes password verifier)
+ *
+ * The host then keeps {I, s, v} in its password database.
+ *
+ * The authentication protocol itself goes as follows:
+ * User -&gt; Host: I, A = g&circ;a (identifies self, a = random number)
+ * Host -&gt; User: s, B = 3v + g&circ;b (sends salt, b = random number)
+ *
+ * Both: u = H(A, B)
+ *
+ * User: x = H(s, p) (user enters password)
+ * User: S = (B - 3g&circ;x) &circ; (a + ux) (computes session key)
+ * User: K = H(S)
+ *
+ * Host: S = (Av&circ;u) &circ; b (computes session key)
+ * Host: K = H(S)
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public abstract class SRP6KeyAgreement
+ extends BaseKeyAgreementParty
+{
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp6.ka.prng";
+ public static final String SHARED_MODULUS = "gnu.crypto.srp6.ka.N";
+ public static final String GENERATOR = "gnu.crypto.srp6.ka.g";
+ public static final String HASH_FUNCTION = "gnu.crypto.srp6.ka.H";
+ public static final String USER_IDENTITY = "gnu.crypto.srp6.ka.I";
+ public static final String USER_PASSWORD = "gnu.crypto.srp6.ka.p";
+ public static final String HOST_PASSWORD_DB = "gnu.crypto.srp6.ka.password.db";
+ protected static final BigInteger THREE = BigInteger.valueOf(3L);
+ protected SRP srp;
+ protected BigInteger N;
+ protected BigInteger g;
+ /** The shared secret key. */
+ protected BigInteger K;
+
+ protected SRP6KeyAgreement()
+ {
+ super(Registry.SRP6_KA);
+ }
+
+ protected byte[] engineSharedSecret() throws KeyAgreementException
+ {
+ return Util.trim(K);
+ }
+
+ protected void engineReset()
+ {
+ srp = null;
+ N = null;
+ g = null;
+ K = null;
+ }
+
+ protected BigInteger uValue(final BigInteger A, final BigInteger B)
+ {
+ final IMessageDigest hash = srp.newDigest();
+ byte[] b;
+ b = Util.trim(A);
+ hash.update(b, 0, b.length);
+ b = Util.trim(B);
+ hash.update(b, 0, b.length);
+ return new BigInteger(1, hash.digest());
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java
new file mode 100644
index 000000000..ec5cd7f17
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java
@@ -0,0 +1,90 @@
+/* SRP6SaslClient.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+
+/**
+ * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the
+ * User (client side).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ *
+ * <pre>
+ * C -&gt; S: I (identifies self)
+ * S -&gt; C: N, g, s, B = 3v + g&circ;b (sends salt, b = random number)
+ * C -&gt; S: A = g&circ;a (a = random number)
+ * </pre>
+ *
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6SaslClient
+ extends SRP6TLSClient
+{
+ // default 0-arguments constructor
+
+ protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final OutgoingMessage result = super.computeSharedSecret(in);
+ final byte[] sBytes = Util.trim(K);
+ final IMessageDigest hash = srp.newDigest();
+ hash.update(sBytes, 0, sBytes.length);
+ K = new BigInteger(1, hash.digest());
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java
new file mode 100644
index 000000000..a4313f4d3
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java
@@ -0,0 +1,90 @@
+/* SRP6SaslServer.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+
+import java.math.BigInteger;
+
+/**
+ * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the
+ * Host (server side).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ *
+ * <pre>
+ * C -&gt; S: I (identifies self)
+ * S -&gt; C: N, g, s, B = 3v + g&circ;b (sends salt, b = random number)
+ * C -&gt; S: A = g&circ;a (a = random number)
+ * </pre>
+ *
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6SaslServer
+ extends SRP6TLSServer
+{
+ // default 0-arguments constructor
+
+ protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ super.computeSharedSecret(in);
+ final byte[] sBytes = Util.trim(K);
+ final IMessageDigest hash = srp.newDigest();
+ hash.update(sBytes, 0, sBytes.length);
+ K = new BigInteger(1, hash.digest());
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java
new file mode 100644
index 000000000..c2459f620
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java
@@ -0,0 +1,155 @@
+/* SRP6TLSClient.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A variation of the SRP6 key agreement protocol, for the client-side as
+ * proposed in <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+public class SRP6TLSClient
+ extends SRP6KeyAgreement
+{
+ /** The user's identity. */
+ private String I;
+ /** The user's cleartext password. */
+ private byte[] p;
+ /** The user's ephemeral key pair. */
+ private KeyPair userKeyPair;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(final Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ final String md = (String) attributes.get(HASH_FUNCTION);
+ if (md == null || md.trim().length() == 0)
+ throw new KeyAgreementException("missing hash function");
+ srp = SRP.instance(md);
+ I = (String) attributes.get(USER_IDENTITY);
+ if (I == null)
+ throw new KeyAgreementException("missing user identity");
+ p = (byte[]) attributes.get(USER_PASSWORD);
+ if (p == null)
+ throw new KeyAgreementException("missing user password");
+ }
+
+ protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return sendIdentity(in);
+ case 1:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ protected void engineReset()
+ {
+ I = null;
+ p = null;
+ userKeyPair = null;
+ super.engineReset();
+ }
+
+ private OutgoingMessage sendIdentity(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final OutgoingMessage result = new OutgoingMessage();
+ result.writeString(I);
+ return result;
+ }
+
+ protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ N = in.readMPI();
+ g = in.readMPI();
+ final BigInteger s = in.readMPI();
+ final BigInteger B = in.readMPI();
+ // generate an ephemeral keypair
+ final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+ final Map attributes = new HashMap();
+ if (rnd != null)
+ attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+ attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+ attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+ kpg.setup(attributes);
+ userKeyPair = kpg.generate();
+ final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY();
+ final BigInteger u = uValue(A, B); // u = H(A | B)
+ final BigInteger x;
+ try
+ {
+ x = new BigInteger(1, srp.computeX(Util.trim(s), I, p));
+ }
+ catch (Exception e)
+ {
+ throw new KeyAgreementException("computeSharedSecret()", e);
+ }
+ // compute S = (B - 3g^x) ^ (a + ux)
+ final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX();
+ final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N)))
+ .modPow(a.add(u.multiply(x)), N);
+ K = S;
+ final OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(A);
+ complete = true;
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java
new file mode 100644
index 000000000..42e3d9cb1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java
@@ -0,0 +1,177 @@
+/* SRP6TLSServer.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A variation of the SRP6 key agreement protocol, for the server-side as
+ * proposed in <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+public class SRP6TLSServer
+ extends SRP6KeyAgreement
+{
+ /** The user's ephemeral key pair. */
+ private KeyPair hostKeyPair;
+ /** The SRP password database. */
+ private SRPAuthInfoProvider passwordDB;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(final Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ final String md = (String) attributes.get(HASH_FUNCTION);
+ if (md == null || md.trim().length() == 0)
+ throw new KeyAgreementException("missing hash function");
+ srp = SRP.instance(md);
+ passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB);
+ if (passwordDB == null)
+ throw new KeyAgreementException("missing SRP password database");
+ }
+
+ protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return sendParameters(in);
+ case 1:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ protected void engineReset()
+ {
+ hostKeyPair = null;
+ super.engineReset();
+ }
+
+ private OutgoingMessage sendParameters(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final String I = in.readString();
+ // get s and v for user identified by I
+ // ----------------------------------------------------------------------
+ final Map credentials;
+ try
+ {
+ final Map userID = new HashMap();
+ userID.put(Registry.SASL_USERNAME, I);
+ userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm());
+ credentials = passwordDB.lookup(userID);
+ }
+ catch (IOException x)
+ {
+ throw new KeyAgreementException("computeSharedSecret()", x);
+ }
+
+ final BigInteger s = new BigInteger(
+ 1, Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD)));
+ final BigInteger v = new BigInteger(
+ 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD)));
+ final Map configuration;
+ try
+ {
+ final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD);
+ configuration = passwordDB.getConfiguration(mode);
+ }
+ catch (IOException x)
+ {
+ throw new KeyAgreementException("computeSharedSecret()", x);
+ }
+ N = new BigInteger(
+ 1, Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS)));
+ g = new BigInteger(
+ 1, Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR)));
+ // generate an ephemeral keypair
+ final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+ final Map attributes = new HashMap();
+ if (rnd != null)
+ attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+ attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+ attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+ attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+ kpg.setup(attributes);
+ hostKeyPair = kpg.generate();
+ final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+ final OutgoingMessage result = new OutgoingMessage();
+ result.writeMPI(N);
+ result.writeMPI(g);
+ result.writeMPI(s);
+ result.writeMPI(B);
+ return result;
+ }
+
+ protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final BigInteger A = in.readMPI();
+ final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();
+ final BigInteger u = uValue(A, B); // u = H(A | B)
+ // compute S = (Av^u) ^ b
+ final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX();
+ final BigInteger v = ((SRPPrivateKey) hostKeyPair.getPrivate()).getV();
+ final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N);
+ K = S;
+ complete = true;
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java
new file mode 100644
index 000000000..4a1e8dda9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java
@@ -0,0 +1,163 @@
+/* SRP6User.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The implementation of the User in the SRP-6 protocol.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRP6User
+ extends SRP6KeyAgreement
+{
+ /** The user's identity. */
+ private String I;
+ /** The user's cleartext password. */
+ private byte[] p;
+ /** The user's ephemeral key pair. */
+ private KeyPair userKeyPair;
+
+ // default 0-arguments constructor
+
+ protected void engineInit(final Map attributes) throws KeyAgreementException
+ {
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ N = (BigInteger) attributes.get(SHARED_MODULUS);
+ if (N == null)
+ throw new KeyAgreementException("missing shared modulus");
+ g = (BigInteger) attributes.get(GENERATOR);
+ if (g == null)
+ throw new KeyAgreementException("missing generator");
+ final String md = (String) attributes.get(HASH_FUNCTION);
+ if (md == null || md.trim().length() == 0)
+ throw new KeyAgreementException("missing hash function");
+ srp = SRP.instance(md);
+ I = (String) attributes.get(USER_IDENTITY);
+ if (I == null)
+ throw new KeyAgreementException("missing user identity");
+ p = (byte[]) attributes.get(USER_PASSWORD);
+ if (p == null)
+ throw new KeyAgreementException("missing user password");
+ }
+
+ protected OutgoingMessage engineProcessMessage(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ switch (step)
+ {
+ case 0:
+ return sendIdentity(in);
+ case 1:
+ return computeSharedSecret(in);
+ default:
+ throw new IllegalStateException("unexpected state");
+ }
+ }
+
+ protected void engineReset()
+ {
+ I = null;
+ p = null;
+ userKeyPair = null;
+ super.engineReset();
+ }
+
+ private OutgoingMessage sendIdentity(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ // generate an ephemeral keypair
+ final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
+ final Map attributes = new HashMap();
+ if (rnd != null)
+ attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
+ attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+ attributes.put(SRPKeyPairGenerator.GENERATOR, g);
+ kpg.setup(attributes);
+ userKeyPair = kpg.generate();
+ final OutgoingMessage result = new OutgoingMessage();
+ result.writeString(I);
+ result.writeMPI(((SRPPublicKey) userKeyPair.getPublic()).getY());
+ return result;
+ }
+
+ private OutgoingMessage computeSharedSecret(final IncomingMessage in)
+ throws KeyAgreementException
+ {
+ final BigInteger s = in.readMPI();
+ final BigInteger B = in.readMPI();
+ final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY();
+ final BigInteger u = uValue(A, B); // u = H(A | B)
+ final BigInteger x;
+ try
+ {
+ x = new BigInteger(1, srp.computeX(Util.trim(s), I, p));
+ }
+ catch (Exception e)
+ {
+ throw new KeyAgreementException("computeSharedSecret()", e);
+ }
+ // compute S = (B - 3g^x) ^ (a + ux)
+ final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX();
+ final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N)))
+ .modPow(a.add(u.multiply(x)), N);
+ final byte[] sBytes = Util.trim(S);
+ final IMessageDigest hash = srp.newDigest();
+ hash.update(sBytes, 0, sBytes.length);
+ K = new BigInteger(1, hash.digest());
+ complete = true;
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java
new file mode 100644
index 000000000..fb8249e05
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java
@@ -0,0 +1,131 @@
+/* SRPAlgorithm.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+
+import java.math.BigInteger;
+
+/**
+ * Utilities for use with SRP-6 based methods and protocols.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPAlgorithm
+{
+ // lifted from draft-burdis-cat-srp-sasl-09
+ public static final BigInteger N_2048 = new BigInteger(
+ "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050"
+ + "A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50"
+ + "E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B8"
+ + "55F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773B"
+ + "CA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748"
+ + "544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6"
+ + "AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6"
+ + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 16);
+ public static final BigInteger N_1536 = new BigInteger(
+ "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D"
+ + "5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DC"
+ + "DF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC"
+ + "764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C486"
+ + "65772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E"
+ + "5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", 16);
+ public static final BigInteger N_1280 = new BigInteger(
+ "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC4"
+ + "3872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B78"
+ + "6C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891"
+ + "690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163"
+ + "EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", 16);
+ public static final BigInteger N_1024 = new BigInteger(
+ "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576"
+ + "D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD1"
+ + "5DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC"
+ + "68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", 16);
+ public static final BigInteger N_768 = new BigInteger(
+ "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F40"
+ + "2653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF"
+ + "737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", 16);
+ public static final BigInteger N_640 = new BigInteger(
+ "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046"
+ + "E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A207"
+ + "1C4B3836CBEEAB15034460FAA7ADF483", 16);
+ public static final BigInteger N_512 = new BigInteger(
+ "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA"
+ + "2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", 16);
+ public static final BigInteger N_384 = new BigInteger(
+ "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED57"
+ + "54EB764C7AB7184578C57D5949CCB41B", 16);
+ public static final BigInteger N_264 = new BigInteger(
+ "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", 16);
+ private static final BigInteger ZERO = BigInteger.ZERO;
+ private static final BigInteger ONE = BigInteger.ONE;
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+ /** Trivial constructor to enforce usage through class methods. */
+ private SRPAlgorithm()
+ {
+ super();
+ }
+
+ public static void checkParams(final BigInteger N, final BigInteger g)
+ {
+ // 1. N should be at least 512-bit long
+ final int blen = N.bitLength();
+ if (blen < SRPRegistry.MINIMUM_MODULUS_BITLENGTH)
+ throw new IllegalArgumentException("Bit length of N ("
+ + blen
+ + ") is too low. Should be at least "
+ + SRPRegistry.MINIMUM_MODULUS_BITLENGTH);
+ // 2. N should be a prime
+ if (! N.isProbablePrime(80))
+ throw new IllegalArgumentException("N should be prime but isn't");
+ // 3. N should be of the form 2*q + 1, where q is prime
+ final BigInteger q = N.subtract(ONE).divide(TWO);
+ if (! q.isProbablePrime(80))
+ throw new IllegalArgumentException("(N-1)/2 should be prime but isn't");
+ // 4. g**q should be -1 mod N
+ final BigInteger gq = g.modPow(q, N).add(ONE).mod(N);
+ if (gq.compareTo(ZERO) != 0)
+ throw new IllegalArgumentException("g**q should be -1 (mod N) but isn't");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java
new file mode 100644
index 000000000..72ce8d2cf
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java
@@ -0,0 +1,147 @@
+/* SRPKey.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.security.Key;
+
+/**
+ * An abstract representation of a base SRP ephemeral key.
+ * <p>
+ * This object encapsulates the two numbers:
+ * <ul>
+ * <li><b>N</b>: A large safe prime (N = 2q+1, where q is prime).</li>
+ * <li><b>g</b>: A generator modulo N.</li>
+ * </ul>
+ * <p>
+ * Note that in SRP, all arithmetic is done modulo N.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public abstract class SRPKey
+ implements Key, Serializable
+{
+ /** The public, Germaine prime, shared modulus. */
+ protected final BigInteger N;
+ /** The generator. */
+ protected final BigInteger g;
+
+ protected SRPKey(BigInteger N, BigInteger g)
+ {
+ super();
+
+ this.N = N;
+ this.g = g;
+ }
+
+ /**
+ * Returns the standard algorithm name for this key.
+ *
+ * @return the standard algorithm name for this key.
+ */
+ public String getAlgorithm()
+ {
+ return Registry.SRP_KPG;
+ }
+
+ /** @deprecated see getEncoded(int). */
+ public byte[] getEncoded()
+ {
+ return getEncoded(IKeyPairCodec.RAW_FORMAT);
+ }
+
+ /**
+ * Returns {@link Registry#RAW_ENCODING_SHORT_NAME} which is the sole format
+ * supported for this type of keys.
+ *
+ * @return {@link Registry#RAW_ENCODING_SHORT_NAME} ALWAYS.
+ */
+ public String getFormat()
+ {
+ return Registry.RAW_ENCODING_SHORT_NAME;
+ }
+
+ /**
+ * Returns the public shared modulus.
+ *
+ * @return <code>N</code>.
+ */
+ public BigInteger getN()
+ {
+ return N;
+ }
+
+ /**
+ * Returns the generator.
+ *
+ * @return <code>g</code>.
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * <code>SRPKey</code> and has the same SRP parameter values as this one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+ if (! (obj instanceof SRPKey))
+ return false;
+ SRPKey that = (SRPKey) obj;
+ return N.equals(that.getN()) && g.equals(that.getG());
+ }
+
+ public abstract byte[] getEncoded(int format);
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java
new file mode 100644
index 000000000..59e5bc943
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java
@@ -0,0 +1,282 @@
+/* SRPKeyPairGenerator.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPKeyPairGenerator
+ implements IKeyPairGenerator
+{
+ private static final Logger log = Logger.getLogger(SRPKeyPairGenerator.class.getName());
+ private static final BigInteger ZERO = BigInteger.ZERO;
+ private static final BigInteger ONE = BigInteger.ONE;
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+ private static final BigInteger THREE = BigInteger.valueOf(3L);
+ /** Property name of the length (Integer) of the modulus (N) of an SRP key. */
+ public static final String MODULUS_LENGTH = "gnu.crypto.srp.L";
+ /** Property name of the Boolean indicating wether or not to use defaults. */
+ public static final String USE_DEFAULTS = "gnu.crypto.srp.use.defaults";
+ /** Property name of the modulus (N) of an SRP key. */
+ public static final String SHARED_MODULUS = "gnu.crypto.srp.N";
+ /** Property name of the generator (g) of an SRP key. */
+ public static final String GENERATOR = "gnu.crypto.srp.g";
+ /** Property name of the user's verifier (v) for a Server SRP key. */
+ public static final String USER_VERIFIER = "gnu.crypto.srp.v";
+ /**
+ * Property name of an optional {@link SecureRandom} instance to use. The
+ * default is to use a classloader singleton from {@link PRNG}.
+ */
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp.prng";
+ /** Default value for the modulus length. */
+ private static final int DEFAULT_MODULUS_LENGTH = 1024;
+ /** The optional {@link SecureRandom} instance to use. */
+ private SecureRandom rnd = null;
+ /** Bit length of the shared modulus. */
+ private int l;
+ /** The shared public modulus. */
+ private BigInteger N;
+ /** The Field generator. */
+ private BigInteger g;
+ /** The user's verifier MPI. */
+ private BigInteger v;
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ // implicit 0-arguments constructor
+
+ public String name()
+ {
+ return Registry.SRP_KPG;
+ }
+
+ public void setup(Map attributes)
+ {
+ // do we have a SecureRandom, or should we use our own?
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ N = (BigInteger) attributes.get(SHARED_MODULUS);
+ if (N != null)
+ {
+ l = N.bitLength();
+ g = (BigInteger) attributes.get(GENERATOR);
+ if (g == null)
+ g = TWO;
+ SRPAlgorithm.checkParams(N, g);
+ }
+ else
+ { // generate or use default values for N and g
+ Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
+ if (useDefaults == null)
+ useDefaults = Boolean.TRUE;
+ Integer L = (Integer) attributes.get(MODULUS_LENGTH);
+ l = DEFAULT_MODULUS_LENGTH;
+ if (useDefaults.equals(Boolean.TRUE))
+ {
+ if (L != null)
+ {
+ l = L.intValue();
+ switch (l)
+ {
+ case 512:
+ N = SRPAlgorithm.N_512;
+ break;
+ case 640:
+ N = SRPAlgorithm.N_640;
+ break;
+ case 768:
+ N = SRPAlgorithm.N_768;
+ break;
+ case 1024:
+ N = SRPAlgorithm.N_1024;
+ break;
+ case 1280:
+ N = SRPAlgorithm.N_1280;
+ break;
+ case 1536:
+ N = SRPAlgorithm.N_1536;
+ break;
+ case 2048:
+ N = SRPAlgorithm.N_2048;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unknown default shared modulus bit length");
+ }
+ g = TWO;
+ l = N.bitLength();
+ }
+ }
+ else // generate new N and g
+ {
+ if (L != null)
+ {
+ l = L.intValue();
+ if ((l % 256) != 0 || l < 512 || l > 2048)
+ throw new IllegalArgumentException(
+ "invalid shared modulus bit length");
+ }
+ }
+ }
+ // are we using this generator on the server side, or the client side?
+ v = (BigInteger) attributes.get(USER_VERIFIER);
+ }
+
+ public KeyPair generate()
+ {
+ if (N == null)
+ {
+ BigInteger[] params = generateParameters();
+ BigInteger q = params[0];
+ N = params[1];
+ g = params[2];
+ if (Configuration.DEBUG)
+ {
+ log.fine("q: " + q.toString(16));
+ log.fine("N: " + N.toString(16));
+ log.fine("g: " + g.toString(16));
+ }
+ }
+ return (v != null ? hostKeyPair() : userKeyPair());
+ }
+
+ private synchronized BigInteger[] generateParameters()
+ {
+ // N A large safe prime (N = 2q+1, where q is prime)
+ // g A generator modulo N
+ BigInteger q, p, g;
+ byte[] qBytes = new byte[l / 8];
+ do
+ {
+ do
+ {
+ nextRandomBytes(qBytes);
+ q = new BigInteger(1, qBytes);
+ q = q.setBit(0).setBit(l - 2).clearBit(l - 1);
+ }
+ while (! q.isProbablePrime(80));
+ p = q.multiply(TWO).add(ONE);
+ }
+ while (p.bitLength() != l || ! p.isProbablePrime(80));
+ // compute g. from FIPS-186, Appendix 4: e == 2
+ BigInteger p_minus_1 = p.subtract(ONE);
+ g = TWO;
+ // Set h = any integer, where 1 < h < p - 1 and
+ // h differs from any value previously tried
+ for (BigInteger h = TWO; h.compareTo(p_minus_1) < 0; h = h.add(ONE))
+ {
+ // Set g = h**2 mod p
+ g = h.modPow(TWO, p);
+ // If g = 1, go to step 3
+ if (! g.equals(ONE))
+ break;
+ }
+ return new BigInteger[] { q, p, g };
+ }
+
+ private KeyPair hostKeyPair()
+ {
+ byte[] bBytes = new byte[(l + 7) / 8];
+ BigInteger b, B;
+ do
+ {
+ do
+ {
+ nextRandomBytes(bBytes);
+ b = new BigInteger(1, bBytes);
+ }
+ while (b.compareTo(ONE) <= 0 || b.compareTo(N) >= 0);
+ B = THREE.multiply(v).add(g.modPow(b, N)).mod(N);
+ }
+ while (B.compareTo(ZERO) == 0 || B.compareTo(N) >= 0);
+ KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, B }),
+ new SRPPrivateKey(new BigInteger[] { N, g, b, v }));
+ return result;
+ }
+
+ private KeyPair userKeyPair()
+ {
+ byte[] aBytes = new byte[(l + 7) / 8];
+ BigInteger a, A;
+ do
+ {
+ do
+ {
+ nextRandomBytes(aBytes);
+ a = new BigInteger(1, aBytes);
+ }
+ while (a.compareTo(ONE) <= 0 || a.compareTo(N) >= 0);
+ A = g.modPow(a, N);
+ }
+ while (A.compareTo(ZERO) == 0 || A.compareTo(N) >= 0);
+ KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, A }),
+ new SRPPrivateKey(new BigInteger[] { N, g, a }));
+ return result;
+ }
+
+ private void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java
new file mode 100644
index 000000000..b7cc53693
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java
@@ -0,0 +1,334 @@
+/* SRPKeyPairRawCodec.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with SRP keypairs.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPKeyPairRawCodec
+ implements IKeyPairCodec
+{
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return RAW_FORMAT;
+ }
+
+ /**
+ * Returns the encoded form of the designated SRP public key according to the
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an SRP public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>N</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not an SRP one.
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ if (! (key instanceof SRPPublicKey))
+ throw new IllegalArgumentException("key");
+ SRPPublicKey srpKey = (SRPPublicKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]);
+ // version
+ baos.write(0x01);
+ // N
+ byte[] buffer = srpKey.getN().toByteArray();
+ int length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = srpKey.getG().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // y
+ buffer = srpKey.getY().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ return baos.toByteArray();
+ }
+
+ public PublicKey decodePublicKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3])
+ throw new IllegalArgumentException("magic");
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // N
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger N = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // y
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger y = new BigInteger(1, buffer);
+ return new SRPPublicKey(N, g, y);
+ }
+
+ /**
+ * Returns the encoded form of the designated SRP private key according to the
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an SRP private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>N</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>x</code>,
+ * </li>
+ * <li>one byte which indicates whether the SRP parameter <code>v</code> is
+ * included in this encoding (value <code>0x01</code>) or not (value
+ * <code>0x00</code>).</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>v</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>v</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not an SRP one.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ if (! (key instanceof SRPPrivateKey))
+ throw new IllegalArgumentException("key");
+ SRPPrivateKey srpKey = (SRPPrivateKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]);
+ // version
+ baos.write(0x01);
+ // N
+ byte[] buffer = srpKey.getN().toByteArray();
+ int length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = srpKey.getG().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // x
+ buffer = srpKey.getX().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ // v
+ if (srpKey.getV() != null)
+ {
+ baos.write(0x01);
+ buffer = srpKey.getV().toByteArray();
+ length = buffer.length;
+ baos.write( length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write( length & 0xFF);
+ baos.write(buffer, 0, length);
+ }
+ else
+ baos.write(0x00);
+ return baos.toByteArray();
+ }
+
+ public PrivateKey decodePrivateKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3])
+ throw new IllegalArgumentException("magic");
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // N
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger N = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // x
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger x = new BigInteger(1, buffer);
+ // v
+ l = k[i++];
+ if (l == 0x01)
+ {
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger v = new BigInteger(1, buffer);
+ return new SRPPrivateKey(N, g, x, v);
+ }
+ return new SRPPrivateKey(N, g, x);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java
new file mode 100644
index 000000000..c2e13be82
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java
@@ -0,0 +1,227 @@
+/* SRPPrivateKey.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * A representation of an SRP ephemeral private key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPPrivateKey
+ extends SRPKey
+ implements PrivateKey
+{
+ /**
+ * The private exponent for either the server or the client engaged in the SRP
+ * protocol exchange.
+ */
+ private final BigInteger X;
+ /**
+ * The user's verifier (v) --for the server-- also computed at the client side
+ * as g.modPow(x, N), where x is the hashed output of the user name and
+ * password .
+ */
+ private final BigInteger v;
+
+ /**
+ * Public constructor for use from outside this package.
+ *
+ * @param N the public shared modulus.
+ * @param g the generator.
+ * @param x the private exponent of the ephemeral key.
+ */
+ public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x)
+ {
+ this(N, g, x, null);
+ }
+
+ /**
+ * Public constructor for use from outside this package.
+ *
+ * @param N the public shared modulus.
+ * @param g the generator.
+ * @param x the private exponent of the ephemeral key.
+ * @param v the user's verifier value (for the server side only).
+ */
+ public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x, BigInteger v)
+ {
+ super(N, g);
+
+ SRPAlgorithm.checkParams(N, g);
+ this.X = x;
+ this.v = v;
+ }
+
+ /**
+ * Default constructor. Assumes N and g are already validated.
+ *
+ * @param params an array of either 3 or 4 values representing N, g, and
+ * either v and X for the server, or just X for the client. Those
+ * values represent the following:
+ * <ol>
+ * <li>v (server side): the user's verifier.</li>
+ * <li>X (both sides): the server's or client's ephemeral private
+ * exponent.</li>
+ * </ol>
+ */
+ SRPPrivateKey(BigInteger[] params)
+ {
+ super(params[0], params[1]);
+
+ if (params.length == 3)
+ {
+ X = params[2];
+ v = null;
+ }
+ else if (params.length == 4)
+ {
+ X = params[2];
+ v = params[3];
+ }
+ else
+ throw new IllegalArgumentException("invalid number of SRP parameters");
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePrivateKey()</code>
+ * method of an SRP keypair codec object (an instance implementing
+ * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this
+ * object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an instance
+ * of this object.
+ * @throws IllegalArgumentException if the byte sequence does not represent a
+ * valid encoding of an instance of this object.
+ */
+ public static SRPPrivateKey valueOf(byte[] k)
+ {
+ // check magic...
+ // we should parse here enough bytes to know which codec to use, and
+ // direct the byte array to the appropriate codec. since we only have one
+ // codec, we could have immediately tried it; nevertheless since testing
+ // one byte is cheaper than instatiating a codec that will fail we test
+ // the first byte before we carry on.
+ if (k[0] == Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0])
+ {
+ // it's likely to be in raw format. get a raw codec and hand it over
+ IKeyPairCodec codec = new SRPKeyPairRawCodec();
+ return (SRPPrivateKey) codec.decodePrivateKey(k);
+ }
+ throw new IllegalArgumentException("magic");
+ }
+
+ /**
+ * Returns the private exponent of the key as a {@link BigInteger}.
+ *
+ * @return the private exponent of the key as a {@link BigInteger}.
+ */
+ public BigInteger getX()
+ {
+ return X;
+ }
+
+ /**
+ * Returns the user's verifier as a {@link BigInteger}.
+ *
+ * @return the user's verifier as a {@link BigInteger} if this is an SRP
+ * private key of a Host, or <code>null</code> if this is a private
+ * SRP key for a User.
+ */
+ public BigInteger getV()
+ {
+ return v;
+ }
+
+ /**
+ * Returns the encoded form of this private key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @throws IllegalArgumentException if the format is not supported.
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new SRPKeyPairRawCodec().encodePrivateKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("format");
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * <code>SRPPrivateKey</code> and has the same SRP parameter values as this
+ * one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+ if (! (obj instanceof SRPPrivateKey))
+ return false;
+ SRPPrivateKey that = (SRPPrivateKey) obj;
+ boolean result = super.equals(that) && X.equals(that.getX());
+ if (v != null)
+ result = result && v.equals(that.getV());
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java
new file mode 100644
index 000000000..2db13ff4c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java
@@ -0,0 +1,175 @@
+/* SRPPublicKey.java --
+ Copyright (C) 2003, 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.crypto.key.srp6;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * A representation of an SRP ephemeral public key.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+public class SRPPublicKey
+ extends SRPKey
+ implements PublicKey
+{
+ /**
+ * The public exponent for either the server or the client engaged in the SRP
+ * protocol exchange.
+ */
+ private final BigInteger Y;
+
+ /**
+ * Public constructor for use from outside this package.
+ *
+ * @param N the public shared modulus.
+ * @param g the generator.
+ * @param Y the public exponent of the ephemeral key.
+ */
+ public SRPPublicKey(BigInteger N, BigInteger g, BigInteger Y)
+ {
+ super(N, g);
+
+ SRPAlgorithm.checkParams(N, g);
+ this.Y = Y;
+ }
+
+ /**
+ * Default constructor. Assumes that N and g are already validated.
+ *
+ * @param params an array of 3 values representing N, g and Y; the latter
+ * being the client's or server's public exponent.
+ */
+ SRPPublicKey(BigInteger[] params)
+ {
+ super(params[0], params[1]);
+
+ this.Y = params[2];
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePublicKey()</code>
+ * method of an SRP keypair codec object (an instance implementing
+ * {@link IKeyPairCodec} for SRP keys, and re-constructs an instance of this
+ * object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an instance
+ * of this object.
+ * @throws IllegalArgumentException if the byte sequence does not represent a
+ * valid encoding of an instance of this object.
+ */
+ public static SRPPublicKey valueOf(byte[] k)
+ {
+ // check magic...
+ // we should parse here enough bytes to know which codec to use, and
+ // direct the byte array to the appropriate codec. since we only have one
+ // codec, we could have immediately tried it; nevertheless since testing
+ // one byte is cheaper than instatiating a codec that will fail we test
+ // the first byte before we carry on.
+ if (k[0] == Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0])
+ {
+ // it's likely to be in raw format. get a raw codec and hand it over
+ IKeyPairCodec codec = new SRPKeyPairRawCodec();
+ return (SRPPublicKey) codec.decodePublicKey(k);
+ }
+ throw new IllegalArgumentException("magic");
+ }
+
+ /**
+ * Returns the public exponent of the key as a {@link BigInteger}.
+ *
+ * @return the public exponent of the key as a {@link BigInteger}.
+ */
+ public BigInteger getY()
+ {
+ return Y;
+ }
+
+ /**
+ * Returns the encoded form of this public key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @throws IllegalArgumentException if the format is not supported.
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new SRPKeyPairRawCodec().encodePublicKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("format");
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * <code>SRPPublicKey</code>and has the same SRP parameter values as this
+ * one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+ if (! (obj instanceof SRPPublicKey))
+ return false;
+ SRPPublicKey that = (SRPPublicKey) obj;
+ return super.equals(that) && Y.equals(that.getY());
+ }
+}