|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.crypto.provider; |
|
|
|
import java.io.*; |
|
import java.util.Arrays; |
|
import java.util.Objects; |
|
import java.math.BigInteger; |
|
import java.security.KeyRep; |
|
import java.security.PrivateKey; |
|
import java.security.InvalidKeyException; |
|
import java.security.ProviderException; |
|
import javax.crypto.spec.DHParameterSpec; |
|
import sun.security.util.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final class DHPrivateKey implements PrivateKey, |
|
javax.crypto.interfaces.DHPrivateKey, Serializable { |
|
|
|
@java.io.Serial |
|
static final long serialVersionUID = 7565477590005668886L; |
|
|
|
|
|
private static final BigInteger PKCS8_VERSION = BigInteger.ZERO; |
|
|
|
|
|
private BigInteger x; |
|
|
|
|
|
private byte[] key; |
|
|
|
|
|
private byte[] encodedKey; |
|
|
|
|
|
private BigInteger p; |
|
|
|
|
|
private BigInteger g; |
|
|
|
|
|
private int l; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
DHPrivateKey(BigInteger x, BigInteger p, BigInteger g) |
|
throws InvalidKeyException { |
|
this(x, p, g, 0); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
DHPrivateKey(BigInteger x, BigInteger p, BigInteger g, int l) { |
|
this.x = x; |
|
this.p = p; |
|
this.g = g; |
|
this.l = l; |
|
try { |
|
byte[] xbytes = x.toByteArray(); |
|
DerValue val = new DerValue(DerValue.tag_Integer, xbytes); |
|
this.key = val.toByteArray(); |
|
val.clear(); |
|
Arrays.fill(xbytes, (byte)0); |
|
encode(); |
|
} catch (IOException e) { |
|
throw new ProviderException("Cannot produce ASN.1 encoding", e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
DHPrivateKey(byte[] encodedKey) throws InvalidKeyException { |
|
DerValue val = null; |
|
try { |
|
val = new DerValue(encodedKey); |
|
if (val.tag != DerValue.tag_Sequence) { |
|
throw new InvalidKeyException ("Key not a SEQUENCE"); |
|
} |
|
|
|
// |
|
// version |
|
|
|
BigInteger parsedVersion = val.data.getBigInteger(); |
|
if (!parsedVersion.equals(PKCS8_VERSION)) { |
|
throw new IOException("version mismatch: (supported: " + |
|
PKCS8_VERSION + ", parsed: " + |
|
parsedVersion); |
|
} |
|
|
|
// |
|
// privateKeyAlgorithm |
|
|
|
DerValue algid = val.data.getDerValue(); |
|
if (algid.tag != DerValue.tag_Sequence) { |
|
throw new InvalidKeyException("AlgId is not a SEQUENCE"); |
|
} |
|
DerInputStream derInStream = algid.toDerInputStream(); |
|
ObjectIdentifier oid = derInStream.getOID(); |
|
if (oid == null) { |
|
throw new InvalidKeyException("Null OID"); |
|
} |
|
if (derInStream.available() == 0) { |
|
throw new InvalidKeyException("Parameters missing"); |
|
} |
|
|
|
DerValue params = derInStream.getDerValue(); |
|
if (params.tag == DerValue.tag_Null) { |
|
throw new InvalidKeyException("Null parameters"); |
|
} |
|
if (params.tag != DerValue.tag_Sequence) { |
|
throw new InvalidKeyException("Parameters not a SEQUENCE"); |
|
} |
|
params.data.reset(); |
|
this.p = params.data.getBigInteger(); |
|
this.g = params.data.getBigInteger(); |
|
|
|
if (params.data.available() != 0) { |
|
this.l = params.data.getInteger(); |
|
} |
|
if (params.data.available() != 0) { |
|
throw new InvalidKeyException("Extra parameter data"); |
|
} |
|
|
|
// |
|
// privateKey |
|
|
|
this.key = val.data.getOctetString(); |
|
parseKeyBits(); |
|
|
|
this.encodedKey = encodedKey.clone(); |
|
} catch (IOException | NumberFormatException e) { |
|
throw new InvalidKeyException("Error parsing key encoding", e); |
|
} finally { |
|
if (val != null) { |
|
val.clear(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String getFormat() { |
|
return "PKCS#8"; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String getAlgorithm() { |
|
return "DH"; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public synchronized byte[] getEncoded() { |
|
encode(); |
|
return encodedKey.clone(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void encode() { |
|
if (this.encodedKey == null) { |
|
try { |
|
DerOutputStream tmp = new DerOutputStream(); |
|
|
|
// |
|
// version |
|
|
|
tmp.putInteger(PKCS8_VERSION); |
|
|
|
// |
|
// privateKeyAlgorithm |
|
|
|
DerOutputStream algid = new DerOutputStream(); |
|
|
|
|
|
algid.putOID(DHPublicKey.DH_OID); |
|
|
|
DerOutputStream params = new DerOutputStream(); |
|
params.putInteger(this.p); |
|
params.putInteger(this.g); |
|
if (this.l != 0) { |
|
params.putInteger(this.l); |
|
} |
|
|
|
DerValue paramSequence = new DerValue(DerValue.tag_Sequence, |
|
params.toByteArray()); |
|
|
|
algid.putDerValue(paramSequence); |
|
|
|
tmp.write(DerValue.tag_Sequence, algid); |
|
|
|
|
|
tmp.putOctetString(this.key); |
|
|
|
|
|
DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp); |
|
this.encodedKey = val.toByteArray(); |
|
val.clear(); |
|
} catch (IOException e) { |
|
throw new AssertionError(e); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BigInteger getX() { |
|
return this.x; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DHParameterSpec getParams() { |
|
if (this.l != 0) { |
|
return new DHParameterSpec(this.p, this.g, this.l); |
|
} else { |
|
return new DHParameterSpec(this.p, this.g); |
|
} |
|
} |
|
|
|
private void parseKeyBits() throws InvalidKeyException { |
|
try { |
|
DerInputStream in = new DerInputStream(this.key); |
|
this.x = in.getBigInteger(); |
|
} catch (IOException e) { |
|
InvalidKeyException ike = new InvalidKeyException( |
|
"Error parsing key encoding: " + e.getMessage()); |
|
ike.initCause(e); |
|
throw ike; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public int hashCode() { |
|
return Objects.hash(x, p, g); |
|
} |
|
|
|
public boolean equals(Object obj) { |
|
if (this == obj) return true; |
|
|
|
if (!(obj instanceof javax.crypto.interfaces.DHPrivateKey)) { |
|
return false; |
|
} |
|
javax.crypto.interfaces.DHPrivateKey other = |
|
(javax.crypto.interfaces.DHPrivateKey) obj; |
|
DHParameterSpec otherParams = other.getParams(); |
|
return ((this.x.compareTo(other.getX()) == 0) && |
|
(this.p.compareTo(otherParams.getP()) == 0) && |
|
(this.g.compareTo(otherParams.getG()) == 0)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@java.io.Serial |
|
private Object writeReplace() throws java.io.ObjectStreamException { |
|
encode(); |
|
return new KeyRep(KeyRep.Type.PRIVATE, |
|
getAlgorithm(), |
|
getFormat(), |
|
encodedKey); |
|
} |
|
} |