Skip to content

Commit

Permalink
Merge pull request #179 from catenax-ng/feature/153_remove_lombok_dat…
Browse files Browse the repository at this point in the history
…a_encryption
  • Loading branch information
florianrusch-zf authored Apr 5, 2023
2 parents 335453c + af40856 commit 896458b
Show file tree
Hide file tree
Showing 13 changed files with 636 additions and 538 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<AesKey> {

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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte[]> {

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]++;
}
}
}
}
Loading

0 comments on commit 896458b

Please sign in to comment.