0N/A/*
3002N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.crypto.provider;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.math.BigInteger;
0N/Aimport java.security.KeyRep;
0N/Aimport java.security.InvalidKeyException;
0N/Aimport java.security.InvalidAlgorithmParameterException;
0N/Aimport java.security.ProviderException;
0N/Aimport java.security.PublicKey;
0N/Aimport javax.crypto.*;
0N/Aimport javax.crypto.spec.DHParameterSpec;
0N/Aimport sun.security.util.*;
0N/A
0N/A
0N/A/**
0N/A * A public key in X.509 format for the Diffie-Hellman key agreement algorithm.
0N/A *
0N/A * @author Jan Luehe
0N/A *
0N/A *
0N/A * @see DHPrivateKey
0N/A * @see java.security.KeyAgreement
0N/A */
0N/Afinal class DHPublicKey implements PublicKey,
0N/Ajavax.crypto.interfaces.DHPublicKey, Serializable {
0N/A
0N/A static final long serialVersionUID = 7647557958927458271L;
0N/A
0N/A // the public key
0N/A private BigInteger y;
0N/A
0N/A // the key bytes, without the algorithm information
0N/A private byte[] key;
0N/A
0N/A // the encoded key
0N/A private byte[] encodedKey;
0N/A
0N/A // the prime modulus
0N/A private BigInteger p;
0N/A
0N/A // the base generator
0N/A private BigInteger g;
0N/A
0N/A // the private-value length
0N/A private int l;
0N/A
0N/A private int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
0N/A
0N/A /**
0N/A * Make a DH public key out of a public value <code>y</code>, a prime
0N/A * modulus <code>p</code>, and a base generator <code>g</code>.
0N/A *
0N/A * @param y the public value
0N/A * @param p the prime modulus
0N/A * @param g the base generator
0N/A *
0N/A * @exception InvalidKeyException if the key cannot be encoded
0N/A */
0N/A DHPublicKey(BigInteger y, BigInteger p, BigInteger g)
0N/A throws InvalidKeyException {
0N/A this(y, p, g, 0);
0N/A }
0N/A
0N/A /**
0N/A * Make a DH public key out of a public value <code>y</code>, a prime
0N/A * modulus <code>p</code>, a base generator <code>g</code>, and a
0N/A * private-value length <code>l</code>.
0N/A *
0N/A * @param y the public value
0N/A * @param p the prime modulus
0N/A * @param g the base generator
0N/A * @param l the private-value length
0N/A *
0N/A * @exception ProviderException if the key cannot be encoded
0N/A */
0N/A DHPublicKey(BigInteger y, BigInteger p, BigInteger g, int l) {
0N/A this.y = y;
0N/A this.p = p;
0N/A this.g = g;
0N/A this.l = l;
0N/A try {
0N/A this.key = new DerValue(DerValue.tag_Integer,
0N/A this.y.toByteArray()).toByteArray();
0N/A this.encodedKey = getEncoded();
0N/A } catch (IOException e) {
0N/A throw new ProviderException("Cannot produce ASN.1 encoding", e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Make a DH public key from its DER encoding (X.509).
0N/A *
0N/A * @param encodedKey the encoded key
0N/A *
0N/A * @exception InvalidKeyException if the encoded key does not represent
0N/A * a Diffie-Hellman public key
0N/A */
0N/A DHPublicKey(byte[] encodedKey) throws InvalidKeyException {
0N/A InputStream inStream = new ByteArrayInputStream(encodedKey);
0N/A try {
0N/A DerValue derKeyVal = new DerValue(inStream);
0N/A if (derKeyVal.tag != DerValue.tag_Sequence) {
0N/A throw new InvalidKeyException ("Invalid key format");
0N/A }
0N/A
0N/A /*
0N/A * Parse the algorithm identifier
0N/A */
0N/A DerValue algid = derKeyVal.data.getDerValue();
0N/A if (algid.tag != DerValue.tag_Sequence) {
0N/A throw new InvalidKeyException("AlgId is not a SEQUENCE");
0N/A }
0N/A DerInputStream derInStream = algid.toDerInputStream();
0N/A ObjectIdentifier oid = derInStream.getOID();
0N/A if (oid == null) {
0N/A throw new InvalidKeyException("Null OID");
0N/A }
0N/A if (derInStream.available() == 0) {
0N/A throw new InvalidKeyException("Parameters missing");
0N/A }
0N/A
0N/A /*
0N/A * Parse the parameters
0N/A */
0N/A DerValue params = derInStream.getDerValue();
0N/A if (params.tag == DerValue.tag_Null) {
0N/A throw new InvalidKeyException("Null parameters");
0N/A }
0N/A if (params.tag != DerValue.tag_Sequence) {
0N/A throw new InvalidKeyException("Parameters not a SEQUENCE");
0N/A }
0N/A params.data.reset();
0N/A this.p = params.data.getBigInteger();
0N/A this.g = params.data.getBigInteger();
0N/A // Private-value length is OPTIONAL
0N/A if (params.data.available() != 0) {
0N/A this.l = params.data.getInteger();
0N/A }
0N/A if (params.data.available() != 0) {
0N/A throw new InvalidKeyException("Extra parameter data");
0N/A }
0N/A
0N/A /*
0N/A * Parse the key
0N/A */
0N/A this.key = derKeyVal.data.getBitString();
0N/A parseKeyBits();
0N/A if (derKeyVal.data.available() != 0) {
0N/A throw new InvalidKeyException("Excess key data");
0N/A }
0N/A
0N/A this.encodedKey = (byte[])encodedKey.clone();
0N/A
0N/A } catch (NumberFormatException e) {
0N/A throw new InvalidKeyException("Private-value length too big");
0N/A
0N/A } catch (IOException e) {
3002N/A throw new InvalidKeyException(
3002N/A "Error parsing key encoding: " + e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the encoding format of this key: "X.509"
0N/A */
0N/A public String getFormat() {
0N/A return "X.509";
0N/A }
0N/A
0N/A /**
0N/A * Returns the name of the algorithm associated with this key: "DH"
0N/A */
0N/A public String getAlgorithm() {
0N/A return "DH";
0N/A }
0N/A
0N/A /**
0N/A * Get the encoding of the key.
0N/A */
0N/A public synchronized byte[] getEncoded() {
0N/A if (this.encodedKey == null) {
0N/A try {
0N/A DerOutputStream algid = new DerOutputStream();
0N/A
0N/A // store oid in algid
0N/A algid.putOID(new ObjectIdentifier(DH_data));
0N/A
0N/A // encode parameters
0N/A DerOutputStream params = new DerOutputStream();
0N/A params.putInteger(this.p);
0N/A params.putInteger(this.g);
0N/A if (this.l != 0)
0N/A params.putInteger(this.l);
0N/A // wrap parameters into SEQUENCE
0N/A DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
0N/A params.toByteArray());
0N/A // store parameter SEQUENCE in algid
0N/A algid.putDerValue(paramSequence);
0N/A
0N/A // wrap algid into SEQUENCE, and store it in key encoding
0N/A DerOutputStream tmpDerKey = new DerOutputStream();
0N/A tmpDerKey.write(DerValue.tag_Sequence, algid);
0N/A
0N/A // store key data
0N/A tmpDerKey.putBitString(this.key);
0N/A
0N/A // wrap algid and key into SEQUENCE
0N/A DerOutputStream derKey = new DerOutputStream();
0N/A derKey.write(DerValue.tag_Sequence, tmpDerKey);
0N/A this.encodedKey = derKey.toByteArray();
0N/A } catch (IOException e) {
0N/A return null;
0N/A }
0N/A }
0N/A return (byte[])this.encodedKey.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the public value, <code>y</code>.
0N/A *
0N/A * @return the public value, <code>y</code>
0N/A */
0N/A public BigInteger getY() {
0N/A return this.y;
0N/A }
0N/A
0N/A /**
0N/A * Returns the key parameters.
0N/A *
0N/A * @return the key parameters
0N/A */
0N/A public DHParameterSpec getParams() {
0N/A if (this.l != 0)
0N/A return new DHParameterSpec(this.p, this.g, this.l);
0N/A else
0N/A return new DHParameterSpec(this.p, this.g);
0N/A }
0N/A
0N/A public String toString() {
0N/A String LINE_SEP = System.getProperty("line.separator");
0N/A
0N/A StringBuffer strbuf
0N/A = new StringBuffer("SunJCE Diffie-Hellman Public Key:"
0N/A + LINE_SEP + "y:" + LINE_SEP
0N/A + Debug.toHexString(this.y)
0N/A + LINE_SEP + "p:" + LINE_SEP
0N/A + Debug.toHexString(this.p)
0N/A + LINE_SEP + "g:" + LINE_SEP
0N/A + Debug.toHexString(this.g));
0N/A if (this.l != 0)
0N/A strbuf.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);
0N/A return strbuf.toString();
0N/A }
0N/A
0N/A private void parseKeyBits() throws InvalidKeyException {
0N/A try {
0N/A DerInputStream in = new DerInputStream(this.key);
0N/A this.y = in.getBigInteger();
0N/A } catch (IOException e) {
3002N/A throw new InvalidKeyException(
3002N/A "Error parsing key encoding: " + e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Calculates a hash code value for the object.
0N/A * Objects that are equal will also have the same hashcode.
0N/A */
0N/A public int hashCode() {
0N/A int retval = 0;
0N/A byte[] enc = getEncoded();
0N/A
0N/A for (int i = 1; i < enc.length; i++) {
0N/A retval += enc[i] * i;
0N/A }
0N/A return(retval);
0N/A }
0N/A
0N/A public boolean equals(Object obj) {
0N/A if (this == obj)
0N/A return true;
0N/A
0N/A if (!(obj instanceof PublicKey))
0N/A return false;
0N/A
0N/A byte[] thisEncoded = this.getEncoded();
0N/A byte[] thatEncoded = ((PublicKey)obj).getEncoded();
0N/A
0N/A return java.util.Arrays.equals(thisEncoded, thatEncoded);
0N/A }
0N/A
0N/A /**
0N/A * Replace the DH public key to be serialized.
0N/A *
0N/A * @return the standard KeyRep object to be serialized
0N/A *
0N/A * @throws java.io.ObjectStreamException if a new object representing
0N/A * this DH public key could not be created
0N/A */
0N/A private Object writeReplace() throws java.io.ObjectStreamException {
0N/A return new KeyRep(KeyRep.Type.PUBLIC,
0N/A getAlgorithm(),
0N/A getFormat(),
0N/A getEncoded());
0N/A }
0N/A}