package de.persosim.simulator.protocols.pace;
import static org.globaltester.logging.BasicLogger.TRACE;
import static org.globaltester.logging.BasicLogger.log;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import de.persosim.simulator.crypto.CryptoUtil;
import de.persosim.simulator.crypto.DomainParameterSet;
import de.persosim.simulator.crypto.DomainParameterSetEcdh;
import de.persosim.simulator.utils.HexString;
import de.persosim.simulator.utils.Utils;
/**
* This class performs the ECDH specific parts of generic mapping.
*
* @author slutters
*
*/
public class GenericMappingEcdh extends GenericMapping {
/* (non-Javadoc)
*
* The common secret as generated by the key agreement must be encoded as follows.
* In case of ECDH: encoding according to ANSI X9.62
* i.e. "0x04|unsigned x-coordinate|unsigned y-coordinate" for uncompressed encoding
*/
@Override
public DomainParameterSet performMappingOfDomainParameters(DomainParameterSet domainParameterSetUnMapped, byte[] nonceS, byte[] secretOfKeyAgreement) {
if(!(domainParameterSetUnMapped instanceof DomainParameterSetEcdh)) {throw new IllegalArgumentException("domain parameters must be ECDH");};
BigInteger sNonceBigInt = new BigInteger(1, nonceS);
DomainParameterSetEcdh domainParameterSetEcdhUnMapped = (DomainParameterSetEcdh) domainParameterSetUnMapped;
ECPoint h = DomainParameterSetEcdh.reconstructPoint(secretOfKeyAgreement);
EllipticCurve curve = domainParameterSetEcdhUnMapped.getCurve();
ECPoint gUnMapped = domainParameterSetEcdhUnMapped.getGenerator();
log(this.getClass(), "gUnMapped x: " + HexString.encode(Utils.toUnsignedByteArray(gUnMapped.getAffineX())));
log(this.getClass(), "gUnMapped y: " + HexString.encode(Utils.toUnsignedByteArray(gUnMapped.getAffineY())));
log(this.getClass(), "nonce S: " + HexString.encode(nonceS));
ECPoint gspm = CryptoUtil.scalarPointMultiplication(curve, domainParameterSetEcdhUnMapped.getOrder(), gUnMapped, sNonceBigInt);
log(this.getClass(), "gspm x: " + HexString.encode(Utils.toUnsignedByteArray(gspm.getAffineX())));
log(this.getClass(), "gspm y: " + HexString.encode(Utils.toUnsignedByteArray(gspm.getAffineY())));
ECPoint gMapped = CryptoUtil.addPoint(curve, gspm, h);
DomainParameterSetEcdh domainParametersMapped = domainParameterSetEcdhUnMapped.getUpdatedDomainParameterSet(gMapped);
return domainParametersMapped;
}
@Override
public String getMappingName() {
return super.getMappingName() + " with ECDH key agreement";
}
@Override
public byte[] performKeyAgreement(DomainParameterSet domainParameters, PrivateKey privKeyPicc, PublicKey pubKeyPcd) {
DomainParameterSetEcdh domainParameterSetEcdh = (DomainParameterSetEcdh) domainParameters;
ECPrivateKey ecPrivateKeyPicc = (ECPrivateKey) privKeyPicc;
ECPublicKey ecPublicKeyPcd = (ECPublicKey) pubKeyPcd;
ECPoint secretPoint = domainParameterSetEcdh.performEcdhKeyAgreement(ecPublicKeyPcd, ecPrivateKeyPicc);
log(GenericMappingEcdh.class, "result H of ECDH key agreement is", TRACE);
log(GenericMappingEcdh.class, "H.x: " + HexString.encode(secretPoint.getAffineX()), TRACE);
log(GenericMappingEcdh.class, "H.y: " + HexString.encode(secretPoint.getAffineY()), TRACE);
byte[] encodedPoint = CryptoUtil.encode(secretPoint, domainParameterSetEcdh.getPublicPointReferenceLengthL(), CryptoUtil.ENCODING_UNCOMPRESSED);
log(GenericMappingEcdh.class, "H uncompressed encoding: " + HexString.encode(encodedPoint), TRACE);
return encodedPoint;
}
@Override
public String getMeaningOfMappingData() {
return "PCD's ECDH public key point";
}
}