Search in sources :

Example 31 with X9ECParameters

use of org.openecard.bouncycastle.asn1.x9.X9ECParameters in project jmulticard by ctt-gob-es.

the class PaceChannelHelper method openPaceChannel.

/**
 * Abre un canal PACE.
 * @param cla Clase de APDU para los comandos de establecimiento de canal.
 * @param pi Valor de inicialización del canal. Puede ser un CAN
 *           (<i>Card Access Number</i>) o una MRZ (<i>Machine Readable Zone</i>).
 * @param conn Conexi&oacute;n hacia la tarjeta inteligente.
 * @param cryptoHelper Clase para la realizaci&oacute;n de operaciones criptogr&aacute;ficas auxiliares.
 * @return SecureMessaging Objeto para el env&iacute;o de mensajes seguros a trav&eacute;s de canal PACE.
 * @throws ApduConnectionException Si hay problemas de conexi&oacute;n con la tarjeta.
 * @throws PaceException Si hay problemas en la apertura del canal.
 */
public static SecureMessaging openPaceChannel(final byte cla, final PaceInitializer pi, final ApduConnection conn, final CryptoHelper cryptoHelper) throws ApduConnectionException, PaceException {
    if (conn == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "El canal de conexion no puede ser nulo");
    }
    if (pi == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "Es necesario proporcionar un inicializador para abrir canal PACE");
    }
    if (cryptoHelper == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "El CryptoHelper no puede ser nulo");
    }
    if (!conn.isOpen()) {
        conn.open();
    }
    ResponseApdu res;
    CommandApdu comm;
    // 1.3.2 - Establecemos el algoritmo para PACE con el comando MSE Set:
    comm = new MseSetPaceAlgorithmApduCommand(cla, MseSetPaceAlgorithmApduCommand.PaceAlgorithmOid.PACE_ECDH_GM_AES_CBC_CMAC128, pi.getPasswordType(), MseSetPaceAlgorithmApduCommand.PaceAlgorithmParam.BRAINPOOL_256_R1);
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error estableciendo el algoritmo del protocolo PACE.");
    }
    // 1.3.3 - Primer comando General Autenticate - Get Nonce
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, new byte[] { (byte) 0x7C, (byte) 0x00 });
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error solicitando el aleatorio de calculo PACE (Nonce)");
    }
    // Calcular nonce devuelto por la tarjeta que se empleara en los calculos
    final byte[] nonce;
    try {
        nonce = new Tlv(new Tlv(res.getData()).getValue()).getValue();
    } catch (final TlvException e) {
        throw new PaceException(// $NON-NLS-1$ //$NON-NLS-2$
        "El aleatorio de calculo PACE (Nonce) obtenido (" + HexUtils.hexify(res.getData(), true) + ") no sigue el formato esperado: " + e, // $NON-NLS-1$ //$NON-NLS-2$
        e);
    }
    // Calcular sk = SHA-1( CAN || 00000003 );
    // La clave son los 16 bytes MSB del hash
    final byte[] sk = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(pi.getBytes(), CAN_MRZ_PADDING)), 0, sk, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'sk' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Calcular secret = AES_Dec(nonce,sk);
    final byte[] secret_nonce;
    try {
        secret_nonce = cryptoHelper.aesDecrypt(nonce, new byte[0], sk);
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error descifranco el 'nonce': " + e, // $NON-NLS-1$
        e);
    }
    // 1.3.4 - Segundo comando General Autenticate - Map Nonce
    // Generamos un par de claves efimeras EC para el DH
    // $NON-NLS-1$
    final X9ECParameters ecdhParameters = TeleTrusTNamedCurves.getByName("brainpoolp256r1");
    final ECPoint pointG = ecdhParameters.getG();
    final Fp curve = (org.spongycastle.math.ec.ECCurve.Fp) ecdhParameters.getCurve();
    // La privada del terminal se genera aleatoriamente (PrkIFDDH1)
    // La publica de la tarjeta sera devuelta por ella misma al enviar nuesra publica (pukIFDDH1)
    final Random rnd = new Random();
    rnd.setSeed(rnd.nextLong());
    final byte[] x1 = new byte[curve.getFieldSize() / 8];
    rnd.nextBytes(x1);
    final BigInteger PrkIFDDH1 = new BigInteger(1, x1);
    // Enviamos nuestra clave publica (pukIFDDH1 = G*PrkIFDDH1)
    final ECPoint pukIFDDH1 = pointG.multiply(PrkIFDDH1);
    Tlv tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_2, pukIFDDH1.getEncoded(false)).getBytes());
    // ... Y la enviamos a la tarjeta
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, tlv.getBytes());
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error mapeando el aleatorio de calculo PACE (Nonce)");
    }
    // Se obtiene la clave publica de la tarjeta
    final byte[] pukIccDh1;
    try {
        pukIccDh1 = unwrapEcKey(res.getData());
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo la clave efimera EC publica de la tarjeta: " + e, // $NON-NLS-1$
        e);
    }
    // calcular blinding point H = PrkIFDDH1 * PukICCDH1
    final ECPoint y1FromG = byteArrayToECPoint(pukIccDh1, curve);
    // Calculamos el punto H secreto
    final ECPoint SharedSecret_H = y1FromG.multiply(PrkIFDDH1);
    // Se calcula el nuevo punto G' = nonce*G + H
    final BigInteger ms = new BigInteger(1, secret_nonce);
    final ECPoint g_temp = pointG.multiply(ms);
    final ECPoint newPointG = g_temp.add(SharedSecret_H);
    // 1.3.5 Tercer comando General Authenticate
    // Se calcula la coordenada X de G' y generamos con la tarjeta un nuevo acuerdo de claves
    // La privada del terminal se genera aleatoriamente (PrkIFDDH2)
    // La publica de la tarjeta sera devuelta por ella misma al enviar nuesra publica (pukIFDDH2)
    final byte[] x2 = new byte[curve.getFieldSize() / 8];
    rnd.setSeed(rnd.nextLong());
    rnd.nextBytes(x2);
    final BigInteger PrkIFDDH2 = new BigInteger(1, x2);
    // Enviamos nuestra clave publica (pukIFDDH2 = G'*PrkIFDDH2)
    final ECPoint pukIFDDH2 = newPointG.multiply(PrkIFDDH2);
    // ... La metemos en un TLV de autenticacion ...
    tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_3, pukIFDDH2.getEncoded(false)).getBytes());
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, tlv.getBytes());
    res = conn.transmit(comm);
    // Se obtiene la clave publica de la tarjeta (pukIccDh2) que es la coordenada Y del nuevo Punto G'
    final byte[] pukIccDh2;
    try {
        pukIccDh2 = unwrapEcKey(res.getData());
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo la clave efimera EC publica de la tarjeta: " + e, // $NON-NLS-1$
        e);
    }
    final ECPoint y2FromNewG = byteArrayToECPoint(pukIccDh2, curve);
    // Se calcula el secreto k = PukICCDH2 * PrkIFDDH2
    final ECPoint.Fp SharedSecret_K = (org.spongycastle.math.ec.ECPoint.Fp) y2FromNewG.multiply(PrkIFDDH2);
    final byte[] secretK = bigIntToByteArray(SharedSecret_K.normalize().getXCoord().toBigInteger());
    // 1.3.6 Cuarto comando General Authenticate
    // Se validan las claves de sesion generadas en el paso anterior,
    // por medio de un MAC que calcula el terminal y comprueba la tarjeta,
    // la cual devolvera un segundo MAC.
    // Calcular kenc = SHA-1( k || 00000001 );
    final byte[] kenc = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(secretK, KENC_PADDING)), 0, kenc, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'kenc' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Calcular kmac = SHA-1( k || 00000002 );
    final byte[] kmac = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(secretK, KMAC_PADDING)), 0, kmac, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'kmac' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Elimina el byte '04' del inicio que es el indicador de punto descomprimido
    final byte[] pukIccDh2Descompressed = new byte[pukIccDh2.length - 1];
    System.arraycopy(pukIccDh2, 1, pukIccDh2Descompressed, 0, pukIccDh2.length - 1);
    // Se calcula el Mac del terminal: data = '7f494F06' + oid + '864104' + PukICCDH2;
    final byte[] data = HexUtils.concatenateByteArrays(MAC_PADDING, HexUtils.concatenateByteArrays(MseSetPaceAlgorithmApduCommand.PaceAlgorithmOid.PACE_ECDH_GM_AES_CBC_CMAC128.getBytes(), HexUtils.concatenateByteArrays(MAC2_PADDING, pukIccDh2Descompressed)));
    byte[] mac8bytes;
    try {
        mac8bytes = cryptoHelper.doAesCmac(data, kmac);
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error descifrando el 'nonce': " + e, // $NON-NLS-1$
        e);
    }
    // ... La metemos en un TLV de autenticacion ...
    tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_4, mac8bytes).getBytes());
    // Se envia el comando General Authenticate y se recupera el MAC devuelto por la tarjeta.
    comm = new GeneralAuthenticateApduCommand((byte) 0x00, tlv.getBytes());
    res = conn.transmit(comm);
    // Se obtiene un MAC con respuesta 90-00 indicando que se ha establecido el canal correctamente
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error estableciendo el algoritmo del protocolo PACE.");
    }
    // Se inicializa el contador de secuencia a ceros
    final byte[] ssc = new byte[16];
    Arrays.fill(ssc, (byte) 0);
    // $NON-NLS-1$
    LOGGER.info("Canal Pace abierto");
    LOGGER.info(// $NON-NLS-1$
    "\nKenc: " + HexUtils.hexify(kenc, true) + "Kmac: " + // $NON-NLS-1$
    HexUtils.hexify(kmac, true) + "Ssc: " + // $NON-NLS-1$
    HexUtils.hexify(ssc, true));
    final AmCryptoProvider crypto = new AmAESCrypto();
    return new SecureMessaging(crypto, kenc, kmac, new byte[crypto.getBlockSize()]);
}
Also used : CommandApdu(es.gob.jmulticard.apdu.CommandApdu) SecureMessaging(es.gob.jmulticard.de.tsenger.androsmex.iso7816.SecureMessaging) AmAESCrypto(es.gob.jmulticard.de.tsenger.androsmex.crypto.AmAESCrypto) X9ECParameters(org.spongycastle.asn1.x9.X9ECParameters) ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu) Fp(org.spongycastle.math.ec.ECCurve.Fp) IOException(java.io.IOException) ECPoint(org.spongycastle.math.ec.ECPoint) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) IOException(java.io.IOException) TlvException(es.gob.jmulticard.asn1.TlvException) AmCryptoProvider(es.gob.jmulticard.de.tsenger.androsmex.crypto.AmCryptoProvider) TlvException(es.gob.jmulticard.asn1.TlvException) Random(java.util.Random) MseSetPaceAlgorithmApduCommand(es.gob.jmulticard.apdu.iso7816four.pace.MseSetPaceAlgorithmApduCommand) GeneralAuthenticateApduCommand(es.gob.jmulticard.apdu.iso7816four.GeneralAuthenticateApduCommand) BigInteger(java.math.BigInteger) Tlv(es.gob.jmulticard.asn1.Tlv)

Example 32 with X9ECParameters

use of org.openecard.bouncycastle.asn1.x9.X9ECParameters in project open-ecard by ecsec.

the class ExplicitDomainParameters method loadECDHParameter.

private void loadECDHParameter(ASN1Sequence seq) {
    // ASN1Integer version = (ASN1Integer) seq.getObjectAt(0);
    // ASN1Sequence modulus = (ASN1Sequence) seq.getObjectAt(1);
    // ASN1Sequence coefficient = (ASN1Sequence) seq.getObjectAt(2);
    // ASN1OctetString basepoint = (ASN1OctetString) seq.getObjectAt(3);
    ASN1Integer order = (ASN1Integer) seq.getObjectAt(4);
    ASN1Integer cofactor = (ASN1Integer) seq.getObjectAt(5);
    try {
        // BigInteger p = new BigInteger(modulus.getObjectAt(1).toASN1Primitive().getEncoded());
        // BigInteger a = new BigInteger(coefficient.getObjectAt(0).toASN1Primitive().getEncoded());
        // BigInteger b = new BigInteger(coefficient.getObjectAt(1).toASN1Primitive().getEncoded());
        BigInteger r = order.getValue();
        BigInteger f = cofactor.getValue();
        X9ECParameters ECParameters = X9ECParameters.getInstance(seq);
        ECCurve curve = ECParameters.getCurve();
        domainParameter = new ECParameterSpec(curve, ECParameters.getG(), r, f);
    } catch (Exception e) {
        _logger.error("Failed to load proprietary domain parameters", e);
    }
}
Also used : X9ECParameters(org.openecard.bouncycastle.asn1.x9.X9ECParameters) ECParameterSpec(org.openecard.bouncycastle.jce.spec.ECParameterSpec) ECCurve(org.openecard.bouncycastle.math.ec.ECCurve) BigInteger(java.math.BigInteger) ASN1Integer(org.openecard.bouncycastle.asn1.ASN1Integer)

Aggregations

X9ECParameters (org.bouncycastle.asn1.x9.X9ECParameters)29 X962Parameters (org.bouncycastle.asn1.x9.X962Parameters)16 IOException (java.io.IOException)14 ASN1ObjectIdentifier (org.bouncycastle.asn1.ASN1ObjectIdentifier)12 ECNamedCurveSpec (org.bouncycastle.jce.spec.ECNamedCurveSpec)12 ECCurve (org.bouncycastle.math.ec.ECCurve)11 AlgorithmIdentifier (org.bouncycastle.asn1.x509.AlgorithmIdentifier)10 BigInteger (java.math.BigInteger)9 ASN1OctetString (org.bouncycastle.asn1.ASN1OctetString)8 DERObjectIdentifier (org.bouncycastle.asn1.DERObjectIdentifier)8 X9ECPoint (org.bouncycastle.asn1.x9.X9ECPoint)8 ASN1Encodable (org.bouncycastle.asn1.ASN1Encodable)7 ECParameterSpec (java.security.spec.ECParameterSpec)6 ECPoint (java.security.spec.ECPoint)6 EllipticCurve (java.security.spec.EllipticCurve)6 ASN1Integer (org.bouncycastle.asn1.ASN1Integer)6 ECDomainParameters (org.bouncycastle.crypto.params.ECDomainParameters)6 DERInteger (org.bouncycastle.asn1.DERInteger)5 PrivateKeyInfo (org.bouncycastle.asn1.pkcs.PrivateKeyInfo)5 ECPrivateKeyStructure (org.bouncycastle.asn1.sec.ECPrivateKeyStructure)5