diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithm.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithm.java index 69c54a173..6f463fc82 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithm.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithm.java @@ -20,93 +20,91 @@ */ package org.eclipse.tractusx.edc.data.encryption.algorithms.aes; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.eclipse.tractusx.edc.data.encryption.algorithms.CryptoAlgorithm; +import org.eclipse.tractusx.edc.data.encryption.data.CryptoDataFactory; +import org.eclipse.tractusx.edc.data.encryption.data.DecryptedData; +import org.eclipse.tractusx.edc.data.encryption.data.EncryptedData; +import org.eclipse.tractusx.edc.data.encryption.key.AesKey; +import org.eclipse.tractusx.edc.data.encryption.util.ArrayUtil; + import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.Objects; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; -import lombok.NonNull; -import lombok.SneakyThrows; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.eclipse.tractusx.edc.data.encryption.algorithms.CryptoAlgorithm; -import org.eclipse.tractusx.edc.data.encryption.data.CryptoDataFactory; -import org.eclipse.tractusx.edc.data.encryption.data.DecryptedData; -import org.eclipse.tractusx.edc.data.encryption.data.EncryptedData; -import org.eclipse.tractusx.edc.data.encryption.key.AesKey; -import org.eclipse.tractusx.edc.data.encryption.util.ArrayUtil; -import org.jetbrains.annotations.NotNull; public class AesAlgorithm implements CryptoAlgorithm { - private static final String AES_GCM = "AES/GCM/NoPadding"; - private static final String AES = "AES"; - private static final Object MONITOR = new Object(); + private static final String AES_GCM = "AES/GCM/NoPadding"; + private static final String AES = "AES"; + private static final Object MONITOR = new Object(); + + private final SecureRandom secureRandom; - private final SecureRandom secureRandom; + private final CryptoDataFactory cryptoDataFactory; + private AesInitializationVectorIterator initializationVectorIterator; - @NonNull private final CryptoDataFactory cryptoDataFactory; - private AesInitializationVectorIterator initializationVectorIterator; + public AesAlgorithm(CryptoDataFactory cryptoDataFactory) { + this.cryptoDataFactory = Objects.requireNonNull(cryptoDataFactory); - @SneakyThrows - public AesAlgorithm(@NotNull CryptoDataFactory cryptoDataFactory) { - this.cryptoDataFactory = cryptoDataFactory; + // We use new SecureRandom() and not SecureRandom.getInstanceStrong(), as the second one + // would use a blocking algorithm, which leads to an increased encryption time of up to 3 + // minutes. Since we have already used /dev/urandom, which only provides pseudo-randomness and + // is also non-blocking, switching to a non-blocking algorithm should not matter here either. + this.secureRandom = new SecureRandom(); + this.initializationVectorIterator = new AesInitializationVectorIterator(this.secureRandom); + } - // We use new SecureRandom() and not SecureRandom.getInstanceStrong(), as the second one - // would use a blocking algorithm, which leads to an increased encryption time of up to 3 - // minutes. Since we have already used /dev/urandom, which only provides pseudo-randomness and - // is also non-blocking, switching to a non-blocking algorithm should not matter here either. - this.secureRandom = new SecureRandom(); - this.initializationVectorIterator = new AesInitializationVectorIterator(this.secureRandom); - } + @Override + public synchronized EncryptedData encrypt(DecryptedData data, AesKey key) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - @Override - public synchronized EncryptedData encrypt(DecryptedData data, AesKey key) - throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, - NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { + final byte[] initializationVector; + synchronized (MONITOR) { + if (!initializationVectorIterator.hasNext()) { + initializationVectorIterator = new AesInitializationVectorIterator(this.secureRandom); + } - final byte[] initializationVector; - synchronized (MONITOR) { - if (!initializationVectorIterator.hasNext()) { - initializationVectorIterator = new AesInitializationVectorIterator(this.secureRandom); - } + initializationVector = initializationVectorIterator.next(); + } - initializationVector = initializationVectorIterator.next(); + Cipher cipher = Cipher.getInstance(AES_GCM, new BouncyCastleProvider()); + final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), AES); + final GCMParameterSpec gcmParameterSpec = + new GCMParameterSpec(16 * 8 /* =128 */, initializationVector); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec); + byte[] encrypted = cipher.doFinal(data.getBytes()); + byte[] encryptedWithVector = ArrayUtil.concat(initializationVector, encrypted); + + return cryptoDataFactory.encryptedFromBytes(encryptedWithVector); } - Cipher cipher = Cipher.getInstance(AES_GCM, new BouncyCastleProvider()); - final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), AES); - final GCMParameterSpec gcmParameterSpec = - new GCMParameterSpec(16 * 8 /* =128 */, initializationVector); - cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec); - byte[] encrypted = cipher.doFinal(data.getBytes()); - byte[] encryptedWithVector = ArrayUtil.concat(initializationVector, encrypted); - - return cryptoDataFactory.encryptedFromBytes(encryptedWithVector); - } - - @Override - public DecryptedData decrypt(EncryptedData data, AesKey key) - throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, - NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - byte[] encryptedWithVector = data.getBytes(); - byte[] initializationVector = ArrayUtil.subArray(encryptedWithVector, 0, 16); - byte[] encrypted = ArrayUtil.subArray(encryptedWithVector, 16, encryptedWithVector.length - 16); - - Cipher cipher = Cipher.getInstance(AES_GCM, new BouncyCastleProvider()); - final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), AES); - final GCMParameterSpec gcmParameterSpec = - new GCMParameterSpec(16 * 8 /* =128 */, initializationVector); - cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec); - byte[] decryptedData = cipher.doFinal(encrypted); - return cryptoDataFactory.decryptedFromBytes(decryptedData); - } - - public String getAlgorithm() { - return this.secureRandom.getAlgorithm(); - } + @Override + public DecryptedData decrypt(EncryptedData data, AesKey key) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { + byte[] encryptedWithVector = data.getBytes(); + byte[] initializationVector = ArrayUtil.subArray(encryptedWithVector, 0, 16); + byte[] encrypted = ArrayUtil.subArray(encryptedWithVector, 16, encryptedWithVector.length - 16); + + Cipher cipher = Cipher.getInstance(AES_GCM, new BouncyCastleProvider()); + final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), AES); + final GCMParameterSpec gcmParameterSpec = + new GCMParameterSpec(16 * 8 /* =128 */, initializationVector); + cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec); + byte[] decryptedData = cipher.doFinal(encrypted); + return cryptoDataFactory.decryptedFromBytes(decryptedData); + } + + public String getAlgorithm() { + return this.secureRandom.getAlgorithm(); + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIterator.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIterator.java index cd0a6b1ec..73d02c3d5 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIterator.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIterator.java @@ -20,51 +20,50 @@ */ package org.eclipse.tractusx.edc.data.encryption.algorithms.aes; +import org.eclipse.tractusx.edc.data.encryption.util.ArrayUtil; + import java.security.SecureRandom; import java.util.Iterator; import java.util.NoSuchElementException; -import lombok.SneakyThrows; -import org.eclipse.tractusx.edc.data.encryption.util.ArrayUtil; public class AesInitializationVectorIterator implements Iterator { - public static final int RANDOM_SIZE = 12; - public static final int COUNTER_SIZE = 4; - - private final ByteCounter counter; + public static final int RANDOM_SIZE = 12; + public static final int COUNTER_SIZE = 4; - private SecureRandom secureRandom; + private final ByteCounter counter; - public AesInitializationVectorIterator(SecureRandom secureRandom) { - this.counter = new ByteCounter(COUNTER_SIZE); - this.secureRandom = secureRandom; - } + private SecureRandom secureRandom; - public AesInitializationVectorIterator(ByteCounter byteCounter) { - this.counter = byteCounter; - } + public AesInitializationVectorIterator(SecureRandom secureRandom) { + this.counter = new ByteCounter(COUNTER_SIZE); + this.secureRandom = secureRandom; + } - @Override - public boolean hasNext() { - return !counter.isMaxed(); - } + public AesInitializationVectorIterator(ByteCounter byteCounter) { + this.counter = byteCounter; + } - @Override - public byte[] next() { - if (counter.isMaxed()) { - throw new NoSuchElementException(getClass().getSimpleName() + " has no more elements"); + @Override + public boolean hasNext() { + return !counter.isMaxed(); } - byte[] random = getNextRandom(); - counter.increment(); + @Override + public byte[] next() { + if (counter.isMaxed()) { + throw new NoSuchElementException(getClass().getSimpleName() + " has no more elements"); + } - return ArrayUtil.concat(random, counter.getBytes()); - } + byte[] random = getNextRandom(); + counter.increment(); - @SneakyThrows - public byte[] getNextRandom() { - byte[] newVector = new byte[RANDOM_SIZE]; - secureRandom.nextBytes(newVector); - return newVector; - } + return ArrayUtil.concat(random, counter.getBytes()); + } + + public byte[] getNextRandom() { + byte[] newVector = new byte[RANDOM_SIZE]; + secureRandom.nextBytes(newVector); + return newVector; + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/ByteCounter.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/ByteCounter.java index 55eec8184..e7874c158 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/ByteCounter.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/ByteCounter.java @@ -19,63 +19,69 @@ */ package org.eclipse.tractusx.edc.data.encryption.algorithms.aes; -/** Big Endian Byte Counter */ +/** + * Big Endian Byte Counter + */ public class ByteCounter { - private final byte[] counter; - - /** - * Constructs a new ByteCounter with the given number of bytes. E.g. a ByteCounter with 4 bytes - * will have a counter value of [0, 0, 0, 0]. - * - * @param size number of bytes used by the counter - */ - public ByteCounter(int size) { - this.counter = new byte[size]; - } + private final byte[] counter; - /** - * Constructs a new ByteCounter with the given counter value. Counter cannot grow bigger than the - * size of the array. - * - * @param counter initial counter value - */ - public ByteCounter(byte[] counter) { - this.counter = counter; - } + /** + * Constructs a new ByteCounter with the given number of bytes. E.g. a ByteCounter with 4 bytes + * will have a counter value of [0, 0, 0, 0]. + * + * @param size number of bytes used by the counter + */ + public ByteCounter(int size) { + this.counter = new byte[size]; + } - /** Returns the counter value as a byte array. */ - public byte[] getBytes() { - return counter; - } + /** + * Constructs a new ByteCounter with the given counter value. Counter cannot grow bigger than the + * size of the array. + * + * @param counter initial counter value + */ + public ByteCounter(byte[] counter) { + this.counter = counter; + } - /** Returns true if counter is maxed */ - public boolean isMaxed() { - for (byte b : counter) { - if (b != (byte) 0xff) return false; + /** + * Returns the counter value as a byte array. + */ + public byte[] getBytes() { + return counter; } - return true; - } - /** - * Increments the counter by one. - * - * @throws IllegalStateException if the counter is already maxed - */ - public void increment() { - incrementByte(counter.length - 1); - } + /** + * Returns true if counter is maxed + */ + public boolean isMaxed() { + for (byte b : counter) { + if (b != (byte) 0xff) return false; + } + return true; + } - private void incrementByte(int index) { - if (isMaxed()) { - throw new IllegalStateException("Counter is already maxed"); + /** + * Increments the counter by one. + * + * @throws IllegalStateException if the counter is already maxed + */ + public void increment() { + incrementByte(counter.length - 1); } - if (counter[index] == (byte) 0xff) { - incrementByte(index - 1); - counter[index] = (byte) 0x00; - } else { - counter[index]++; + private void incrementByte(int index) { + if (isMaxed()) { + throw new IllegalStateException("Counter is already maxed"); + } + + if (counter[index] == (byte) 0xff) { + incrementByte(index - 1); + counter[index] = (byte) 0x00; + } else { + counter[index]++; + } } - } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/data/CryptoDataFactoryImpl.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/data/CryptoDataFactoryImpl.java index b23966170..a01331275 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/data/CryptoDataFactoryImpl.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/data/CryptoDataFactoryImpl.java @@ -19,58 +19,89 @@ */ package org.eclipse.tractusx.edc.data.encryption.data; -import lombok.Value; import org.bouncycastle.util.encoders.Base64; public class CryptoDataFactoryImpl implements CryptoDataFactory { - public DecryptedData decryptedFromText(String text) { - final byte[] bytes = text.getBytes(); - final String base64 = Base64.toBase64String(bytes); - return new DecryptedDataImpl(bytes, base64, text); - } - - public DecryptedData decryptedFromBase64(String base64) { - final byte[] bytes = Base64.decode(base64); - final String text = new String(bytes); - return new DecryptedDataImpl(bytes, base64, text); - } - - public DecryptedData decryptedFromBytes(byte[] bytes) { - final String base64 = Base64.toBase64String(bytes); - final String text = new String(bytes); - return new DecryptedDataImpl(bytes, base64, text); - } - - public EncryptedData encryptedFromText(String text) { - final byte[] bytes = text.getBytes(); - final String base64 = Base64.toBase64String(bytes); - return new EncryptedDataImpl(bytes, base64, text); - } - - public EncryptedData encryptedFromBase64(String base64) { - final byte[] bytes = Base64.decode(base64); - final String text = new String(bytes); - return new EncryptedDataImpl(bytes, base64, text); - } - - public EncryptedData encryptedFromBytes(byte[] bytes) { - final String base64 = Base64.toBase64String(bytes); - final String text = new String(bytes); - return new EncryptedDataImpl(bytes, base64, text); - } - - @Value - private static class DecryptedDataImpl implements DecryptedData { - byte[] bytes; - String base64; - String text; - } - - @Value - private static class EncryptedDataImpl implements EncryptedData { - byte[] bytes; - String base64; - String text; - } + public DecryptedData decryptedFromText(String text) { + final byte[] bytes = text.getBytes(); + final String base64 = Base64.toBase64String(bytes); + return new DecryptedDataImpl(bytes, base64, text); + } + + public DecryptedData decryptedFromBase64(String base64) { + final byte[] bytes = Base64.decode(base64); + final String text = new String(bytes); + return new DecryptedDataImpl(bytes, base64, text); + } + + public DecryptedData decryptedFromBytes(byte[] bytes) { + final String base64 = Base64.toBase64String(bytes); + final String text = new String(bytes); + return new DecryptedDataImpl(bytes, base64, text); + } + + public EncryptedData encryptedFromText(String text) { + final byte[] bytes = text.getBytes(); + final String base64 = Base64.toBase64String(bytes); + return new EncryptedDataImpl(bytes, base64, text); + } + + public EncryptedData encryptedFromBase64(String base64) { + final byte[] bytes = Base64.decode(base64); + final String text = new String(bytes); + return new EncryptedDataImpl(bytes, base64, text); + } + + public EncryptedData encryptedFromBytes(byte[] bytes) { + final String base64 = Base64.toBase64String(bytes); + final String text = new String(bytes); + return new EncryptedDataImpl(bytes, base64, text); + } + + + private static class DecryptedDataImpl implements DecryptedData { + private final byte[] bytes; + private final String base64; + private final String text; + + private DecryptedDataImpl(byte[] bytes, String base64, String text) { + this.bytes = bytes; + this.base64 = base64; + this.text = text; + } + + @Override + public byte[] getBytes() { + return bytes; + } + + @Override + public String getBase64() { + return base64; + } + } + + + private static class EncryptedDataImpl implements EncryptedData { + private final byte[] bytes; + private final String base64; + private final String text; + + private EncryptedDataImpl(byte[] bytes, String base64, String text) { + this.bytes = bytes; + this.base64 = base64; + this.text = text; + } + + @Override + public byte[] getBytes() { + return bytes; + } + + @Override + public String getBase64() { + return base64; + } + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterConfiguration.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterConfiguration.java index 725828acc..0723306e4 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterConfiguration.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterConfiguration.java @@ -21,12 +21,28 @@ package org.eclipse.tractusx.edc.data.encryption.encrypter; import java.time.Duration; -import lombok.NonNull; -import lombok.Value; -@Value + public class AesDataEncrypterConfiguration { - @NonNull String keySetAlias; - boolean cachingEnabled; - @NonNull Duration cachingDuration; + private final String keySetAlias; + private final boolean cachingEnabled; + private final Duration cachingDuration; + + public AesDataEncrypterConfiguration(String keySetAlias, boolean cachingEnabled, Duration cachingDuration) { + this.keySetAlias = keySetAlias; + this.cachingEnabled = cachingEnabled; + this.cachingDuration = cachingDuration; + } + + public Duration getCachingDuration() { + return cachingDuration; + } + + public boolean isCachingEnabled() { + return cachingEnabled; + } + + public String getKeySetAlias() { + return keySetAlias; + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterImpl.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterImpl.java index 160f57df0..d8b4add87 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterImpl.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/AesDataEncrypterImpl.java @@ -20,15 +20,6 @@ package org.eclipse.tractusx.edc.data.encryption.encrypter; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Optional; -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.transfer.dataplane.spi.security.DataEncrypter; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.monitor.Monitor; @@ -40,69 +31,85 @@ import org.eclipse.tractusx.edc.data.encryption.key.AesKey; import org.eclipse.tractusx.edc.data.encryption.provider.KeyProvider; -@RequiredArgsConstructor +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Optional; +import javax.crypto.AEADBadTagException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + public class AesDataEncrypterImpl implements DataEncrypter { - private final CryptoAlgorithm encryptionStrategy; - private final Monitor monitor; - private final KeyProvider keyProvider; - private final CryptoAlgorithm algorithm; - private final CryptoDataFactory cryptoDataFactory; + private final CryptoAlgorithm encryptionStrategy; + private final Monitor monitor; + private final KeyProvider keyProvider; + private final CryptoAlgorithm algorithm; + private final CryptoDataFactory cryptoDataFactory; - @Override - public String encrypt(String value) { - DecryptedData decryptedData = cryptoDataFactory.decryptedFromText(value); - AesKey key = keyProvider.getEncryptionKey(); + public AesDataEncrypterImpl(CryptoAlgorithm encryptionStrategy, Monitor monitor, KeyProvider keyProvider, CryptoAlgorithm algorithm, CryptoDataFactory cryptoDataFactory) { + this.encryptionStrategy = encryptionStrategy; + this.monitor = monitor; + this.keyProvider = keyProvider; + this.algorithm = algorithm; + this.cryptoDataFactory = cryptoDataFactory; + } - try { - EncryptedData encryptedData = algorithm.encrypt(decryptedData, key); - return encryptedData.getBase64(); - } catch (IllegalBlockSizeException - | BadPaddingException - | InvalidKeyException - | InvalidAlgorithmParameterException - | NoSuchPaddingException - | NoSuchAlgorithmException e) { - throw new EdcException(e); + @Override + public String encrypt(String value) { + DecryptedData decryptedData = cryptoDataFactory.decryptedFromText(value); + AesKey key = keyProvider.getEncryptionKey(); + + try { + EncryptedData encryptedData = algorithm.encrypt(decryptedData, key); + return encryptedData.getBase64(); + } catch (IllegalBlockSizeException + | BadPaddingException + | InvalidKeyException + | InvalidAlgorithmParameterException + | NoSuchPaddingException + | NoSuchAlgorithmException e) { + throw new EdcException(e); + } } - } - @Override - public String decrypt(String value) { - EncryptedData encryptedData = cryptoDataFactory.encryptedFromBase64(value); + @Override + public String decrypt(String value) { + EncryptedData encryptedData = cryptoDataFactory.encryptedFromBase64(value); - return keyProvider - .getDecryptionKeySet() - .map(key -> decrypt(encryptedData, key)) - .filter(Optional::isPresent) - .map(Optional::get) - .map(DecryptedData::getBytes) - .map(String::new) - .findFirst() - .orElseThrow( - () -> - new EdcException( - DataEncryptionExtension.EXTENSION_NAME - + ": Failed to decrypt data. This can happen if the key set is empty, contains invalid keys, the decryption key rotated out of the key set or because the data was encrypted by a different algorithm.")); - } + return keyProvider + .getDecryptionKeySet() + .map(key -> decrypt(encryptedData, key)) + .filter(Optional::isPresent) + .map(Optional::get) + .map(DecryptedData::getBytes) + .map(String::new) + .findFirst() + .orElseThrow( + () -> + new EdcException( + DataEncryptionExtension.EXTENSION_NAME + + ": Failed to decrypt data. This can happen if the key set is empty, contains invalid keys, the decryption key rotated out of the key set or because the data was encrypted by a different algorithm.")); + } - private Optional decrypt(EncryptedData data, AesKey key) { - try { - return Optional.of(encryptionStrategy.decrypt(data, key)); - } catch (AEADBadTagException e) { // thrown when wrong key is used for decryption - return Optional.empty(); - } catch (IllegalBlockSizeException - | BadPaddingException - | InvalidKeyException - | NoSuchPaddingException - | NoSuchAlgorithmException - | InvalidAlgorithmParameterException e) { - monitor.warning( - String.format( - DataEncryptionExtension.EXTENSION_NAME - + ": Exception decrypting data using key from rotating key set. %s", - e.getMessage())); - throw new EdcException(e); + private Optional decrypt(EncryptedData data, AesKey key) { + try { + return Optional.of(encryptionStrategy.decrypt(data, key)); + } catch (AEADBadTagException e) { // thrown when wrong key is used for decryption + return Optional.empty(); + } catch (IllegalBlockSizeException + | BadPaddingException + | InvalidKeyException + | NoSuchPaddingException + | NoSuchAlgorithmException + | InvalidAlgorithmParameterException e) { + monitor.warning( + String.format( + DataEncryptionExtension.EXTENSION_NAME + + ": Exception decrypting data using key from rotating key set. %s", + e.getMessage())); + throw new EdcException(e); + } } - } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterFactory.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterFactory.java index 916ab245f..c40e20b08 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterFactory.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterFactory.java @@ -21,9 +21,6 @@ package org.eclipse.tractusx.edc.data.encryption.encrypter; -import static java.lang.String.format; - -import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.transfer.dataplane.spi.security.DataEncrypter; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.security.Vault; @@ -36,45 +33,52 @@ import org.eclipse.tractusx.edc.data.encryption.provider.CachingKeyProvider; import org.eclipse.tractusx.edc.data.encryption.provider.KeyProvider; -@RequiredArgsConstructor -public class DataEncrypterFactory { +import static java.lang.String.format; - public static final String AES_ALGORITHM = "AES"; - public static final String NONE = "NONE"; +public class DataEncrypterFactory { - private final Vault vault; - private final Monitor monitor; - private final CryptoKeyFactory keyFactory; + public static final String AES_ALGORITHM = "AES"; + public static final String NONE = "NONE"; - public DataEncrypter createNoneEncrypter() { - return new DataEncrypter() { - @Override - public String encrypt(String data) { - return data; - } + private final Vault vault; + private final Monitor monitor; + private final CryptoKeyFactory keyFactory; - @Override - public String decrypt(String data) { - return data; - } - }; - } + public DataEncrypterFactory(Vault vault, Monitor monitor, CryptoKeyFactory keyFactory) { + this.vault = vault; + this.monitor = monitor; + this.keyFactory = keyFactory; + } - public DataEncrypter createAesEncrypter(AesDataEncrypterConfiguration configuration) { - KeyProvider keyProvider = - new AesKeyProvider(vault, configuration.getKeySetAlias(), keyFactory); + public DataEncrypter createNoneEncrypter() { + return new DataEncrypter() { + @Override + public String encrypt(String data) { + return data; + } - if (configuration.isCachingEnabled()) { - keyProvider = new CachingKeyProvider<>(keyProvider, configuration.getCachingDuration()); + @Override + public String decrypt(String data) { + return data; + } + }; } + + public DataEncrypter createAesEncrypter(AesDataEncrypterConfiguration configuration) { + KeyProvider keyProvider = + new AesKeyProvider(vault, configuration.getKeySetAlias(), keyFactory); - final CryptoDataFactory cryptoDataFactory = new CryptoDataFactoryImpl(); - final AesAlgorithm algorithm = new AesAlgorithm(cryptoDataFactory); + if (configuration.isCachingEnabled()) { + keyProvider = new CachingKeyProvider<>(keyProvider, configuration.getCachingDuration()); + } - monitor.debug( - format( - "AES algorithm was initialised with SecureRandom algorithm '%s'", - algorithm.getAlgorithm())); - return new AesDataEncrypterImpl(algorithm, monitor, keyProvider, algorithm, cryptoDataFactory); - } + final CryptoDataFactory cryptoDataFactory = new CryptoDataFactoryImpl(); + final AesAlgorithm algorithm = new AesAlgorithm(cryptoDataFactory); + + monitor.debug( + format( + "AES algorithm was initialised with SecureRandom algorithm '%s'", + algorithm.getAlgorithm())); + return new AesDataEncrypterImpl(algorithm, monitor, keyProvider, algorithm, cryptoDataFactory); + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/key/CryptoKeyFactoryImpl.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/key/CryptoKeyFactoryImpl.java index f3fa102a4..7a5b0fc15 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/key/CryptoKeyFactoryImpl.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/key/CryptoKeyFactoryImpl.java @@ -19,7 +19,6 @@ */ package org.eclipse.tractusx.edc.data.encryption.key; -import lombok.Value; import org.bouncycastle.util.encoders.Base64; public class CryptoKeyFactoryImpl implements CryptoKeyFactory { @@ -37,9 +36,24 @@ public AesKey fromBytes(byte[] key) { return new AesKeyImpl(key, Base64.toBase64String(key)); } - @Value + private static class AesKeyImpl implements AesKey { - byte[] bytes; - String base64; + private final byte[] bytes; + private final String base64; + + private AesKeyImpl(byte[] bytes, String base64) { + this.bytes = bytes; + this.base64 = base64; + } + + @Override + public byte[] getBytes() { + return bytes; + } + + @Override + public String getBase64() { + return base64; + } } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/AesKeyProvider.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/AesKeyProvider.java index 82b8eccdd..e740a6f43 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/AesKeyProvider.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/AesKeyProvider.java @@ -19,51 +19,56 @@ */ package org.eclipse.tractusx.edc.data.encryption.provider; -import java.util.Arrays; -import java.util.function.Predicate; -import java.util.stream.Stream; -import lombok.RequiredArgsConstructor; import org.bouncycastle.util.encoders.Base64; import org.eclipse.edc.spi.security.Vault; import org.eclipse.tractusx.edc.data.encryption.DataEncryptionExtension; import org.eclipse.tractusx.edc.data.encryption.key.AesKey; import org.eclipse.tractusx.edc.data.encryption.key.CryptoKeyFactory; -@RequiredArgsConstructor +import java.util.Arrays; +import java.util.function.Predicate; +import java.util.stream.Stream; + public class AesKeyProvider implements KeyProvider { - private static final String KEY_SEPARATOR = ","; + private static final String KEY_SEPARATOR = ","; + + private final Vault vault; + private final String vaultKeyAlias; + private final CryptoKeyFactory cryptoKeyFactory; - private final Vault vault; - private final String vaultKeyAlias; - private final CryptoKeyFactory cryptoKeyFactory; + public AesKeyProvider(Vault vault, String vaultKeyAlias, CryptoKeyFactory cryptoKeyFactory) { + this.vault = vault; + this.vaultKeyAlias = vaultKeyAlias; + this.cryptoKeyFactory = cryptoKeyFactory; + } - @Override - public Stream getDecryptionKeySet() { - return getKeysStream(); - } + @Override + public AesKey getEncryptionKey() { + return getKeysStream() + .findFirst() + .orElseThrow( + () -> + new RuntimeException( + DataEncryptionExtension.EXTENSION_NAME + + ": Vault must contain at least one key.")); + } - @Override - public AesKey getEncryptionKey() { - return getKeysStream() - .findFirst() - .orElseThrow( - () -> - new RuntimeException( - DataEncryptionExtension.EXTENSION_NAME - + ": Vault must contain at least one key.")); - } + @Override + public Stream getDecryptionKeySet() { + return getKeysStream(); + } - private Stream getKeysStream() { - return Arrays.stream(getKeys().split(KEY_SEPARATOR)) - .map(String::trim) - .filter(Predicate.not(String::isEmpty)) - .map(Base64::decode) - .map(cryptoKeyFactory::fromBytes); - } + private Stream getKeysStream() { + return Arrays.stream(getKeys().split(KEY_SEPARATOR)) + .map(String::trim) + .filter(Predicate.not(String::isEmpty)) + .map(Base64::decode) + .map(cryptoKeyFactory::fromBytes); + } - private String getKeys() { - String keys = vault.resolveSecret(vaultKeyAlias); - return keys == null ? "" : keys; - } + private String getKeys() { + String keys = vault.resolveSecret(vaultKeyAlias); + return keys == null ? "" : keys; + } } diff --git a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/CachingKeyProvider.java b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/CachingKeyProvider.java index b4b490918..4819b6386 100644 --- a/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/CachingKeyProvider.java +++ b/edc-extensions/data-encryption/src/main/java/org/eclipse/tractusx/edc/data/encryption/provider/CachingKeyProvider.java @@ -20,60 +20,73 @@ package org.eclipse.tractusx.edc.data.encryption.provider; +import org.eclipse.tractusx.edc.data.encryption.key.CryptoKey; + import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; -import lombok.NonNull; -import lombok.Value; -import org.eclipse.tractusx.edc.data.encryption.key.CryptoKey; public class CachingKeyProvider implements KeyProvider { - @NonNull private final KeyProvider decoratedProvider; - @NonNull private final Clock clock; - @NonNull private final Duration cacheExpiration; - - private CachedKeys cachedKeys; - - public CachingKeyProvider(KeyProvider keyProvider, Duration cacheExpiration) { - this(keyProvider, cacheExpiration, Clock.systemUTC()); - } - - public CachingKeyProvider(KeyProvider keyProvider, Duration cacheExpiration, Clock clock) { - - this.decoratedProvider = keyProvider; - this.cacheExpiration = cacheExpiration; - this.clock = clock; - } - - @Override - public T getEncryptionKey() { - checkCache(); - return cachedKeys.getEncryptionKey(); - } - - @Override - public Stream getDecryptionKeySet() { - checkCache(); - return cachedKeys.getDecryptionKeys().stream(); - } - - private void checkCache() { - if (cachedKeys == null || cachedKeys.expiration.isBefore(clock.instant())) { - T encryptionKey = decoratedProvider.getEncryptionKey(); - List decryptionKeys = decoratedProvider.getDecryptionKeySet().collect(Collectors.toList()); - cachedKeys = - new CachedKeys<>(encryptionKey, decryptionKeys, clock.instant().plus(cacheExpiration)); + private final KeyProvider decoratedProvider; + private final Clock clock; + private final Duration cacheExpiration; + + private CachedKeys cachedKeys; + + public CachingKeyProvider(KeyProvider keyProvider, Duration cacheExpiration) { + this(keyProvider, cacheExpiration, Clock.systemUTC()); + } + + public CachingKeyProvider(KeyProvider keyProvider, Duration cacheExpiration, Clock clock) { + this.decoratedProvider = Objects.requireNonNull(keyProvider); + this.cacheExpiration = Objects.requireNonNull(cacheExpiration); + this.clock = Objects.requireNonNull(clock); + } + + @Override + public T getEncryptionKey() { + checkCache(); + return cachedKeys.getEncryptionKey(); + } + + @Override + public Stream getDecryptionKeySet() { + checkCache(); + return cachedKeys.getDecryptionKeys().stream(); + } + + private void checkCache() { + if (cachedKeys == null || cachedKeys.expiration.isBefore(clock.instant())) { + T encryptionKey = decoratedProvider.getEncryptionKey(); + List decryptionKeys = decoratedProvider.getDecryptionKeySet().collect(Collectors.toList()); + cachedKeys = + new CachedKeys<>(encryptionKey, decryptionKeys, clock.instant().plus(cacheExpiration)); + } + } + + + private static class CachedKeys { + private final T encryptionKey; + private final List decryptionKeys; + private final Instant expiration; + + private CachedKeys(T encryptionKey, List decryptionKeys, Instant expiration) { + this.encryptionKey = encryptionKey; + this.decryptionKeys = decryptionKeys; + this.expiration = Objects.requireNonNull(expiration); + } + + public List getDecryptionKeys() { + return decryptionKeys; + } + + public T getEncryptionKey() { + return encryptionKey; + } } - } - - @Value - private static class CachedKeys { - T encryptionKey; - List decryptionKeys; - @NonNull Instant expiration; - } } diff --git a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithmTest.java b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithmTest.java index 4d19927fb..683a06f08 100644 --- a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithmTest.java +++ b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesAlgorithmTest.java @@ -19,7 +19,6 @@ */ package org.eclipse.tractusx.edc.data.encryption.algorithms.aes; -import lombok.SneakyThrows; import org.bouncycastle.util.encoders.Base64; import org.eclipse.tractusx.edc.data.encryption.data.CryptoDataFactory; import org.eclipse.tractusx.edc.data.encryption.data.CryptoDataFactoryImpl; @@ -31,62 +30,71 @@ class AesAlgorithmTest { - private static final byte[] KEY_128_BIT = Base64.decode("dVUjmYJzbwVcntkFZU+lNQ=="); - private static final byte[] KEY_196_BIT = Base64.decode("NcgHzzRTUC+z396tWG9hqIbeihujz0m8"); - private static final byte[] KEY_256_BIT = - Base64.decode("OSD+3NcZAmS/6UXbq6NL8UL+aQIAJDLL7BE2rBX5MtA="); - - private final AesAlgorithm strategy = new AesAlgorithm(new CryptoDataFactoryImpl()); - private final CryptoDataFactory cryptoDataFactory = new CryptoDataFactoryImpl(); - - @Test - void test128BitKey() { - testKey(KEY_128_BIT); - } - - @Test - void test196BitKey() { - testKey(KEY_196_BIT); - } - - @Test - void test256BitKey() { - testKey(KEY_256_BIT); - } - - @Test - @SneakyThrows - void testSameDataEncryptedDifferently() { - final AesKey aesKey = createKey(KEY_128_BIT); - final DecryptedData expected = cryptoDataFactory.decryptedFromText("same data"); - final EncryptedData result1 = strategy.encrypt(expected, aesKey); - final EncryptedData result2 = strategy.encrypt(expected, aesKey); - - Assertions.assertNotEquals(result1.getBase64(), result2.getBase64()); - } - - @SneakyThrows - void testKey(byte[] key) { - final AesKey aesKey = createKey(key); - final DecryptedData expected = cryptoDataFactory.decryptedFromText("I will be encrypted"); - final EncryptedData encryptedResult = strategy.encrypt(expected, aesKey); - final DecryptedData result = strategy.decrypt(encryptedResult, aesKey); - - Assertions.assertEquals(expected.getBase64(), result.getBase64()); - } - - AesKey createKey(byte[] key) { - return new AesKey() { - - @Override - public byte[] getBytes() { - return key; - } - - @Override - public String getBase64() { - return Base64.toBase64String(key); - } - }; - } + private static final byte[] KEY_128_BIT = Base64.decode("dVUjmYJzbwVcntkFZU+lNQ=="); + private static final byte[] KEY_196_BIT = Base64.decode("NcgHzzRTUC+z396tWG9hqIbeihujz0m8"); + private static final byte[] KEY_256_BIT = + Base64.decode("OSD+3NcZAmS/6UXbq6NL8UL+aQIAJDLL7BE2rBX5MtA="); + + private final AesAlgorithm strategy = new AesAlgorithm(new CryptoDataFactoryImpl()); + private final CryptoDataFactory cryptoDataFactory = new CryptoDataFactoryImpl(); + + @Test + void test128BitKey() { + testKey(KEY_128_BIT); + } + + @Test + void test196BitKey() { + testKey(KEY_196_BIT); + } + + @Test + void test256BitKey() { + testKey(KEY_256_BIT); + } + + @Test + void testSameDataEncryptedDifferently() { + final AesKey aesKey = createKey(KEY_128_BIT); + final DecryptedData expected = cryptoDataFactory.decryptedFromText("same data"); + + try { + final EncryptedData result1 = strategy.encrypt(expected, aesKey); + final EncryptedData result2 = strategy.encrypt(expected, aesKey); + + Assertions.assertNotEquals(result1.getBase64(), result2.getBase64()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + void testKey(byte[] key) { + final AesKey aesKey = createKey(key); + final DecryptedData expected = cryptoDataFactory.decryptedFromText("I will be encrypted"); + try { + final EncryptedData encryptedResult = strategy.encrypt(expected, aesKey); + final DecryptedData result = strategy.decrypt(encryptedResult, aesKey); + + + Assertions.assertEquals(expected.getBase64(), result.getBase64()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + AesKey createKey(byte[] key) { + return new AesKey() { + + @Override + public byte[] getBytes() { + return key; + } + + @Override + public String getBase64() { + return Base64.toBase64String(key); + } + }; + } } diff --git a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIteratorTest.java b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIteratorTest.java index ceebf50d6..f70a3bf70 100644 --- a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIteratorTest.java +++ b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/algorithms/aes/AesInitializationVectorIteratorTest.java @@ -20,61 +20,57 @@ */ package org.eclipse.tractusx.edc.data.encryption.algorithms.aes; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import lombok.SneakyThrows; import org.eclipse.tractusx.edc.data.encryption.util.ArrayUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + class AesInitializationVectorIteratorTest { - @Test - @SneakyThrows - void testDistinctVectors() { - final int vectorCount = 100; - final SecureRandom secureRandom = new SecureRandom(); - AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(secureRandom); + @Test + void testDistinctVectors() { + final int vectorCount = 100; + final SecureRandom secureRandom = new SecureRandom(); + AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(secureRandom); - List vectors = new ArrayList<>(); - for (var i = 0; i < vectorCount; i++) { - vectors.add(iterator.next()); - } + List vectors = new ArrayList<>(); + for (var i = 0; i < vectorCount; i++) { + vectors.add(iterator.next()); + } - long distinctVectors = vectors.stream().map(ArrayUtil::byteArrayToHex).distinct().count(); - Assertions.assertEquals(vectorCount, distinctVectors); - } + long distinctVectors = vectors.stream().map(ArrayUtil::byteArrayToHex).distinct().count(); + Assertions.assertEquals(vectorCount, distinctVectors); + } - @Test - @SneakyThrows - void testHasNextTrueOnCounterContinuing() { - ByteCounter counter = Mockito.mock(ByteCounter.class); - AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); + @Test + void testHasNextTrueOnCounterContinuing() { + ByteCounter counter = Mockito.mock(ByteCounter.class); + AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); - Mockito.when(counter.isMaxed()).thenReturn(false); - Assertions.assertTrue(iterator.hasNext()); - } + Mockito.when(counter.isMaxed()).thenReturn(false); + Assertions.assertTrue(iterator.hasNext()); + } - @Test - @SneakyThrows - void testHasNextFalseOnCounterEnd() { - ByteCounter counter = Mockito.mock(ByteCounter.class); - AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); + @Test + void testHasNextFalseOnCounterEnd() { + ByteCounter counter = Mockito.mock(ByteCounter.class); + AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); - Mockito.when(counter.isMaxed()).thenReturn(true); - Assertions.assertFalse(iterator.hasNext()); - } + Mockito.when(counter.isMaxed()).thenReturn(true); + Assertions.assertFalse(iterator.hasNext()); + } - @Test - @SneakyThrows - void testNoSuchElementExceptionOnCounterEnd() { - ByteCounter counter = Mockito.mock(ByteCounter.class); - AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); + @Test + void testNoSuchElementExceptionOnCounterEnd() { + ByteCounter counter = Mockito.mock(ByteCounter.class); + AesInitializationVectorIterator iterator = new AesInitializationVectorIterator(counter); - Mockito.when(counter.isMaxed()).thenReturn(true); - Assertions.assertThrows(NoSuchElementException.class, iterator::next); - } + Mockito.when(counter.isMaxed()).thenReturn(true); + Assertions.assertThrows(NoSuchElementException.class, iterator::next); + } } diff --git a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterAesComponentTest.java b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterAesComponentTest.java index aa9140629..6dcd103cb 100644 --- a/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterAesComponentTest.java +++ b/edc-extensions/data-encryption/src/test/java/org/eclipse/tractusx/edc/data/encryption/encrypter/DataEncrypterAesComponentTest.java @@ -19,7 +19,6 @@ */ package org.eclipse.tractusx.edc.data.encryption.encrypter; -import lombok.SneakyThrows; import org.eclipse.edc.connector.transfer.dataplane.spi.security.DataEncrypter; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.security.Vault; @@ -42,64 +41,68 @@ @SuppressWarnings("FieldCanBeLocal") class DataEncrypterAesComponentTest { - private static final String KEY_128_BIT_BASE_64 = "7h6sh6t6tchCmNnHjK2kFA=="; - private static final String KEY_256_BIT_BASE_64 = "OSD+3NcZAmS/6UXbq6NL8UL+aQIAJDLL7BE2rBX5MtA="; - - private DataEncrypter dataEncrypter; - private CryptoAlgorithm algorithm; - private KeyProvider keyProvider; - private CryptoKeyFactory cryptoKeyFactory; - private CryptoDataFactory cryptoDataFactory; - - // mocks - private Monitor monitor; - private Vault vault; - - @BeforeEach - void setup() { - monitor = Mockito.mock(Monitor.class); - vault = Mockito.mock(Vault.class); - - cryptoKeyFactory = new CryptoKeyFactoryImpl(); - cryptoDataFactory = new CryptoDataFactoryImpl(); - algorithm = new AesAlgorithm(cryptoDataFactory); - keyProvider = new AesKeyProvider(vault, "foo", cryptoKeyFactory); - - dataEncrypter = - new AesDataEncrypterImpl(algorithm, monitor, keyProvider, algorithm, cryptoDataFactory); - } - - @Test - @SneakyThrows - void testKeyRotation() { - Mockito.when(vault.resolveSecret(Mockito.anyString())) - .thenReturn( - String.format( - "%s, %s, %s, %s", - KEY_128_BIT_BASE_64, - KEY_128_BIT_BASE_64, - KEY_128_BIT_BASE_64, - KEY_256_BIT_BASE_64)); - - final AesKey key256Bit = cryptoKeyFactory.fromBase64(KEY_256_BIT_BASE_64); - final String expectedResult = "hello"; - final DecryptedData decryptedResult = cryptoDataFactory.decryptedFromText(expectedResult); - final EncryptedData encryptedResult = algorithm.encrypt(decryptedResult, key256Bit); - - var result = dataEncrypter.decrypt(encryptedResult.getBase64()); - - Assertions.assertEquals(expectedResult, result); - } - - @Test - void testEncryption() { - Mockito.when(vault.resolveSecret(Mockito.anyString())).thenReturn(KEY_128_BIT_BASE_64); - - final String expectedResult = "hello world!"; - - var encryptedResult = dataEncrypter.encrypt(expectedResult); - var result = dataEncrypter.decrypt(encryptedResult); - - Assertions.assertEquals(expectedResult, result); - } + private static final String KEY_128_BIT_BASE_64 = "7h6sh6t6tchCmNnHjK2kFA=="; + private static final String KEY_256_BIT_BASE_64 = "OSD+3NcZAmS/6UXbq6NL8UL+aQIAJDLL7BE2rBX5MtA="; + + private DataEncrypter dataEncrypter; + private CryptoAlgorithm algorithm; + private KeyProvider keyProvider; + private CryptoKeyFactory cryptoKeyFactory; + private CryptoDataFactory cryptoDataFactory; + + // mocks + private Monitor monitor; + private Vault vault; + + @BeforeEach + void setup() { + monitor = Mockito.mock(Monitor.class); + vault = Mockito.mock(Vault.class); + + cryptoKeyFactory = new CryptoKeyFactoryImpl(); + cryptoDataFactory = new CryptoDataFactoryImpl(); + algorithm = new AesAlgorithm(cryptoDataFactory); + keyProvider = new AesKeyProvider(vault, "foo", cryptoKeyFactory); + + dataEncrypter = + new AesDataEncrypterImpl(algorithm, monitor, keyProvider, algorithm, cryptoDataFactory); + } + + @Test + void testKeyRotation() { + Mockito.when(vault.resolveSecret(Mockito.anyString())) + .thenReturn( + String.format( + "%s, %s, %s, %s", + KEY_128_BIT_BASE_64, + KEY_128_BIT_BASE_64, + KEY_128_BIT_BASE_64, + KEY_256_BIT_BASE_64)); + + final AesKey key256Bit = cryptoKeyFactory.fromBase64(KEY_256_BIT_BASE_64); + final String expectedResult = "hello"; + final DecryptedData decryptedResult = cryptoDataFactory.decryptedFromText(expectedResult); + + try { + final EncryptedData encryptedResult = algorithm.encrypt(decryptedResult, key256Bit); + + var result = dataEncrypter.decrypt(encryptedResult.getBase64()); + + Assertions.assertEquals(expectedResult, result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + void testEncryption() { + Mockito.when(vault.resolveSecret(Mockito.anyString())).thenReturn(KEY_128_BIT_BASE_64); + + final String expectedResult = "hello world!"; + + var encryptedResult = dataEncrypter.encrypt(expectedResult); + var result = dataEncrypter.decrypt(encryptedResult); + + Assertions.assertEquals(expectedResult, result); + } }