diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/crypto/key/dh')
14 files changed, 2541 insertions, 0 deletions
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 <= g <= 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 <= x <= p-2, and sends B message + * (1) which is g^x mod p.</li> + * <li>B chooses a random secret y, 1 <= y <= 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> + * "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." + * </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 <= x <= 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> + * "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." + * </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; + } +} |