/****************************************************************************
* Copyright (C) 2012 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.sal.protocol.eac.crypto;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import org.openecard.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.openecard.bouncycastle.crypto.params.ECDomainParameters;
import org.openecard.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.openecard.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.openecard.bouncycastle.crypto.params.ElGamalParameters;
import org.openecard.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
import org.openecard.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
import org.openecard.bouncycastle.jce.spec.ECParameterSpec;
import org.openecard.bouncycastle.jce.spec.ElGamalParameterSpec;
import org.openecard.bouncycastle.math.ec.ECPoint;
import org.openecard.common.tlv.TLV;
import org.openecard.common.util.ByteUtils;
import org.openecard.crypto.common.asn1.eac.CADomainParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implements an abstract key for chip authentication.
*
* @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de>
*/
public final class CAKey {
private static final Logger logger = LoggerFactory.getLogger(CAKey.class);
private AsymmetricKeyParameter sk;
private AsymmetricKeyParameter pk;
private CADomainParameter cdp;
/**
* Creates a new key for CA.
*
* @param cdp CADomainParameter
*/
public CAKey(CADomainParameter cdp) {
this.cdp = cdp;
}
/**
* Decodes a public key from a byte array.
*
* @param data Encoded key
* @return Decoded key
* @throws Exception
*/
public byte[] decodePublicKey(byte[] data) throws Exception {
byte[] keyBytes;
if (data[0] == (byte) 0x7C) {
keyBytes = TLV.fromBER(data).getChild().getValue();
} else if (data[0] != 04) {
keyBytes = ByteUtils.concatenate((byte) 0x04, data);
} else {
keyBytes = data;
}
if (cdp.isECDH()) {
ECParameterSpec p = (ECParameterSpec) cdp.getParameter();
ECDomainParameters ecp = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH());
ECPoint q = p.getCurve().decodePoint(keyBytes);
pk = new ECPublicKeyParameters(q, ecp);
return getEncodedPublicKey();
} else if (cdp.isDH()) {
//TODO
logger.error("Not implemented yet.");
throw new UnsupportedOperationException("Not implemented yet.");
} else {
throw new IllegalArgumentException();
}
}
/**
* Generate a key pair.
*/
public void generateKeyPair() {
if (cdp.isDH()) {
ElGamalParameterSpec p = (ElGamalParameterSpec) cdp.getParameter();
int numBits = p.getG().bitLength();
BigInteger d = new BigInteger(numBits, new SecureRandom());
ElGamalParameters egp = new ElGamalParameters(p.getP(), p.getG());
sk = new ElGamalPrivateKeyParameters(d, egp);
pk = new ElGamalPublicKeyParameters(egp.getG().multiply(d), egp);
} else if (cdp.isECDH()) {
ECParameterSpec p = (ECParameterSpec) cdp.getParameter();
int numBits = p.getN().bitLength();
BigInteger d = new BigInteger(numBits, new SecureRandom());
ECDomainParameters ecp = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH());
sk = new ECPrivateKeyParameters(d, ecp);
pk = new ECPublicKeyParameters(ecp.getG().multiply(d), ecp);
} else {
throw new IllegalArgumentException();
}
}
/**
* Returns the public key.
*
* @return Public key
*/
public AsymmetricKeyParameter getPublicKey() {
return pk;
}
/**
* Returns the byte encoded public key.
*
* @return Public key
*/
public byte[] getEncodedPublicKey() {
if (cdp.isDH()) {
return ((ElGamalPublicKeyParameters) pk).getY().toByteArray();
} else if (cdp.isECDH()) {
return ((ECPublicKeyParameters) pk).getQ().getEncoded();
} else {
throw new IllegalArgumentException();
}
}
/**
* Returns the byte encoded compressed public key.
*
* @return Public key
*/
public byte[] getEncodedCompressedPublicKey() {
if (cdp.isDH()) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] input = ((ElGamalPublicKeyParameters) pk).getY().toByteArray();
byte[] compKey = md.digest(input);
return compKey;
} catch (NoSuchAlgorithmException e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
} else if (cdp.isECDH()) {
byte[] compKey = ((ECPublicKeyParameters) pk).getQ().getX().toBigInteger().toByteArray();
return ByteUtils.cutLeadingNullByte(compKey);
} else {
throw new IllegalArgumentException();
}
}
/**
* Returns the private key.
*
* @return Private key
*/
public AsymmetricKeyParameter getPrivateKey() {
return sk;
}
/**
* Returns the byte encoded private key.
*
* @return Private key
*/
public byte[] getEncodedPrivateKey() {
if (cdp.isDH()) {
return ((ElGamalPrivateKeyParameters) sk).getX().toByteArray();
} else if (cdp.isECDH()) {
return ((ECPrivateKeyParameters) sk).getD().toByteArray();
} else {
throw new IllegalArgumentException();
}
}
}