libeac.tests.CPACECoreTest.java Source code

Java tutorial

Introduction

Here is the source code for libeac.tests.CPACECoreTest.java

Source

/*
 * CPACECoreTest.java
 *
 * Copyright (C) 2012, Axel
 *
 * This program 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 2 of the License, or (at your option) any later version.
 *
 * This program 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 this program;
 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package libeac.tests;

import common.CConverter;
import common.CFactoryHelper;
import common.crypto.IECPoint;
import common.util.Logger;
import junit.framework.TestCase;
import libeac.*;
import libeac.cardio.CGeneralAuthenticateAPDUCommand;
import libeac.cardio.CGetNonceADPUCommand;
import libeac.cardio.CMSEATAPDUCommand;
import libeac.cardio.CPACEFinalAPDUCommand;
import libeac.definitions.PACETypes;
import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.prng.VMPCRandomGenerator;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;

import javax.xml.bind.DatatypeConverter;
import java.math.BigInteger;
import java.util.Arrays;

/**
 * Created by IntelliJ IDEA.
 * User: Axel
 * Date: 21.12.11
 * Time: 13:18
 * To change this template use File | Settings | File Templates.
 */
public class CPACECoreTest extends TestCase {
    PACECore m_pace;
    final String m_szPw = "hgoiewrhgowh";

    @Override
    public void setUp() throws Exception {
        super.setUp(); //To change body of overridden methods use File | Settings | File Templates.
        m_pace = new PACECore(new PACEInfos(
                CFactoryHelper.getCryptoProvider().createDERObjectIdentifier("0.4.0.127.0.7.2.2.4.2.2"), 2, 13));
        assertNotNull(m_pace);
    }

    public void testCalcKPassword() throws Exception {

        m_pace.calcKPassword(m_szPw);
        assertTrue(Arrays.equals(m_pace.getKPassword(),
                DatatypeConverter.parseHexBinary("e81bff55075ffd49d6915f2a789ddc35")));
    }

    public void testDecryptNonce() throws Exception {
        m_pace.calcKPassword(m_szPw);
        m_pace.decryptNonce(DatatypeConverter.parseHexBinary("4dd3ea7e1d014d9f6c66940d4125496b"));
        assertTrue(Arrays.equals(m_pace.getDecryptedNonce(),
                DatatypeConverter.parseHexBinary("12236554766534425356246513647687")));
    }

    public void testCalcX() throws Exception {
        m_pace.calcKPassword(m_szPw);
        m_pace.decryptNonce(DatatypeConverter.parseHexBinary("4dd3ea7e1d014d9f6c66940d4125496b"));
        IECPoint X = m_pace.calcX();

        byte[] byaRnd = m_pace.getRand();
        VMPCRandomGenerator rndGen = new VMPCRandomGenerator();
        rndGen.nextBytes(byaRnd);
        X9ECParameters params = TeleTrusTNamedCurves.getByName("brainpoolp256r1");
        ECCurve.Fp curve = (ECCurve.Fp) params.getCurve();
        ECPoint base = params.getG();
        ECPoint.Fp Xbc = (ECPoint.Fp) base.multiply(new BigInteger(1, byaRnd));

        assertTrue(Arrays.equals(Xbc.getEncoded(), X.getEncoded()));

    }

    public void testCalcPkPcd() throws Exception {
        m_pace.calcKPassword(m_szPw);
        m_pace.decryptNonce(DatatypeConverter.parseHexBinary("4dd3ea7e1d014d9f6c66940d4125496b"));
        IECPoint X = m_pace.calcX();
    }

    public void testCalcTPcd() throws Exception {

    }

    public void testPACEWorkingExample() {

        // check MSE AT cmd
        String szMSEATCmd = "0022C1A427800A04007F000702020402028301037F4C12060904007F0007030102025305000000011084010D";
        CMSEATAPDUCommand mseCMd = new CMSEATAPDUCommand(PACETypes.AuthenticationType.PACE);
        mseCMd.setPassword(PACETypes.Password.PIN);
        mseCMd.setProtocol(CFactoryHelper.getCryptoProvider().createDERObjectIdentifier("0.4.0.127.0.7.2.2.4.2.2"));
        CertHolderAuthTemplate chat = new CertHolderAuthTemplate(PACETypes.ERoleType.AT);
        chat.setAuthorization(new byte[] { 0x00, 0x00, 0x00, 0x01, 0x10 });
        mseCMd.setCHAT(chat);
        mseCMd.setPrivateKeyReference(0xD);
        assertTrue(Arrays.equals(mseCMd.getBytes(), DatatypeConverter.parseHexBinary(szMSEATCmd)));

        m_pace.setTestingMode(true);

        // Decrcrypt nonce
        String szPin = "123456";
        String szCardresponse_Nonce = "7C128010CE834CDE69FFBB1D1EB21585CD709F189000";
        String szEncNonceFromChip = "CE834CDE69FFBB1D1EB21585CD709F18";
        DynamicAuthenticationData dynNon = new DynamicAuthenticationData();
        dynNon.initialize(DatatypeConverter.parseHexBinary(szCardresponse_Nonce));
        assertTrue(Arrays.equals(dynNon.getEncryptedNonce(), DatatypeConverter.parseHexBinary(szEncNonceFromChip)));

        String szKPassword = "591468CDA83D65219CCCB8560233600F";
        m_pace.calcKPassword(szPin);
        assertTrue(Arrays.equals(m_pace.getKPassword(), DatatypeConverter.parseHexBinary(szKPassword)));

        String szDecNonce = "7D98C00FC6C9E9543BBF94A87073A123";
        m_pace.setKPassword(DatatypeConverter.parseHexBinary(szKPassword));
        assertTrue(Arrays.equals(DatatypeConverter.parseHexBinary(szKPassword), m_pace.getKPassword()));

        m_pace.decryptNonce(DatatypeConverter.parseHexBinary(szEncNonceFromChip));
        assertTrue(Arrays.equals(m_pace.getDecryptedNonce(), DatatypeConverter.parseHexBinary(szDecNonce)));

        //check get nonce cmd
        String szNonce = "10860000027C0000";
        CGetNonceADPUCommand nonceCmd = new CGetNonceADPUCommand();
        assertTrue(Arrays.equals(nonceCmd.getBytes(), DatatypeConverter.parseHexBinary(szNonce)));

        // Set sk_x manually for testing purpose
        String szSK_x = "752287F5B02DE3C4BC3E17945118C51B23C97278E4CD748048AC56BA5BDC3D46";
        String szPK_X = "043DD29BBE5907FD21A152ADA4895FAAE7ACC55F5E50EFBFDE5AB0C6EB54F198D615913635F0FDF5BEB383E00355F82D3C41ED0DF2E28363433DFB73856A15DC9F";

        m_pace.setSK_x(new BigInteger(1, DatatypeConverter.parseHexBinary(szSK_x)));
        assertTrue(Arrays.equals(m_pace.getSK_x().toByteArray(), DatatypeConverter.parseHexBinary(szSK_x)));

        // calculate X
        IECPoint X = m_pace.calcX();
        assertTrue(Arrays.equals(X.getEncoded(), DatatypeConverter.parseHexBinary(szPK_X)));

        // check X cmd
        String szGaMapping = "10860000457C438141043DD29BBE5907FD21A152ADA4895FAAE7ACC55F5E50EFBFDE5AB0C6EB54F198D615913635F0FDF5BEB383E00355F82D3C41ED0DF2E28363433DFB73856A15DC9F00";
        CGeneralAuthenticateAPDUCommand gaCmd = new CGeneralAuthenticateAPDUCommand();
        DynamicAuthenticationData dynAuth = new DynamicAuthenticationData();
        dynAuth.setTerminalMapping(X.getEncoded());
        gaCmd.appendData(dynAuth.getDERTerminalAuthenticationData());
        assertTrue(Arrays.equals(gaCmd.getBytes(), DatatypeConverter.parseHexBinary(szGaMapping)));

        //Card responce with Y
        String szCardResp_PK_Y = "7C438241049CFCF7582AC986D0DD52FA53123414C3E1B96B4D00ABA8E574679B70EFB5BC3B45D2F13729CC2AE178E7E241B443213533B77DBB44649A815DDC4A2384BA422A9000";
        String szPK_Y = "049CFCF7582AC986D0DD52FA53123414C3E1B96B4D00ABA8E574679B70EFB5BC3B45D2F13729CC2AE178E7E241B443213533B77DBB44649A815DDC4A2384BA422A";
        DynamicAuthenticationData dynDat2 = new DynamicAuthenticationData();
        dynDat2.initialize(DatatypeConverter.parseHexBinary(szCardResp_PK_Y));
        assertTrue(Arrays.equals(DatatypeConverter.parseHexBinary(szPK_Y), dynDat2.getChipMapping()));

        String szH = "0471850CFD80FB475947E5B1AF10FE8E6663967C2D264935B31951F763A4B03A5749167388F88F52A109167E3E6592CA0820468D1157A8E781D2F7049179B1D114";
        String szGDash = "043929D28BA1E5339D6C5DADE5E33BD3C2F0BD14DD77C7521532261659C918FA6014DD48FA84E62BDE438EDB4C9771D042CDB24B7788BDBAB2031C45751E777F66";
        String szSK_PCD = "009D9A32DF93A57CCE33CA3CDD3457E33A976F293546C73550F397259C93BE0120";
        String szPK_PCD = "04518BC4E532AD2A9BD6527804D5D665ABD51041037A0CC8AA922804EB501C222B3427388599AFAAE9FBACE2DF93E13C3C4979CD12F0AE3E3C0126028391554582";

        // calculate PK_PCD
        m_pace.setSK_PCD(new BigInteger(1, DatatypeConverter.parseHexBinary(szSK_PCD)));
        assertTrue(Arrays.equals(m_pace.getSK_PCD().toByteArray(), DatatypeConverter.parseHexBinary(szSK_PCD)));
        IECPoint pkPCD;
        try {
            pkPCD = m_pace.calcPkPcd(CConverter.getECPointFPFromByteArray(DatatypeConverter.parseHexBinary(szPK_Y),
                    m_pace.getCurve()));
        } catch (Exception e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            return;
        }
        assertTrue(Arrays.equals(m_pace.getGDash().getEncoded(), DatatypeConverter.parseHexBinary(szGDash)));
        assertTrue(Arrays.equals(pkPCD.getEncoded(), DatatypeConverter.parseHexBinary(szPK_PCD)));
        assertTrue(Arrays.equals(m_pace.getH().getEncoded(), DatatypeConverter.parseHexBinary(szH)));

        // check PK_PCD cmd
        String szGaEphKey = "10860000457C43834104518BC4E532AD2A9BD6527804D5D665ABD51041037A0CC8AA922804EB501C222B3427388599AFAAE9FBACE2DF93E13C3C4979CD12F0AE3E3C012602839155458200";
        gaCmd = new CGeneralAuthenticateAPDUCommand();
        dynAuth.reset();
        dynAuth.setTerminalEphemeralPK(pkPCD.getEncoded());
        gaCmd.appendData(dynAuth.getDERTerminalAuthenticationData());
        assertTrue(Arrays.equals(gaCmd.getBytes(), DatatypeConverter.parseHexBinary(szGaEphKey)));

        //Card responds with PK_PICC
        String szCardResponse_PK_PICC = "7C43844104282CF38073036AFAC216AF135BD994DA0C357F10BD4C34AFEA1042B2EB0FD6804DF3658B835AC2E7133F13691184542BB50B109963A4662ABDC08B9763AF4B5B9000";
        String szPK_PICC = "04282CF38073036AFAC216AF135BD994DA0C357F10BD4C34AFEA1042B2EB0FD6804DF3658B835AC2E7133F13691184542BB50B109963A4662ABDC08B9763AF4B5B";
        dynAuth.reset();
        dynAuth.initialize(DatatypeConverter.parseHexBinary(szCardResponse_PK_PICC));
        assertTrue(Arrays.equals(dynAuth.getChipEphemeralPK(), DatatypeConverter.parseHexBinary(szPK_PICC)));

        String szK = "6E7D077CCD367C2EAA683F1E8EC534302E2D00B6ADAF8A87A6EDA78740F17606";
        //values taken from openPACE source code since BSI working example document contains wrong values for K_ENC, K_MAC.  <-- corrected in vers. 1.02
        // Also T_PCD and T_PICC need to be exchanged
        String szTPCD = "A27AE7B36573C1D9";
        String szKENC = "68406B4162100563D9C901A6154D2901";
        String szKMAC = "73FF268784F72AF833FDC9464049AFC9";

        //calculate T_PCD
        byte[] T_PCD;
        try {
            T_PCD = m_pace.calcTPcd(CConverter
                    .getECPointFPFromByteArray(DatatypeConverter.parseHexBinary(szPK_PICC), m_pace.getCurve()));
        } catch (Exception e) {
            e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            return;
        }

        assertTrue(Arrays.equals(m_pace.getK().toByteArray(), DatatypeConverter.parseHexBinary(szK)));
        assertTrue(Arrays.equals(m_pace.getKEnc(), DatatypeConverter.parseHexBinary(szKENC)));
        assertTrue(Arrays.equals(m_pace.getKMac(), DatatypeConverter.parseHexBinary(szKMAC)));
        assertTrue(Arrays.equals(T_PCD, DatatypeConverter.parseHexBinary(szTPCD)));

        // check T_PCD cmd
        String szGaAuthToken = "008600000C7C0A8508A27AE7B36573C1D900";
        CPACEFinalAPDUCommand fpaCmd = new CPACEFinalAPDUCommand();
        dynAuth.reset();
        dynAuth.setTerminalAuthToken(T_PCD);
        fpaCmd.appendData(dynAuth.getDERTerminalAuthenticationData());
        assertTrue(Arrays.equals(fpaCmd.getBytes(), DatatypeConverter.parseHexBinary(szGaAuthToken)));

        String szTPICC = "A2658C2F38600B0F";
        boolean bVerify = m_pace.Verify(DatatypeConverter.parseHexBinary(szTPICC));
        assertTrue(bVerify);

        if (bVerify)
            Logger.log("BSI working example pace check was successful");

    }

}