de.tsenger.animamea.pace.PaceOperator.java Source code

Java tutorial

Introduction

Here is the source code for de.tsenger.animamea.pace.PaceOperator.java

Source

/**
 *  Copyright 2011, Tobias Senger
 *  
 *  This file is part of animamea.
 *
 *  Animamea is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Animamea is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License   
 *  along with animamea.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.tsenger.animamea.pace;

import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_GM;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_GM_3DES_CBC_CBC;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_GM_AES_CBC_CMAC_128;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_GM_AES_CBC_CMAC_192;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_GM_AES_CBC_CMAC_256;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_IM;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_IM_3DES_CBC_CBC;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_IM_AES_CBC_CMAC_128;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_IM_AES_CBC_CMAC_192;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_DH_IM_AES_CBC_CMAC_256;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_GM;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_GM_3DES_CBC_CBC;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_GM_AES_CBC_CMAC_128;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_GM_AES_CBC_CMAC_192;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_GM_AES_CBC_CMAC_256;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_IM;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_IM_3DES_CBC_CBC;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_IM_AES_CBC_CMAC_128;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_IM_AES_CBC_CMAC_192;
import static de.tsenger.animamea.asn1.BSIObjectIdentifiers.id_PACE_ECDH_IM_AES_CBC_CMAC_256;

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.spec.DHPublicKeySpec;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECCurve.Fp;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;

import de.tsenger.animamea.AmCardHandler;
import de.tsenger.animamea.asn1.AmDHPublicKey;
import de.tsenger.animamea.asn1.AmECPublicKey;
import de.tsenger.animamea.asn1.BSIObjectIdentifiers;
import de.tsenger.animamea.asn1.DomainParameter;
import de.tsenger.animamea.asn1.DynamicAuthenticationData;
import de.tsenger.animamea.asn1.PaceDomainParameterInfo;
import de.tsenger.animamea.asn1.PaceInfo;
import de.tsenger.animamea.crypto.AmAESCrypto;
import de.tsenger.animamea.crypto.AmCryptoProvider;
import de.tsenger.animamea.crypto.AmDESCrypto;
import de.tsenger.animamea.crypto.KeyDerivationFunction;
import de.tsenger.animamea.iso7816.MSESetAT;
import de.tsenger.animamea.iso7816.SecureMessaging;
import de.tsenger.animamea.iso7816.SecureMessagingException;
import de.tsenger.animamea.tools.Converter;
import de.tsenger.animamea.tools.HexString;

/**
 * PaceOperator stellt Methoden zur Durchfhrung des PACE-Protokolls zur Verfgung
 * 
 * @author Tobias Senger (tobias@t-senger.de)
 * 
 */

public class PaceOperator {

    private Pace pace = null;
    private AmCryptoProvider crypto = null;
    private AmCardHandler cardHandler = null;
    private int passwordRef = 0;
    private byte[] passwordBytes = null;
    private String protocolOIDString = null;
    private int keyLength = 0;
    private int terminalType = 0;
    private byte[] pk_picc = null;
    private DomainParameter dp = null;

    static Logger logger = Logger.getLogger(PaceOperator.class);

    /** 
     * Konstruktor
     * @param ch AmCardHandler-Instanz ber welches die Kartenkommandos gesendet werden.
     */
    public PaceOperator(AmCardHandler ch) {
        cardHandler = ch;
    }

    /**
     * Initialisiert PACE mit standardisierten Domain Parametern.
     * 
     * @param pi PACEInfo enthlt die Crypto-Information zur Durchfhrung von PACE
     * @param password Das Password welches fr PACE verwendet werden soll
     * @param pwRef Typ des Passwort (1=MRZ, 2=CAN, 3=PIN, 4=PUK). MRZ must encoded as: (SerialNumber||Date of Birth+Checksum||Date of Expiry+Checksum)
     * @param terminalRef Rolle des Terminals laut BSI TR-03110 (1=IS, 2=AT, 3=ST, 0=unauthenticated terminal)
     */
    public void setAuthTemplate(PaceInfo pi, String password, int pwRef, int terminalRef) {

        protocolOIDString = pi.getProtocolOID();
        passwordRef = pwRef;
        terminalType = terminalRef;

        if (passwordRef == 1)
            passwordBytes = calcSHA1(password.getBytes());
        else
            passwordBytes = password.getBytes();

        dp = new DomainParameter(pi.getParameterId());

        if (protocolOIDString.startsWith(id_PACE_DH_GM.toString())
                || protocolOIDString.startsWith(id_PACE_DH_IM.toString()))
            pace = new PaceDH(dp.getDHParameter());
        else if (protocolOIDString.startsWith(id_PACE_ECDH_GM.toString())
                || protocolOIDString.startsWith(id_PACE_ECDH_IM.toString()))
            pace = new PaceECDH(dp.getECParameter());

        getCryptoInformation(pi);
    }

    /**
     * Initialisiert PACE mit properitren Domain Parametern.
     * 
     * @param pi PACEInfo enthlt alle Crypto-Information zur Durchfhrung von PACE
     * @param pdpi Enthlt die properitren Domain Parameter fr PACE
     * @param password Das Password welches fr PACE verwendet werden soll
     * @param pwRef Typ des Passwort (1=MRZ, 2=CAN, 3=PIN, 4=PUK). MRZ must encoded as: (SerialNumber||Date of Birth+Checksum||Date of Expiry+Checksum)
     * @param terminalRef Rolle des Terminals laut BSI TR-03110 (1=IS, 2=AT, 3=ST)
     * @throws PaceException 
     */
    public void setAuthTemplate(PaceInfo pi, PaceDomainParameterInfo pdpi, String password, int pwRef,
            int terminalRef) throws PaceException {

        protocolOIDString = pi.getProtocolOID();
        passwordRef = pwRef;
        terminalType = terminalRef;

        if (pi.getParameterId() >= 0 && pi.getParameterId() <= 31)
            throw new IllegalArgumentException(
                    "ParameterID number 0 to 31 is used for standardized domain parameters!");
        if (pi.getParameterId() != pdpi.getParameterId())
            throw new IllegalArgumentException("PaceInfo doesn't match the PaceDomainParameterInfo");

        if (pwRef == 1)
            passwordBytes = calcSHA1(password.getBytes());
        else
            passwordBytes = password.getBytes();

        getProprietaryDomainParameters(pdpi);

        if (protocolOIDString.startsWith(id_PACE_DH_GM.toString())
                || protocolOIDString.startsWith(id_PACE_DH_IM.toString()))
            pace = new PaceDH(dp.getDHParameter());
        else if (protocolOIDString.startsWith(id_PACE_ECDH_GM.toString())
                || protocolOIDString.startsWith(id_PACE_ECDH_IM.toString()))
            pace = new PaceECDH(dp.getECParameter());

        getCryptoInformation(pi);
    }

    /**
     * Fhrt alle Schritte des PACE-Protokolls durch und liefert bei Erfolg 
     * eine mit den ausgehandelten Schlsseln intialisierte SecureMessaging-Instanz zurck.
     * 
     * @return Bei Erfolg von PACE wird eine mit den ausgehandelten Schlsseln 
     *          intialisierte SecureMessaging-Instanz zurckgegeben. Anderfalls <code>null</code>.
     * @throws PaceException 
     * @throws CardException 
     * @throws SecureMessagingException 
     */
    public SecureMessaging performPace() throws PaceException, SecureMessagingException, CardException {

        // send MSE:SetAT
        int resp = sendMSESetAT(terminalType).getSW();
        if (resp != 0x9000)
            throw new PaceException("MSE:Set AT failed. SW: " + Integer.toHexString(resp));

        // send first GA and get nonce
        byte[] nonce_z = getNonce().getDataObject(0);
        logger.debug("NONCE S ENC: " + HexString.bufferToHex(nonce_z));
        byte[] nonce_s = decryptNonce(nonce_z);
        logger.debug("NONCE S PLAIN: " + HexString.bufferToHex(nonce_s));
        byte[] X1 = pace.getX1(nonce_s);

        // X1 zur Karte schicken und Y1 empfangen
        byte[] Y1 = mapNonce(X1).getDataObject(2);

        byte[] X2 = pace.getX2(Y1);
        // X2 zur Karte schicken und Y2 empfangen.
        byte[] Y2 = performKeyAgreement(X2).getDataObject(4);

        // Y2 ist PK_Picc der fr die TA bentigt wird.
        pk_picc = Y2.clone();

        byte[] S = pace.getSharedSecret_K(Y2);
        byte[] kenc = getKenc(S);
        byte[] kmac = getKmac(S);
        logger.debug("K bzw S: " + HexString.bufferToHex(S));
        logger.debug("Kenc: " + HexString.bufferToHex(kenc));
        logger.debug("Kmac: " + HexString.bufferToHex(kmac));
        // Authentication Token T_PCD berechnen
        byte[] tpcd = calcAuthToken(kmac, Y2);

        // Authentication Token T_PCD zur Karte schicken und Authentication Token T_PICC empfangen
        DynamicAuthenticationData dad = performMutualAuthentication(tpcd);
        byte[] tpicc = dad.getDataObject(6);
        if (dad.getDataObject(7) != null)
            logger.info("CAR: " + new String(dad.getDataObject(7)));
        if (dad.getDataObject(8) != null)
            logger.info("CAR2: " + new String(dad.getDataObject(8)));

        // Authentication Token T_PICC' berechnen
        byte[] tpicc_strich = calcAuthToken(kmac, X2);
        logger.debug("tpicc' :" + HexString.bufferToHex(tpicc_strich));

        // Prfe ob T_PICC = T_PICC'
        if (!Arrays.areEqual(tpicc, tpicc_strich))
            throw new PaceException("Authentication Tokens are different");

        return new SecureMessaging(crypto, kenc, kmac, new byte[crypto.getBlockSize()]);
    }

    /**
     * Fhrt alle Schritte des PACE-Protokolls durch und liefert bei Erfolg 
     * eine mit den ausgehandelten Schlsseln intialisierte SecureMessaging-Instanz zurck.
     * 
     * @return Bei Erfolg von PACE wird eine mit den ausgehandelten Schlsseln 
     *          intialisierte SecureMessaging-Instanz zurckgegeben. Anderfalls <code>null</code>.
     * @throws PaceException 
     * @throws CardException 
     * @throws SecureMessagingException 
     */
    public SecureMessaging performPaceWithTrigger(String startCmd, String stopCmd)
            throws PaceException, SecureMessagingException, CardException {

        // before sending MSE:SetAT, trigger start
        try {
            logger.info("starting: " + startCmd);
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(startCmd);
        } catch (IOException e) {
            // just silently fail
        }

        // send MSE:SetAT
        int resp = sendMSESetAT(terminalType).getSW();
        if (resp != 0x9000)
            throw new PaceException("MSE:Set AT failed. SW: " + Integer.toHexString(resp));

        // afterwards, trigger stop
        try {
            logger.info("starting: " + stopCmd);
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(stopCmd);
        } catch (IOException e) {
            // just silently fail
        }

        // send first GA and get nonce
        byte[] nonce_z = getNonce().getDataObject(0);
        logger.debug("NONCE S ENC: " + HexString.bufferToHex(nonce_z));
        byte[] nonce_s = decryptNonce(nonce_z);
        logger.debug("NONCE S PLAIN: " + HexString.bufferToHex(nonce_s));
        byte[] X1 = pace.getX1(nonce_s);

        // X1 zur Karte schicken und Y1 empfangen
        byte[] Y1 = mapNonce(X1).getDataObject(2);

        byte[] X2 = pace.getX2(Y1);
        // X2 zur Karte schicken und Y2 empfangen.
        byte[] Y2 = performKeyAgreement(X2).getDataObject(4);

        // Y2 ist PK_Picc der fr die TA bentigt wird.
        pk_picc = Y2.clone();

        byte[] S = pace.getSharedSecret_K(Y2);
        byte[] kenc = getKenc(S);
        byte[] kmac = getKmac(S);
        logger.debug("K bzw S: " + HexString.bufferToHex(S));
        logger.debug("Kenc: " + HexString.bufferToHex(kenc));
        logger.debug("Kmac: " + HexString.bufferToHex(kmac));
        // Authentication Token T_PCD berechnen
        byte[] tpcd = calcAuthToken(kmac, Y2);

        // Authentication Token T_PCD zur Karte schicken und Authentication Token T_PICC empfangen
        DynamicAuthenticationData dad = performMutualAuthentication(tpcd);
        byte[] tpicc = dad.getDataObject(6);
        if (dad.getDataObject(7) != null)
            logger.info("CAR: " + new String(dad.getDataObject(7)));
        if (dad.getDataObject(8) != null)
            logger.info("CAR2: " + new String(dad.getDataObject(8)));

        // Authentication Token T_PICC' berechnen
        byte[] tpicc_strich = calcAuthToken(kmac, X2);
        logger.debug("tpicc' :" + HexString.bufferToHex(tpicc_strich));

        // Prfe ob T_PICC = T_PICC'
        if (!Arrays.areEqual(tpicc, tpicc_strich))
            throw new PaceException("Authentication Tokens are different");

        return new SecureMessaging(crypto, kenc, kmac, new byte[crypto.getBlockSize()]);
    }

    /**
     * Liefert den ephemeralen Public Key des Chips zurck. Dieser wird fr Terminal
     * Authentisierung nach V.2 bentigt.
     * @return
     */
    public PublicKey getPKpicc() {

        KeyFactory fact = null;
        PublicKey pubKey = null;
        KeySpec pubKeySpec = null;

        if (dp.getDPType().equals("ECDH")) {
            ECPoint q = Converter.byteArrayToECPoint(pk_picc, (Fp) dp.getECParameter().getCurve());
            pubKeySpec = new ECPublicKeySpec(q, dp.getECParameter());

        } else if (dp.getDPType().equals("DH")) {
            BigInteger y = new BigInteger(1, pk_picc);
            pubKeySpec = new DHPublicKeySpec(y, dp.getDHParameter().getP(), dp.getDHParameter().getG());
        }

        try {
            fact = KeyFactory.getInstance(dp.getDPType(), "BC");
            pubKey = fact.generatePublic(pubKeySpec);
        } catch (NoSuchAlgorithmException e) {
            logger.warn("Couldn't generate ephemeral public key.", e);
        } catch (NoSuchProviderException e) {
            logger.warn("Couldn't generate ephemeral public key.", e);
        } catch (InvalidKeySpecException e) {
            logger.warn("Couldn't generate ephemeral public key.", e);
        }

        return pubKey;
    }

    /**
     * Der Authentication Token berechnet sich aus dem MAC (mit Schlssel kmac) ber 
     * einen AmPublicKey welcher den Object Identifier des verwendeten Protokolls und den 
     * von der empfangenen ephemeralen Public Key (Y2) enthlt. 
     * Siehe dazu TR-03110 V2.05 Kapitel A.2.4 und D.3.4
     * Hinweis: In lteren Versionen des PACE-Protokolls wurden weitere Parameter zur 
     * Berechnung des Authentication Token herangezogen.
     * 
     * @param data Byte-Array welches ein DO84 (Ephemeral Public Key) enthlt
     * @param kmac Schlssel K_mac fr die Berechnung des MAC
     * @return Authentication Token
     */
    private byte[] calcAuthToken(byte[] kmac, byte[] data) {
        byte[] tpcd = null;
        if (pace instanceof PaceECDH) {
            Fp curve = (Fp) dp.getECParameter().getCurve();
            ECPoint pointY = Converter.byteArrayToECPoint(data, curve);
            AmECPublicKey pkpcd = new AmECPublicKey(protocolOIDString, pointY);
            tpcd = crypto.getMAC(kmac, pkpcd.getEncoded());
        } else if (pace instanceof PaceDH) {
            BigInteger y = new BigInteger(data);
            AmDHPublicKey pkpcd = new AmDHPublicKey(protocolOIDString, y);
            tpcd = crypto.getMAC(kmac, pkpcd.getEncoded());
        }
        return tpcd;
    }

    private DynamicAuthenticationData sendGeneralAuthenticate(boolean chaining, byte[] data)
            throws SecureMessagingException, CardException, PaceException {

        CommandAPDU capdu = new CommandAPDU(chaining ? 0x10 : 0x00, 0x86, 0x00, 0x00, data, 0xFF);

        ResponseAPDU resp = cardHandler.transceive(capdu);

        if (!(resp.getSW() == 0x9000 || resp.getSW() == 0x6282))
            throw new PaceException("General Authentication returns: " + HexString.bufferToHex(resp.getBytes()));

        DynamicAuthenticationData dad = new DynamicAuthenticationData(resp.getData());
        return dad;
    }

    private DynamicAuthenticationData performMutualAuthentication(byte[] authToken)
            throws SecureMessagingException, CardException, PaceException {

        DynamicAuthenticationData dad85 = new DynamicAuthenticationData();
        DynamicAuthenticationData rspdad = null;
        dad85.addDataObject(5, authToken);

        try {
            rspdad = sendGeneralAuthenticate(false, dad85.getEncoded(ASN1Encoding.DER));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return rspdad;
    }

    private DynamicAuthenticationData performKeyAgreement(byte[] ephemeralPK)
            throws PaceException, CardException, SecureMessagingException {

        DynamicAuthenticationData dad83 = new DynamicAuthenticationData();
        DynamicAuthenticationData rspdad = null;
        dad83.addDataObject(3, ephemeralPK);

        try {
            rspdad = sendGeneralAuthenticate(true, dad83.getEncoded(ASN1Encoding.DER));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return rspdad;
    }

    private DynamicAuthenticationData mapNonce(byte[] mappingData)
            throws SecureMessagingException, CardException, PaceException {

        DynamicAuthenticationData dad81 = new DynamicAuthenticationData();
        DynamicAuthenticationData rspdad = null;
        dad81.addDataObject(1, mappingData);

        try {
            rspdad = sendGeneralAuthenticate(true, dad81.getEncoded(ASN1Encoding.DER));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return rspdad;
    }

    private ResponseAPDU sendMSESetAT(int terminalType)
            throws PaceException, SecureMessagingException, CardException {
        MSESetAT mse = new MSESetAT();
        mse.setAT(MSESetAT.setAT_PACE);
        mse.setProtocol(protocolOIDString);
        mse.setKeyReference(passwordRef);
        switch (terminalType) {
        case 0:
            break;
        case 1:
            mse.setISChat();
            break;
        case 2:
            mse.setATChat();
            break;
        case 3:
            mse.setSTChat();
            break;
        default:
            throw new PaceException("Unknown Terminal Reference: " + terminalType);
        }
        return cardHandler.transceive(mse.getCommandAPDU());
    }

    private DynamicAuthenticationData getNonce() throws PaceException, SecureMessagingException, CardException {

        byte[] data = new byte[] { 0x7C, 0x00 };

        return sendGeneralAuthenticate(true, data);
    }

    /**
     * @param z
     * @return
     */
    private byte[] decryptNonce(byte[] z) {
        byte[] derivatedPassword = getKey(keyLength, passwordBytes, 3);
        //logger.info("PASSWORD BYTES: " + HexString.bufferToHex(passwordBytes));
        logger.info("PACE NONCE ENC KEY: " + HexString.bufferToHex(derivatedPassword));
        return crypto.decryptBlock(derivatedPassword, z);
    }

    /**
     * @param sharedSecret_S
     * @return
     */
    private byte[] getKenc(byte[] sharedSecret_S) {
        return getKey(keyLength, sharedSecret_S, 1);
    }

    /**
     * @param sharedSecret_S
     * @return
     */
    private byte[] getKmac(byte[] sharedSecret_S) {
        return getKey(keyLength, sharedSecret_S, 2);
    }

    /**
     * @param keyLength
     * @param K
     * @param c
     * @return
     */
    private byte[] getKey(int keyLength, byte[] K, int c) {

        byte[] key = null;

        KeyDerivationFunction kdf = new KeyDerivationFunction(K, c);

        //logger.info("KEY LENGTH: " + keyLength);
        switch (keyLength) {
        case 112:
            key = kdf.getDESedeKey();
            break;
        case 128:
            key = kdf.getAES128Key();
            break;
        case 192:
            key = kdf.getAES192Key();
            break;
        case 256:
            key = kdf.getAES256Key();
            break;
        }
        return key;
    }

    private void getProprietaryDomainParameters(PaceDomainParameterInfo pdpi) throws PaceException {
        if (pdpi.getDomainParameter().getAlgorithm().toString().contains(BSIObjectIdentifiers.id_ecc.toString())) {
            dp = new DomainParameter(pdpi.getDomainParameter());
        } else
            throw new PaceException("Can't decode properietary domain parameters in PaceDomainParameterInfo!");
    }

    /**
     * Berechnet den SHA1-Wert des bergebenen Bytes-Array
     * 
     * @param input
     *            Byte-Array des SHA1-Wert berechnet werden soll
     * @return SHA1-Wert vom bergebenen Byte-Array
     */
    private byte[] calcSHA1(byte[] input) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException ex) {
        }

        md.update(input);
        return md.digest();
    }

    /**
     * Ermittelt anhand der ProtokollOID den Algorithmus und die Schlssellnge
     * fr PACE
     */
    private void getCryptoInformation(PaceInfo pi) {
        String protocolOIDString = pi.getProtocolOID();
        if (protocolOIDString.equals(id_PACE_DH_GM_3DES_CBC_CBC.toString())
                || protocolOIDString.equals(id_PACE_DH_IM_3DES_CBC_CBC.toString())
                || protocolOIDString.equals(id_PACE_ECDH_GM_3DES_CBC_CBC.toString())
                || protocolOIDString.equals(id_PACE_ECDH_IM_3DES_CBC_CBC.toString())) {
            keyLength = 112;
            crypto = new AmDESCrypto();
        } else if (protocolOIDString.equals(id_PACE_DH_GM_AES_CBC_CMAC_128.toString())
                || protocolOIDString.equals(id_PACE_DH_IM_AES_CBC_CMAC_128.toString())
                || protocolOIDString.equals(id_PACE_ECDH_GM_AES_CBC_CMAC_128.toString())
                || protocolOIDString.equals(id_PACE_ECDH_IM_AES_CBC_CMAC_128.toString())) {
            keyLength = 128;
            crypto = new AmAESCrypto();
        } else if (protocolOIDString.equals(id_PACE_DH_GM_AES_CBC_CMAC_192.toString())
                || protocolOIDString.equals(id_PACE_DH_IM_AES_CBC_CMAC_192.toString())
                || protocolOIDString.equals(id_PACE_ECDH_GM_AES_CBC_CMAC_192.toString())
                || protocolOIDString.equals(id_PACE_ECDH_IM_AES_CBC_CMAC_192.toString())) {
            keyLength = 192;
            crypto = new AmAESCrypto();
        } else if (protocolOIDString.equals(id_PACE_DH_GM_AES_CBC_CMAC_256.toString())
                || protocolOIDString.equals(id_PACE_DH_IM_AES_CBC_CMAC_256.toString())
                || protocolOIDString.equals(id_PACE_ECDH_GM_AES_CBC_CMAC_256.toString())
                || protocolOIDString.equals(id_PACE_ECDH_IM_AES_CBC_CMAC_256.toString())) {
            keyLength = 256;
            crypto = new AmAESCrypto();
        }
    }

}