Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
41161 views
/*1* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.crypto.provider;2627import java.io.*;28import java.util.Objects;29import java.math.BigInteger;30import java.security.KeyRep;31import java.security.InvalidKeyException;32import java.security.ProviderException;33import java.security.PublicKey;34import javax.crypto.spec.DHParameterSpec;35import sun.security.util.*;363738/**39* A public key in X.509 format for the Diffie-Hellman key agreement algorithm.40*41* @author Jan Luehe42*43*44* @see DHPrivateKey45* @see javax.crypto.KeyAgreement46*/47final class DHPublicKey implements PublicKey,48javax.crypto.interfaces.DHPublicKey, Serializable {4950@java.io.Serial51static final long serialVersionUID = 7647557958927458271L;5253// the public key54private BigInteger y;5556// the key bytes, without the algorithm information57private byte[] key;5859// the encoded key60private byte[] encodedKey;6162// the prime modulus63private BigInteger p;6465// the base generator66private BigInteger g;6768// the private-value length (optional)69private int l;7071// Note: this OID is used by DHPrivateKey as well.72static ObjectIdentifier DH_OID =73ObjectIdentifier.of(KnownOIDs.DiffieHellman);7475/**76* Make a DH public key out of a public value <code>y</code>, a prime77* modulus <code>p</code>, and a base generator <code>g</code>.78*79* @param y the public value80* @param p the prime modulus81* @param g the base generator82*83* @exception InvalidKeyException if the key cannot be encoded84*/85DHPublicKey(BigInteger y, BigInteger p, BigInteger g)86throws InvalidKeyException {87this(y, p, g, 0);88}8990/**91* Make a DH public key out of a public value <code>y</code>, a prime92* modulus <code>p</code>, a base generator <code>g</code>, and a93* private-value length <code>l</code>.94*95* @param y the public value96* @param p the prime modulus97* @param g the base generator98* @param l the private-value length99*100* @exception ProviderException if the key cannot be encoded101*/102DHPublicKey(BigInteger y, BigInteger p, BigInteger g, int l) {103this.y = y;104this.p = p;105this.g = g;106this.l = l;107try {108this.key = new DerValue(DerValue.tag_Integer,109this.y.toByteArray()).toByteArray();110this.encodedKey = getEncoded();111} catch (IOException e) {112throw new ProviderException("Cannot produce ASN.1 encoding", e);113}114}115116/**117* Make a DH public key from its DER encoding (X.509).118*119* @param encodedKey the encoded key120*121* @exception InvalidKeyException if the encoded key does not represent122* a Diffie-Hellman public key123*/124DHPublicKey(byte[] encodedKey) throws InvalidKeyException {125InputStream inStream = new ByteArrayInputStream(encodedKey);126try {127DerValue derKeyVal = new DerValue(inStream);128if (derKeyVal.tag != DerValue.tag_Sequence) {129throw new InvalidKeyException ("Invalid key format");130}131132/*133* Parse the algorithm identifier134*/135DerValue algid = derKeyVal.data.getDerValue();136if (algid.tag != DerValue.tag_Sequence) {137throw new InvalidKeyException("AlgId is not a SEQUENCE");138}139DerInputStream derInStream = algid.toDerInputStream();140ObjectIdentifier oid = derInStream.getOID();141if (oid == null) {142throw new InvalidKeyException("Null OID");143}144if (derInStream.available() == 0) {145throw new InvalidKeyException("Parameters missing");146}147148/*149* Parse the parameters150*/151DerValue params = derInStream.getDerValue();152if (params.tag == DerValue.tag_Null) {153throw new InvalidKeyException("Null parameters");154}155if (params.tag != DerValue.tag_Sequence) {156throw new InvalidKeyException("Parameters not a SEQUENCE");157}158params.data.reset();159this.p = params.data.getBigInteger();160this.g = params.data.getBigInteger();161// Private-value length is OPTIONAL162if (params.data.available() != 0) {163this.l = params.data.getInteger();164}165if (params.data.available() != 0) {166throw new InvalidKeyException("Extra parameter data");167}168169/*170* Parse the key171*/172this.key = derKeyVal.data.getBitString();173parseKeyBits();174if (derKeyVal.data.available() != 0) {175throw new InvalidKeyException("Excess key data");176}177178this.encodedKey = encodedKey.clone();179} catch (IOException | NumberFormatException e) {180throw new InvalidKeyException("Error parsing key encoding", e);181}182}183184/**185* Returns the encoding format of this key: "X.509"186*/187public String getFormat() {188return "X.509";189}190191/**192* Returns the name of the algorithm associated with this key: "DH"193*/194public String getAlgorithm() {195return "DH";196}197198/**199* Get the encoding of the key.200*/201public synchronized byte[] getEncoded() {202if (this.encodedKey == null) {203try {204DerOutputStream algid = new DerOutputStream();205206// store oid in algid207algid.putOID(DH_OID);208209// encode parameters210DerOutputStream params = new DerOutputStream();211params.putInteger(this.p);212params.putInteger(this.g);213if (this.l != 0) {214params.putInteger(this.l);215}216// wrap parameters into SEQUENCE217DerValue paramSequence = new DerValue(DerValue.tag_Sequence,218params.toByteArray());219// store parameter SEQUENCE in algid220algid.putDerValue(paramSequence);221222// wrap algid into SEQUENCE, and store it in key encoding223DerOutputStream tmpDerKey = new DerOutputStream();224tmpDerKey.write(DerValue.tag_Sequence, algid);225226// store key data227tmpDerKey.putBitString(this.key);228229// wrap algid and key into SEQUENCE230DerOutputStream derKey = new DerOutputStream();231derKey.write(DerValue.tag_Sequence, tmpDerKey);232this.encodedKey = derKey.toByteArray();233} catch (IOException e) {234return null;235}236}237return this.encodedKey.clone();238}239240/**241* Returns the public value, <code>y</code>.242*243* @return the public value, <code>y</code>244*/245public BigInteger getY() {246return this.y;247}248249/**250* Returns the key parameters.251*252* @return the key parameters253*/254public DHParameterSpec getParams() {255if (this.l != 0) {256return new DHParameterSpec(this.p, this.g, this.l);257} else {258return new DHParameterSpec(this.p, this.g);259}260}261262public String toString() {263String LINE_SEP = System.lineSeparator();264265StringBuilder sb266= new StringBuilder("SunJCE Diffie-Hellman Public Key:"267+ LINE_SEP + "y:" + LINE_SEP268+ Debug.toHexString(this.y)269+ LINE_SEP + "p:" + LINE_SEP270+ Debug.toHexString(this.p)271+ LINE_SEP + "g:" + LINE_SEP272+ Debug.toHexString(this.g));273if (this.l != 0)274sb.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);275return sb.toString();276}277278private void parseKeyBits() throws InvalidKeyException {279try {280DerInputStream in = new DerInputStream(this.key);281this.y = in.getBigInteger();282} catch (IOException e) {283throw new InvalidKeyException(284"Error parsing key encoding: " + e.toString());285}286}287288/**289* Calculates a hash code value for the object.290* Objects that are equal will also have the same hashcode.291*/292public int hashCode() {293return Objects.hash(y, p, g);294}295296public boolean equals(Object obj) {297if (this == obj) return true;298299if (!(obj instanceof javax.crypto.interfaces.DHPublicKey)) {300return false;301}302303javax.crypto.interfaces.DHPublicKey other =304(javax.crypto.interfaces.DHPublicKey) obj;305DHParameterSpec otherParams = other.getParams();306return ((this.y.compareTo(other.getY()) == 0) &&307(this.p.compareTo(otherParams.getP()) == 0) &&308(this.g.compareTo(otherParams.getG()) == 0));309}310311/**312* Replace the DH public key to be serialized.313*314* @return the standard KeyRep object to be serialized315*316* @throws java.io.ObjectStreamException if a new object representing317* this DH public key could not be created318*/319@java.io.Serial320private Object writeReplace() throws java.io.ObjectStreamException {321return new KeyRep(KeyRep.Type.PUBLIC,322getAlgorithm(),323getFormat(),324getEncoded());325}326}327328329