/****************************************************************************
* 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.ifd.protocol.pace.crypto;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.openecard.bouncycastle.jce.spec.ECParameterSpec;
import org.openecard.bouncycastle.math.ec.ECPoint;
import org.openecard.common.util.ByteUtils;
import org.openecard.crypto.common.asn1.eac.PACEDomainParameter;
import org.openecard.crypto.common.asn1.eac.PACESecurityInfos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de>
*/
public final class PACECryptoSuite {
private static final Logger logger = LoggerFactory.getLogger(PACECryptoSuite.class.getName());
private PACESecurityInfos psi;
private PACEDomainParameter domainParameter;
/**
* Create a new crypto suite for PACE.
*
* @param psi PACESecurityInfos
* @param pdp PACEDomainParameter
* @throws GeneralSecurityException
*/
public PACECryptoSuite(PACESecurityInfos psi, PACEDomainParameter pdp) throws GeneralSecurityException {
this.psi = psi;
this.domainParameter = pdp;
}
/**
* Decrypt nonce.
*
* @param keyData Key (Key_PI)
* @param nonceData Nonce
* @return Decrypted nonce
* @throws GeneralSecurityException
*/
public byte[] decryptNonce(byte[] keyData, byte[] nonceData) throws GeneralSecurityException {
byte[] ret = new byte[16];
byte[] nonce = ByteUtils.copy(nonceData, 4, nonceData.length - 4);
try {
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec skeySpec = new SecretKeySpec(keyData, "AES");
IvParameterSpec params = new IvParameterSpec(new byte[16]);
c.init(Cipher.DECRYPT_MODE, skeySpec, params);
c.doFinal(nonce, 0, nonce.length, ret);
} catch (Throwable e) {
logger.error(e.getMessage(), e);
throw new GeneralSecurityException(e);
}
return ret;
}
/**
* Perform an Diffie-Hellman key agreement.
*
* @param sk Secret key
* @param pk Public key
* @return Shared secret k
*/
public byte[] generateSharedSecret(byte[] sk, byte[] pk) {
if (domainParameter.isDH()) {
throw new UnsupportedOperationException("Not implemented yet!");
} else if (domainParameter.isECDH()) {
ECParameterSpec p = (ECParameterSpec) domainParameter.getParameter();
if (p.getH().intValue() == 1) {
BigInteger d = new BigInteger(1, sk);
ECPoint q = p.getCurve().decodePoint(pk);
ECPoint k = q.multiply(d);
return ByteUtils.cutLeadingNullBytes(k.getX().toBigInteger().toByteArray());
} else {
throw new UnsupportedOperationException("Not implemented yet!");
}
} else {
throw new IllegalArgumentException();
}
}
/**
* Return the mapping algorithm for PACE.
*
* @return PACE mapping
*/
public PACEMapping getMapping() {
if (psi.getPACEInfo().isGM()) {
return new PACEGenericMapping(domainParameter);
} else if (psi.getPACEInfo().isIM()) {
return new PACEIntegratedMapping(domainParameter);
} else {
throw new IllegalArgumentException();
}
}
}