package de.persosim.simulator.protocols.pace; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECPoint; import java.security.spec.ECPrivateKeySpec; import java.security.spec.ECPublicKeySpec; import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import mockit.NonStrictExpectations; import org.globaltester.cryptoprovider.Crypto; import org.junit.Before; import org.junit.Test; import de.persosim.simulator.crypto.CryptoUtil; import de.persosim.simulator.crypto.DomainParameterSetEcdh; import de.persosim.simulator.crypto.StandardizedDomainParameters; import de.persosim.simulator.test.PersoSimTestCase; import de.persosim.simulator.utils.HexString; public class GenericMappingEcdhTest extends PersoSimTestCase { // ---> ECDH <--- ECPoint ecdhGeneratorUnmappedExpected, ecdhGeneratorMappedExpected, ecdhPublicKeyPointUnmappedExpected, ecdhPublicKeyPointMappedExpected; BigInteger ecdhPrivateKeySExpected; DomainParameterSetEcdh ecdhDomainParameterSetUnMappedExpected, ecdhDomainParameterSetMappedExpected; ECPrivateKey ecdhPrivateKeyUnmappedExpected, ecdhPrivateKeyMappedExpected; ECPublicKey ecdhPublicKeyUnmappedExpected, ecdhPublicKeyMappedExpected; KeyPair ecdhKeyPairUnmappedExpected, ecdhKeyPairMappedExpected; /** * Create the test environment containing an elementary file and the mocked * object store. * @throws ReflectiveOperationException */ @Before public void setUp() throws Exception { //XXX all this setup is currently used only within testPerformMapping, maybe move it there ecdhDomainParameterSetUnMappedExpected = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); ecdhGeneratorUnmappedExpected = ecdhDomainParameterSetUnMappedExpected.getGenerator(); byte[] ecdhGeneratorXMappedPlain = HexString.toByteArray("3D4C109FAF4EFD9FA4BDA13907401379067BF7F03C3ACE6D980575F6F9179E97"); byte[] ecdhGeneratorYMappedPlain = HexString.toByteArray("61E6418377A06DD48D4B624ABC54F7DAA54008E445E8B808713E406726106E2E"); ecdhGeneratorMappedExpected = new ECPoint(new BigInteger(1, ecdhGeneratorXMappedPlain), new BigInteger(1, ecdhGeneratorYMappedPlain)); ecdhDomainParameterSetMappedExpected = ecdhDomainParameterSetUnMappedExpected.getUpdatedDomainParameterSet(ecdhGeneratorMappedExpected); byte[] ecdhPrivateSPlain = HexString.toByteArray("74F6631E3C1A185918CDE69B80016B5F6C34A686BD4E1DC2470911C4A6280A92"); ecdhPrivateKeySExpected = new BigInteger(1, ecdhPrivateSPlain); byte[] ecdhPublicXUnmappedPlain = HexString.toByteArray("16CD374C07A5A00354F5AACC22DC0C5A57AF154E29F3DFDD17A3F05E4374DEF0"); byte[] ecdhPublicYUnmappedPlain = HexString.toByteArray("A6478E512FE183B553EF84A424B0949A913953AC498FF7C4E316F1C71D9BD62A"); ecdhPublicKeyPointUnmappedExpected = new ECPoint(new BigInteger(1, ecdhPublicXUnmappedPlain), new BigInteger(1, ecdhPublicYUnmappedPlain)); ECPrivateKeySpec ecdhPrivateKeySpecUnmappedExpected = new ECPrivateKeySpec(ecdhPrivateKeySExpected, ecdhDomainParameterSetUnMappedExpected.getKeySpec()); ECPublicKeySpec ecdhPublicKeySpecUnmappedExpected = new ECPublicKeySpec(ecdhPublicKeyPointUnmappedExpected, ecdhDomainParameterSetUnMappedExpected.getKeySpec()); KeyFactory keyFactory = KeyFactory.getInstance("ECDH", Crypto.getCryptoProvider()); ecdhPrivateKeyUnmappedExpected = (ECPrivateKey) keyFactory.generatePrivate(ecdhPrivateKeySpecUnmappedExpected); ecdhPublicKeyUnmappedExpected = (ECPublicKey) keyFactory.generatePublic(ecdhPublicKeySpecUnmappedExpected); ecdhKeyPairUnmappedExpected = new KeyPair(ecdhPublicKeyUnmappedExpected, ecdhPrivateKeyUnmappedExpected); ecdhKeyPairMappedExpected = CryptoUtil.updateKeyPairToNewDomainParameters(ecdhKeyPairUnmappedExpected, ecdhDomainParameterSetMappedExpected); ecdhPrivateKeyMappedExpected = (ECPrivateKey) ecdhKeyPairMappedExpected.getPrivate(); ecdhPublicKeyMappedExpected = (ECPublicKey) ecdhKeyPairMappedExpected.getPublic(); } /** * Positive test case: perform mapping of ECDH domain parameters based on values from valid PACE test run. */ @Test public void testPerformMapping() throws Exception { new NonStrictExpectations(CryptoUtil.class) { { CryptoUtil.generateKeyPair( withInstanceOf(DomainParameterSetEcdh.class), withInstanceOf(SecureRandom.class)); // key pair that is used for mapping, e.g. is unmapped result = ecdhKeyPairUnmappedExpected; } }; GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] nonceSPlainExpected = HexString.toByteArray("1DD01F3933B57DA8EF4F07B5FDC46DC412C9E695707E9A391D804F24E683A305"); byte[] mappingDataExpected = HexString.toByteArray("04A983801181B4DF9262ED4D277711BF3AB3FE260E4A814439A80B424CD4A6090E6559F7AE3702AD5C16348B384E09B4B50E8FBD3DEEA081F2A5AB85E7748A8243"); byte[] mappingResponseExpected = ecdhDomainParameterSetUnMappedExpected.encodePublicKey(ecdhPublicKeyUnmappedExpected); MappingResult mappingResultReceived = mapping.performMapping(ecdhDomainParameterSetUnMappedExpected, nonceSPlainExpected, mappingDataExpected); DomainParameterSetEcdh domainParameterSetReceived = (DomainParameterSetEcdh) mappingResultReceived.getMappedDomainParameters(); KeyPair keyPairReceived = mappingResultReceived.getKeyPairPiccMapped(); ECPublicKey publicKeyReceived = (ECPublicKey) keyPairReceived.getPublic(); ECPrivateKey privateKeyReceived = (ECPrivateKey) keyPairReceived.getPrivate(); byte[] mappingResponseReceived = mappingResultReceived.getMappingResponse(); assertEquals("generator", ecdhGeneratorMappedExpected, domainParameterSetReceived.getGenerator()); assertEquals("ECDH public key W", ecdhPublicKeyMappedExpected.getW(), publicKeyReceived.getW()); assertEquals("ECDH private key S", ecdhPrivateKeyMappedExpected.getS(), privateKeyReceived.getS()); assertArrayEquals("mapping response", mappingResponseExpected, mappingResponseReceived); } /** * Positive test case: perform mapping of domain parameters based on values from valid PACE test run. */ @Test public void testPerformGenericMappingOfDomainParameters() { DomainParameterSetEcdh domainParameterSetUnMapped = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] nonceS = HexString.toByteArray("FA587945E9FE2AEB417DF0ADF951B7CBD9D5E476F8F6EF1B701C59C56B180204"); byte[] secretOfKeyAgreement = HexString.toByteArray("04326C2CE38AC366142735AFA4317A24BDE8F12AFAEE1575CE9756E3A8849F9AEF30103CF5396CBA2F4678572988513CFC0F0CBE116644A5B9E8C6B229E0C9E2FB"); BigInteger gxExpected = new BigInteger(1, HexString.toByteArray("7D05B6FEB64B5A197BE4D6482F8C81C918095FB4CA771F838473866137916CAC")); BigInteger gyExpected = new BigInteger(1, HexString.toByteArray("37297DCFDE4A2D65E3AACE40E7C12EA052958662803F6B8A2D9F7F7F30D7B5C3")); ECPoint pointExpected = new ECPoint(gxExpected, gyExpected); DomainParameterSetEcdh domainParametersReceived = (DomainParameterSetEcdh) mapping.performMappingOfDomainParameters(domainParameterSetUnMapped, nonceS, secretOfKeyAgreement); assertEquals("curve", domainParameterSetUnMapped.getCurve(), domainParametersReceived.getCurve()); assertEquals("G", pointExpected, domainParametersReceived.getGenerator()); assertEquals("group order", domainParameterSetUnMapped.getOrder(), domainParametersReceived.getOrder()); assertEquals("cofactor", domainParameterSetUnMapped.getCofactor(), domainParametersReceived.getCofactor()); } /** * Negative test case: perform mapping of domain parameters based on values from valid PACE test run but wrong nonce S. */ @Test public void testPerformGenericMappingOfDomainParametersWrongNonceS() { DomainParameterSetEcdh domainParameterSetUnMapped = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] nonceS = HexString.toByteArray("FA587945E9FE2AEB417DF0ADF951B7CBD9D5E476F8F6EF1B701C59C56B180205"); // wrong nonce byte[] secretOfKeyAgreement = HexString.toByteArray("04326C2CE38AC366142735AFA4317A24BDE8F12AFAEE1575CE9756E3A8849F9AEF30103CF5396CBA2F4678572988513CFC0F0CBE116644A5B9E8C6B229E0C9E2FB"); BigInteger gxExpected = new BigInteger(1, HexString.toByteArray("7D05B6FEB64B5A197BE4D6482F8C81C918095FB4CA771F838473866137916CAC")); BigInteger gyExpected = new BigInteger(1, HexString.toByteArray("37297DCFDE4A2D65E3AACE40E7C12EA052958662803F6B8A2D9F7F7F30D7B5C3")); ECPoint pointExpected = new ECPoint(gxExpected, gyExpected); DomainParameterSetEcdh domainParametersReceived = (DomainParameterSetEcdh) mapping.performMappingOfDomainParameters(domainParameterSetUnMapped, nonceS, secretOfKeyAgreement); assertEquals("curve", domainParameterSetUnMapped.getCurve(), domainParametersReceived.getCurve()); assertNotEquals("G", pointExpected, domainParametersReceived.getGenerator()); assertEquals("group order", domainParameterSetUnMapped.getOrder(), domainParametersReceived.getOrder()); assertEquals("cofactor", domainParameterSetUnMapped.getCofactor(), domainParametersReceived.getCofactor()); } /** * Negative test case: perform mapping of domain parameters based on values from valid PACE test run but with wrong secret of key agreement. */ @Test public void testPerformGenericMappingOfDomainParametersWrongSecretOfKeyAgreement() { DomainParameterSetEcdh domainParameterSetUnMapped = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] nonceS = HexString.toByteArray("FA587945E9FE2AEB417DF0ADF951B7CBD9D5E476F8F6EF1B701C59C56B180204"); byte[] secretOfKeyAgreement = HexString.toByteArray("04326C2CE38AC366142735AFA4317A24BDE8F12AFAEE1575CE9756E3A8849F9AEF30103CF5396CBA2F4678572988513CFC0F0CBE116644A5B9E8C6B229E0C9E2FC"); // wrong secret of key agreement BigInteger gxExpected = new BigInteger(1, HexString.toByteArray("7D05B6FEB64B5A197BE4D6482F8C81C918095FB4CA771F838473866137916CAC")); BigInteger gyExpected = new BigInteger(1, HexString.toByteArray("37297DCFDE4A2D65E3AACE40E7C12EA052958662803F6B8A2D9F7F7F30D7B5C3")); ECPoint pointExpected = new ECPoint(gxExpected, gyExpected); DomainParameterSetEcdh domainParametersReceived = (DomainParameterSetEcdh) mapping.performMappingOfDomainParameters(domainParameterSetUnMapped, nonceS, secretOfKeyAgreement); assertEquals("curve", domainParameterSetUnMapped.getCurve(), domainParametersReceived.getCurve()); assertNotEquals("G", pointExpected, domainParametersReceived.getGenerator()); assertEquals("group order", domainParameterSetUnMapped.getOrder(), domainParametersReceived.getOrder()); assertEquals("cofactor", domainParameterSetUnMapped.getCofactor(), domainParametersReceived.getCofactor()); } /** * Positive test case: perform key agreement as part of mapping function based on values from valid PACE test run. * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException */ @Test public void testPerformKeyAgreement() throws InvalidKeySpecException, NoSuchAlgorithmException { DomainParameterSetEcdh domainParameterSetUnMapped = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] privateKeyDataPicc = HexString.toByteArray("7FC3DE0EDE951E6181392527612FF2A50D4E6C6FE00F7A92E66CB3D7B7D23044"); byte[] publicKeyDataPcd = HexString.toByteArray("0424EF5B5C5D5F085783357C34C01660C6A062005BA1E347EB5E890DC34A305085161950814AE4D7BF20137D5C425E039CCC250835D69E8FEE92E302F468F39394"); ECPrivateKey ecPrivKeyPicc = domainParameterSetUnMapped.reconstructPrivateKey(privateKeyDataPicc); ECPublicKey ecPubKeyPcd = domainParameterSetUnMapped.reconstructPublicKey(publicKeyDataPcd); byte[] commonSecretExpected = HexString.toByteArray("04326C2CE38AC366142735AFA4317A24BDE8F12AFAEE1575CE9756E3A8849F9AEF30103CF5396CBA2F4678572988513CFC0F0CBE116644A5B9E8C6B229E0C9E2FB"); byte[] commonSecretReceived = mapping.performKeyAgreement(domainParameterSetUnMapped, ecPrivKeyPicc, ecPubKeyPcd); assertArrayEquals("common mapping secret", commonSecretExpected, commonSecretReceived); } /** * Negative test case: perform key agreement as part of mapping function based on values from valid PACE test run but with wrong PCD public key (on curve but not matching). * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException */ @Test public void testPerformKeyAgreement_wrongPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException { DomainParameterSetEcdh domainParameterSetUnMapped = (DomainParameterSetEcdh) StandardizedDomainParameters.getDomainParameterSetById(13); GenericMappingEcdh mapping = new GenericMappingEcdh(); byte[] privateKeyDataPicc = HexString.toByteArray("7FC3DE0EDE951E6181392527612FF2A50D4E6C6FE00F7A92E66CB3D7B7D23044"); byte[] publicKeyDataPcd = HexString.toByteArray("047307AED59C716B4328E974EC2460104E013E93B9826A47CB9DB8A104F493F685094776A48D5B6746058D2B0FB206B69E4AA16E8E893BB4908285482BC4B82232"); ECPrivateKey ecPrivKeyPicc = domainParameterSetUnMapped.reconstructPrivateKey(privateKeyDataPicc); ECPublicKey ecPubKeyPcd = domainParameterSetUnMapped.reconstructPublicKey(publicKeyDataPcd); byte[] commonSecretExpected = HexString.toByteArray("04326C2CE38AC366142735AFA4317A24BDE8F12AFAEE1575CE9756E3A8849F9AEF30103CF5396CBA2F4678572988513CFC0F0CBE116644A5B9E8C6B229E0C9E2FB"); byte[] commonSecretReceived = mapping.performKeyAgreement(domainParameterSetUnMapped, ecPrivKeyPicc, ecPubKeyPcd); assertFalse("common mapping secret", Arrays.equals(commonSecretExpected, commonSecretReceived)); } }