Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
41161 views
/*1* Copyright (c) 1997, 2021, 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.Arrays;29import java.util.Objects;30import java.math.BigInteger;31import java.security.KeyRep;32import java.security.PrivateKey;33import java.security.InvalidKeyException;34import java.security.ProviderException;35import javax.crypto.spec.DHParameterSpec;36import sun.security.util.*;3738/**39* A private key in PKCS#8 format for the Diffie-Hellman key agreement40* algorithm.41*42* @author Jan Luehe43*44*45* @see DHPublicKey46* @see java.security.KeyAgreement47*/48final class DHPrivateKey implements PrivateKey,49javax.crypto.interfaces.DHPrivateKey, Serializable {5051@java.io.Serial52static final long serialVersionUID = 7565477590005668886L;5354// only supported version of PKCS#8 PrivateKeyInfo55private static final BigInteger PKCS8_VERSION = BigInteger.ZERO;5657// the private key58private BigInteger x;5960// the key bytes, without the algorithm information61private byte[] key;6263// the encoded key64private byte[] encodedKey;6566// the prime modulus67private BigInteger p;6869// the base generator70private BigInteger g;7172// the private-value length (optional)73private int l;7475/**76* Make a DH private key out of a private value <code>x</code>, a prime77* modulus <code>p</code>, and a base generator <code>g</code>.78*79* @param x the private value80* @param p the prime modulus81* @param g the base generator82*83* @throws ProviderException if the key cannot be encoded84*/85DHPrivateKey(BigInteger x, BigInteger p, BigInteger g)86throws InvalidKeyException {87this(x, p, g, 0);88}8990/**91* Make a DH private key out of a private value <code>x</code>, a prime92* modulus <code>p</code>, a base generator <code>g</code>, and a93* private-value length <code>l</code>.94*95* @param x the private value96* @param p the prime modulus97* @param g the base generator98* @param l the private-value length99*100* @throws ProviderException if the key cannot be encoded101*/102DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) {103this.x = x;104this.p = p;105this.g = g;106this.l = l;107try {108byte[] xbytes = x.toByteArray();109DerValue val = new DerValue(DerValue.tag_Integer, xbytes);110this.key = val.toByteArray();111val.clear();112Arrays.fill(xbytes, (byte)0);113encode();114} catch (IOException e) {115throw new ProviderException("Cannot produce ASN.1 encoding", e);116}117}118119/**120* Make a DH private key from its DER encoding (PKCS #8).121*122* @param encodedKey the encoded key123*124* @throws InvalidKeyException if the encoded key does not represent125* a Diffie-Hellman private key126*/127DHPrivateKey(byte[] encodedKey) throws InvalidKeyException {128DerValue val = null;129try {130val = new DerValue(encodedKey);131if (val.tag != DerValue.tag_Sequence) {132throw new InvalidKeyException ("Key not a SEQUENCE");133}134135//136// version137//138BigInteger parsedVersion = val.data.getBigInteger();139if (!parsedVersion.equals(PKCS8_VERSION)) {140throw new IOException("version mismatch: (supported: " +141PKCS8_VERSION + ", parsed: " +142parsedVersion);143}144145//146// privateKeyAlgorithm147//148DerValue algid = val.data.getDerValue();149if (algid.tag != DerValue.tag_Sequence) {150throw new InvalidKeyException("AlgId is not a SEQUENCE");151}152DerInputStream derInStream = algid.toDerInputStream();153ObjectIdentifier oid = derInStream.getOID();154if (oid == null) {155throw new InvalidKeyException("Null OID");156}157if (derInStream.available() == 0) {158throw new InvalidKeyException("Parameters missing");159}160// parse the parameters161DerValue params = derInStream.getDerValue();162if (params.tag == DerValue.tag_Null) {163throw new InvalidKeyException("Null parameters");164}165if (params.tag != DerValue.tag_Sequence) {166throw new InvalidKeyException("Parameters not a SEQUENCE");167}168params.data.reset();169this.p = params.data.getBigInteger();170this.g = params.data.getBigInteger();171// Private-value length is OPTIONAL172if (params.data.available() != 0) {173this.l = params.data.getInteger();174}175if (params.data.available() != 0) {176throw new InvalidKeyException("Extra parameter data");177}178179//180// privateKey181//182this.key = val.data.getOctetString();183parseKeyBits();184185this.encodedKey = encodedKey.clone();186} catch (IOException | NumberFormatException e) {187throw new InvalidKeyException("Error parsing key encoding", e);188} finally {189if (val != null) {190val.clear();191}192}193}194195/**196* Returns the encoding format of this key: "PKCS#8"197*/198public String getFormat() {199return "PKCS#8";200}201202/**203* Returns the name of the algorithm associated with this key: "DH"204*/205public String getAlgorithm() {206return "DH";207}208209/**210* Get the encoding of the key.211*/212public synchronized byte[] getEncoded() {213encode();214return encodedKey.clone();215}216217/**218* Generate the encodedKey field if it has not been calculated.219* Could generate null.220*/221private void encode() {222if (this.encodedKey == null) {223try {224DerOutputStream tmp = new DerOutputStream();225226//227// version228//229tmp.putInteger(PKCS8_VERSION);230231//232// privateKeyAlgorithm233//234DerOutputStream algid = new DerOutputStream();235236// store OID237algid.putOID(DHPublicKey.DH_OID);238// encode parameters239DerOutputStream params = new DerOutputStream();240params.putInteger(this.p);241params.putInteger(this.g);242if (this.l != 0) {243params.putInteger(this.l);244}245// wrap parameters into SEQUENCE246DerValue paramSequence = new DerValue(DerValue.tag_Sequence,247params.toByteArray());248// store parameter SEQUENCE in algid249algid.putDerValue(paramSequence);250// wrap algid into SEQUENCE251tmp.write(DerValue.tag_Sequence, algid);252253// privateKey254tmp.putOctetString(this.key);255256// make it a SEQUENCE257DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);258this.encodedKey = val.toByteArray();259val.clear();260} catch (IOException e) {261throw new AssertionError(e);262}263}264}265266/**267* Returns the private value, <code>x</code>.268*269* @return the private value, <code>x</code>270*/271public BigInteger getX() {272return this.x;273}274275/**276* Returns the key parameters.277*278* @return the key parameters279*/280public DHParameterSpec getParams() {281if (this.l != 0) {282return new DHParameterSpec(this.p, this.g, this.l);283} else {284return new DHParameterSpec(this.p, this.g);285}286}287288private void parseKeyBits() throws InvalidKeyException {289try {290DerInputStream in = new DerInputStream(this.key);291this.x = in.getBigInteger();292} catch (IOException e) {293InvalidKeyException ike = new InvalidKeyException(294"Error parsing key encoding: " + e.getMessage());295ike.initCause(e);296throw ike;297}298}299300/**301* Calculates a hash code value for the object.302* Objects that are equal will also have the same hashcode.303*/304public int hashCode() {305return Objects.hash(x, p, g);306}307308public boolean equals(Object obj) {309if (this == obj) return true;310311if (!(obj instanceof javax.crypto.interfaces.DHPrivateKey)) {312return false;313}314javax.crypto.interfaces.DHPrivateKey other =315(javax.crypto.interfaces.DHPrivateKey) obj;316DHParameterSpec otherParams = other.getParams();317return ((this.x.compareTo(other.getX()) == 0) &&318(this.p.compareTo(otherParams.getP()) == 0) &&319(this.g.compareTo(otherParams.getG()) == 0));320}321322/**323* Replace the DH private key to be serialized.324*325* @return the standard KeyRep object to be serialized326*327* @throws java.io.ObjectStreamException if a new object representing328* this DH private key could not be created329*/330@java.io.Serial331private Object writeReplace() throws java.io.ObjectStreamException {332encode();333return new KeyRep(KeyRep.Type.PRIVATE,334getAlgorithm(),335getFormat(),336encodedKey);337}338}339340341