From 005a974e5ce0ff43c1f86e478dcd53f4e13823a4 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 21 Oct 2021 14:41:59 +0200 Subject: add jUnit tests for bPK and HSM-Facade encryption --- .../eaaf/core/test/builder/BpkBuilderTest.java | 73 ++++++++++ .../eaaf/core/test/credentials/EncryptionTask.java | 156 +++++++++++++++++++++ .../credentials/KeyOperationPerformanceTest.java | 154 ++++++++++++++++++++ .../resources/spring/test_eaaf_pvp_lazy.beans.xml | 9 ++ 4 files changed, 392 insertions(+) create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java (limited to 'eaaf_core_utils/src') diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java index ccd452c5..bccab09f 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/builder/BpkBuilderTest.java @@ -1,12 +1,20 @@ package at.gv.egiz.eaaf.core.test.builder; +import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.ECGenParameterSpec; import org.apache.commons.lang3.RandomStringUtils; +import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers; +import org.jose4j.jwe.JsonWebEncryption; +import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; +import org.jose4j.lang.JoseException; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -34,10 +42,75 @@ public class BpkBuilderTest { @Before public void initialize() throws NoSuchAlgorithmException, NoSuchProviderException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); keyPair = keyGen.generateKeyPair(); } + @Test + public void encBpkTextualLength() throws EaafBuilderException, InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException, InvalidAlgorithmParameterException, JoseException { + String bpk = "MDEyMzQ1Njc4OWFiY2RIZg+CU"; + String target = EaafConstants.URN_PREFIX_CDID + "AA"; + + printResult("Legacy RSA 1024:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(1024))); + printResult("Legacy RSA 2048:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(2048))); + printResult("Legacy RSA 3072:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(3072))); + printResult("Legacy RSA 4096:", BpkBuilder.encryptBpk(bpk, target, generateRsaPubKey(4096))); + + + bpk = "V1::urn:publicid:gv.at:cdid+BW::MDEyMzQ1Njc 4OW FiY2RIZg+CU&g=::2004-01-22T20:57:12"; + + printResult("RSA 2048:", createJsonEnc(generateRsaPubKey(2048), bpk, target, + KeyManagementAlgorithmIdentifiers.RSA_OAEP_256)); + printResult("RSA 3072:", createJsonEnc(generateRsaPubKey(3072), bpk, target, + KeyManagementAlgorithmIdentifiers.RSA_OAEP_256)); + printResult("RSA 4096:", createJsonEnc(generateRsaPubKey(4048), bpk, target, + KeyManagementAlgorithmIdentifiers.RSA_OAEP_256)); + + printResult("ECC 256:", createJsonEnc(generateEcPubKey("secp256r1"), bpk, target, + KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW)); + printResult("ECC 384:", createJsonEnc(generateEcPubKey("secp384r1"), bpk, target, + KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW)); + printResult("ECC 521:", createJsonEnc(generateEcPubKey("secp521r1"), bpk, target, + KeyManagementAlgorithmIdentifiers.ECDH_ES_A128KW)); + + System.out.println("Finished!"); + } + + private void printResult(String prefix, String body) { + System.out.println(prefix + " " + body.length() + " full:" + body); + + } + + private String createJsonEnc(PublicKey pubKey, String bpk, String target, String keyWrapAlg) throws JoseException { + JsonWebEncryption enc = new JsonWebEncryption(); + enc.setKey(pubKey); + enc.setPayload(bpk); + enc.setAlgorithmHeaderValue(keyWrapAlg); + enc.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM); + enc.setKeyIdHeaderValue("myFirstKey"); + enc.setContentTypeHeaderValue(target); + return enc.getCompactSerialization(); + + } + + private PublicKey generateRsaPubKey(int size) throws NoSuchAlgorithmException { + KeyPairGenerator keyGen3 = KeyPairGenerator.getInstance("RSA"); + keyGen3.initialize(size); + return keyGen3.generateKeyPair().getPublic(); + + } + + private PublicKey generateEcPubKey(String curve) throws NoSuchAlgorithmException, + NoSuchProviderException, InvalidAlgorithmParameterException { + KeyPairGenerator generator = KeyPairGenerator.getInstance("EC"); + ECGenParameterSpec ecSpec = new ECGenParameterSpec(curve); + generator.initialize(ecSpec, new SecureRandom()); + return generator.generateKeyPair().getPublic(); + + } + @Test public void encBpkWrongTarget() throws InvalidKeyException { String bpk = RandomStringUtils.randomAlphanumeric(25); diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java new file mode 100644 index 00000000..ac456c13 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/EncryptionTask.java @@ -0,0 +1,156 @@ +package at.gv.egiz.eaaf.core.test.credentials; + +import static org.junit.Assert.assertArrayEquals; + +import java.security.Provider; +import java.util.concurrent.CompletableFuture; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +public class EncryptionTask implements Runnable { + + private static final String HSM_FACASE_HOST = "eid.a-sit.at"; + private static final String HSM_FACASE_PORT = "9050"; + private static final String HSM_FACASE_SSL_TRUST = "src/test/resources/data/hsm_facade_trust_root.crt"; + private static final String HSM_FACASE_USERNAME = "authhandler-junit"; + private static final String HSM_FACASE_PASSWORD = "supersecret123"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS = + "src/test/resources/data/junit.jks"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS = + "src/test/resources/data/junit_without_trustcerts.jks"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_PKCS12 = + "src/test/resources/data/junit_without_trustcerts.p12"; + private static final String SOFTWARE_KEYSTORE_PASSWORD = "password"; + + private static final String HSM_FACADE_KEY_ALIAS = "authhandler-sign"; + + private static final String CIPHER_MODE = "AES/GCM/NoPadding"; + private static final int GCM_NONCE_LENGTH = 12; // in bytes + private static final int GCM_TAG_LENGTH = 16; // in bytes + + protected static final String KEYNAME = "AES"; + + @Autowired + private DummyAuthConfigMap mapConfig; + @Autowired + private ApplicationContext context; + + String keyName; + int rounds; + private Exception error; + + public EncryptionTask(ApplicationContext context2, DummyAuthConfigMap mapConfig2, + String keyName, int rounds) { + this.context = context2; + this.mapConfig = mapConfig2; + + this.keyName = keyName; + this.rounds = rounds; + + } + + @Override + public void run() { + run(this.keyName, this.rounds); + + } + + @Async + public CompletableFuture run(String keyName, int rounds) { + try { + Pair key = loadSymmetricKey(keyName); + Assert.assertNotNull("Key container is null", key); + + for(int i = 0; i < rounds; i++) { + + log.info("Starting threat: {} Round: {}", Thread.currentThread().getName(), i); + + byte[] data = RandomStringUtils.randomAlphanumeric(1024*64).getBytes(); + Pair enc = encryptData(key.getFirst(), data); + + byte[] checkData = decryptData(enc, key.getFirst()); + log.info("Finishing threat: {} Round: {}", Thread.currentThread().getName(), i); + + + assertArrayEquals("plaintext not match", data, checkData); + + + + } + + } catch (Exception e) { + this.error = e; + throw new RuntimeException(e); + + } + + return new AsyncResult<>("finished").completable(); + + } + + private byte[] decryptData(Pair enc, SecretKey secret) throws Exception { + final GCMParameterSpec iv = new GCMParameterSpec(GCM_TAG_LENGTH * 8, enc.getSecond()); + final Cipher cipher = Cipher.getInstance(CIPHER_MODE); + cipher.init(Cipher.DECRYPT_MODE, secret, iv); + return cipher.doFinal(enc.getFirst()); + + } + + + + private Pair encryptData(SecretKey secret, byte[] toEncrypt) throws Exception { + final byte[] nonce = Random.nextBytes(GCM_NONCE_LENGTH); + final GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce); + final Cipher cipher = Cipher.getInstance(CIPHER_MODE); + cipher.init(Cipher.ENCRYPT_MODE, secret, spec); + + final byte[] encdata = cipher.doFinal(toEncrypt); + final byte[] iv = cipher.getIV(); + + return Pair.newInstance(encdata, iv); + + } + + private Pair loadSymmetricKey(String keyName) throws EaafException { + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, HSM_FACASE_HOST); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT, HSM_FACASE_PORT); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST, HSM_FACASE_SSL_TRUST); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME, HSM_FACASE_USERNAME); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD, HSM_FACASE_PASSWORD); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + keyConfig.setKeyStoreName("authhandler"); + keyConfig.setKeyAlias(keyName); + + return keyStoreFactory.buildNewSymmetricKey(keyConfig); + } + + + +} diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java new file mode 100644 index 00000000..c907301d --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/credentials/KeyOperationPerformanceTest.java @@ -0,0 +1,154 @@ +package at.gv.egiz.eaaf.core.test.credentials; + +import static org.junit.Assert.assertFalse; + +import java.security.Provider; +import java.security.Security; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.crypto.SecretKey; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.hsmfacade.provider.HsmFacadeProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.SymmetricKeyConfiguration.SymmetricKeyType; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; +import lombok.extern.slf4j.Slf4j; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/spring/test_eaaf_pvp_lazy.beans.xml") +@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD) +@Slf4j +public class KeyOperationPerformanceTest { + + private static final String HSM_FACASE_HOST = "eid.a-sit.at"; + private static final String HSM_FACASE_PORT = "9050"; + private static final String HSM_FACASE_SSL_TRUST = "src/test/resources/data/hsm_facade_trust_root.crt"; + private static final String HSM_FACASE_USERNAME = "authhandler-junit"; + private static final String HSM_FACASE_PASSWORD = "supersecret123"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS_WITH_TRUSTED_CERTS = + "src/test/resources/data/junit.jks"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_JKS = + "src/test/resources/data/junit_without_trustcerts.jks"; + private static final String PATH_TO_SOFTWARE_KEYSTORE_PKCS12 = + "src/test/resources/data/junit_without_trustcerts.p12"; + private static final String SOFTWARE_KEYSTORE_PASSWORD = "password"; + + private static final String HSM_FACADE_KEY_ALIAS = "authhandler-sign"; + + private static final String CIPHER_MODE = "AES/GCM/NoPadding"; + private static final int GCM_NONCE_LENGTH = 12; // in bytes + private static final int GCM_TAG_LENGTH = 16; // in bytes + + protected static final String KEYNAME = "AES"; + + + private static final String AES_KEY_1 = "aes-key-1"; + private static final String AES_KEY_2 = "aes-key-2"; + + private static final List ALL_AES_KEYS = Arrays.asList(AES_KEY_1, AES_KEY_2); + + @Autowired + private DummyAuthConfigMap mapConfig; + @Autowired + private ApplicationContext context; + + /** + * jUnit test set-up. + */ + @Before + public void testSetup() { + mapConfig.clearAllConfig(); + Security.removeProvider(HsmFacadeProvider.getInstance().getName()); + + } + + @Ignore + @Test + public void symmetricHsmFacadeKeyLoad() throws EaafException { + Pair key = loadSymmetricKey(AES_KEY_1); + Assert.assertNotNull("Key container is null", key); + Assert.assertNotNull("Key is null", key.getFirst()); + Assert.assertNotNull("Provider is null", key.getFirst()); + + } + + + @Ignore + @Test + public void symmetricHsmFacadeKeyOperations() throws Exception { + Pair key = loadSymmetricKey(AES_KEY_1); + Assert.assertNotNull("Key container is null", key); + new EncryptionTask(context, mapConfig, AES_KEY_2, 15).run(AES_KEY_2, 15); + + } + + @Test + public void symmetricHsmFacadeMultithreatKeyOperations() throws Exception { + Pair key = loadSymmetricKey(AES_KEY_1); + Assert.assertNotNull("Key container is null", key); + + int threads = 30; + + ArrayList taskList = new ArrayList(); + ArrayList threadList = new ArrayList(); + for(int i=0; i < threads; i++){ + EncryptionTask task = new EncryptionTask(context, mapConfig, ALL_AES_KEYS.get(i % 2), 20); + taskList.add(task); + Thread t = new Thread(task); + threadList.add(t); + t.start(); + } + + // wait until they are all done + log.trace("Wait for mandate sources .... "); + for(int i=0; i el.getError() != null) + .findFirst() + .isPresent()); + + + } + + private Pair loadSymmetricKey(String keyName) throws EaafException { + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_HOST, HSM_FACASE_HOST); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_PORT, HSM_FACASE_PORT); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_SSLTRUST, HSM_FACASE_SSL_TRUST); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_USERNAME, HSM_FACASE_USERNAME); + mapConfig.putConfigValue(EaafKeyStoreFactory.CONFIG_PROP_HSM_FACADE_CLIENT_PASSWORD, HSM_FACASE_PASSWORD); + + final EaafKeyStoreFactory keyStoreFactory = context.getBean(EaafKeyStoreFactory.class); + Assert.assertTrue("HSM Facade state wrong", keyStoreFactory.isHsmFacadeInitialized()); + + SymmetricKeyConfiguration keyConfig = new SymmetricKeyConfiguration(); + keyConfig.setFriendlyName("jUnit test"); + keyConfig.setKeyType(SymmetricKeyType.HSMFACADE); + keyConfig.setKeyStoreName("authhandler"); + keyConfig.setKeyAlias(keyName); + + return keyStoreFactory.buildNewSymmetricKey(keyConfig); + } + +} diff --git a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml index 4af34b51..672efe5d 100644 --- a/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml +++ b/eaaf_core_utils/src/test/resources/spring/test_eaaf_pvp_lazy.beans.xml @@ -20,4 +20,13 @@ + + + + + + + + \ No newline at end of file -- cgit v1.2.3