package net.i2p.crypto.elgamal.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPrivateKeySpec;
import static net.i2p.crypto.SigUtil.intToASN1;
import net.i2p.crypto.elgamal.ElGamalPrivateKey;
import static net.i2p.crypto.elgamal.impl.ElGamalPublicKeyImpl.spaceFor;
import net.i2p.crypto.elgamal.spec.ElGamalParameterSpec;
import net.i2p.crypto.elgamal.spec.ElGamalPrivateKeySpec;
public class ElGamalPrivateKeyImpl
implements ElGamalPrivateKey, DHPrivateKey
{
private static final long serialVersionUID = 4819350091141529678L;
private BigInteger x;
private ElGamalParameterSpec elSpec;
protected ElGamalPrivateKeyImpl()
{
}
public ElGamalPrivateKeyImpl(
ElGamalPrivateKey key)
{
this.x = key.getX();
this.elSpec = key.getParameters();
}
public ElGamalPrivateKeyImpl(
DHPrivateKey key)
{
this.x = key.getX();
this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG());
}
public ElGamalPrivateKeyImpl(
ElGamalPrivateKeySpec spec)
{
this.x = spec.getX();
this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG());
}
public ElGamalPrivateKeyImpl(
DHPrivateKeySpec spec)
{
this.x = spec.getX();
this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
}
public ElGamalPrivateKeyImpl(
BigInteger x,
ElGamalParameterSpec elSpec)
{
this.x = x;
this.elSpec = elSpec;
}
public ElGamalPrivateKeyImpl(
PKCS8EncodedKeySpec spec)
{
throw new UnsupportedOperationException("todo");
//this.x = spec.getX();
//this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
}
public String getAlgorithm()
{
return "ElGamal";
}
/**
* return the encoding format we produce in getEncoded().
*
* @return the string "PKCS#8"
*/
public String getFormat()
{
return "PKCS#8";
}
/**
* Return a PKCS8 representation of the key. The sequence returned
* represents a full PrivateKeyInfo object.
*
* @return a PKCS8 representation of the key.
*/
public byte[] getEncoded()
{
byte[] pb = elSpec.getP().toByteArray();
byte[] gb = elSpec.getG().toByteArray();
byte[] xb = x.toByteArray();
int seq3len = spaceFor(pb.length) + spaceFor(gb.length);
int seq2len = 8 + spaceFor(seq3len);
int seq1len = 3 + spaceFor(seq2len) + spaceFor(xb.length);
int totlen = spaceFor(seq1len);
byte[] rv = new byte[totlen];
int idx = 0;
// sequence 1
rv[idx++] = 0x30;
idx = intToASN1(rv, idx, seq1len);
// version
rv[idx++] = 0x02;
rv[idx++] = 1;
rv[idx++] = 0;
// Algorithm Identifier
// sequence 2
rv[idx++] = 0x30;
idx = intToASN1(rv, idx, seq2len);
// OID: 1.3.14.7.2.1.1
rv[idx++] = 0x06;
rv[idx++] = 6;
rv[idx++] = (1 * 40) + 3;
rv[idx++] = 14;
rv[idx++] = 7;
rv[idx++] = 2;
rv[idx++] = 1;
rv[idx++] = 1;
// params
// sequence 3
rv[idx++] = 0x30;
idx = intToASN1(rv, idx, seq3len);
// P
// integer
rv[idx++] = 0x02;
idx = intToASN1(rv, idx, pb.length);
System.arraycopy(pb, 0, rv, idx, pb.length);
idx += pb.length;
// G
// integer
rv[idx++] = 0x02;
idx = intToASN1(rv, idx, gb.length);
System.arraycopy(gb, 0, rv, idx, gb.length);
idx += gb.length;
// the key
// octet string
rv[idx++] = 0x04;
idx = intToASN1(rv, idx, xb.length);
// BC puts an integer in the bit string, we're not going to do that
System.arraycopy(xb, 0, rv, idx, xb.length);
return rv;
}
public ElGamalParameterSpec getParameters()
{
return elSpec;
}
public DHParameterSpec getParams()
{
return new DHParameterSpec(elSpec.getP(), elSpec.getG());
}
public BigInteger getX()
{
return x;
}
private void readObject(
ObjectInputStream in)
throws IOException, ClassNotFoundException
{
x = (BigInteger)in.readObject();
this.elSpec = new ElGamalParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject());
}
private void writeObject(
ObjectOutputStream out)
throws IOException
{
out.writeObject(this.getX());
out.writeObject(elSpec.getP());
out.writeObject(elSpec.getG());
}
}