-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3105 from mercedes-benz/feature-837-encrypt-sechu…
…b-configuration-in-db Feature 837 subframework for encrypting data at rest.
- Loading branch information
Showing
24 changed files
with
2,447 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
.../java/com/mercedesbenz/sechub/commons/core/security/persistence/AbstractBinaryString.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.mercedesbenz.sechub.commons.core.security.persistence; | ||
|
||
import java.util.Arrays; | ||
|
||
/** | ||
* @author Jeremias Eppler | ||
*/ | ||
public abstract class AbstractBinaryString implements BinaryString { | ||
byte[] bytes; | ||
|
||
protected AbstractBinaryString(byte[] bytes) { | ||
if (bytes == null) { | ||
throw new IllegalArgumentException("Byte array cannot be null."); | ||
} | ||
|
||
this.bytes = bytes; | ||
} | ||
|
||
protected AbstractBinaryString(String string) { | ||
if (string == null) { | ||
throw new IllegalArgumentException("String cannot be null."); | ||
} | ||
|
||
this.bytes = string.getBytes(); | ||
} | ||
|
||
public abstract String toString(); | ||
|
||
public byte[] getBytes() { | ||
// deep copy | ||
return Arrays.copyOf(bytes, bytes.length); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = 1; | ||
result = prime * result + Arrays.hashCode(bytes); | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
AbstractBinaryString other = (AbstractBinaryString) obj; | ||
return Arrays.equals(bytes, other.bytes); | ||
} | ||
} |
141 changes: 141 additions & 0 deletions
141
...re/src/main/java/com/mercedesbenz/sechub/commons/core/security/persistence/AesGcmSiv.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package com.mercedesbenz.sechub.commons.core.security.persistence; | ||
|
||
import java.security.InvalidAlgorithmParameterException; | ||
import java.security.InvalidKeyException; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.Provider; | ||
import java.security.SecureRandom; | ||
import java.security.Security; | ||
|
||
import javax.crypto.BadPaddingException; | ||
import javax.crypto.Cipher; | ||
import javax.crypto.IllegalBlockSizeException; | ||
import javax.crypto.NoSuchPaddingException; | ||
import javax.crypto.SecretKey; | ||
import javax.crypto.spec.GCMParameterSpec; | ||
import javax.crypto.spec.SecretKeySpec; | ||
|
||
import org.bouncycastle.jce.provider.BouncyCastleProvider; | ||
|
||
/** | ||
* Providing access to AES-GCM-SIV | ||
* | ||
* AES-GCM-SIV is a nonce misuse-resistant authenticated encryption algorithm. | ||
* | ||
* For more information refer to | ||
* <a href="https://datatracker.ietf.org/doc/html/rfc8452">RFC 8452</a> | ||
* | ||
* @author Jeremias Eppler | ||
*/ | ||
public class AesGcmSiv implements PersistenceCipher { | ||
|
||
private SecretKey secret; | ||
private Provider cryptoProvider; | ||
private PersistenceCipherType cipherType; | ||
|
||
private static final String ALGORITHM = "AES/GCM-SIV/NoPadding"; | ||
|
||
/** | ||
* The recommended initialization vector (iv) for AES-GCM-SIV is 12 bytes or 96 | ||
* bits. | ||
* | ||
* For an explanation have a look at: - | ||
* https://datatracker.ietf.org/doc/html/rfc8452#section-4 - | ||
* https://crypto.stackexchange.com/questions/41601/aes-gcm-recommended-iv-size-why-12-bytes | ||
*/ | ||
public static final int IV_LENGTH_IN_BYTES = 12; | ||
|
||
public static final int AUTHENTICATION_TAG_LENGTH_IN_BITS = 16 * 8; // 16 bytes (128 bits) | ||
|
||
private AesGcmSiv(SecretKey secret, PersistenceCipherType cipherType) { | ||
this.secret = secret; | ||
this.cipherType = cipherType; | ||
cryptoProvider = new BouncyCastleProvider(); | ||
Security.addProvider(cryptoProvider); | ||
} | ||
|
||
public static AesGcmSiv create(BinaryString secret) throws InvalidKeyException { | ||
AesGcmSiv instance = null; | ||
|
||
byte[] rawSecret = secret.getBytes(); | ||
|
||
if (rawSecret.length == 32 || rawSecret.length == 16) { | ||
PersistenceCipherType cipherType = (rawSecret.length == 32) ? PersistenceCipherType.AES_GCM_SIV_256 : PersistenceCipherType.AES_GCM_SIV_128; | ||
SecretKey secretKey = new SecretKeySpec(rawSecret, 0, rawSecret.length, "AES"); | ||
|
||
instance = new AesGcmSiv(secretKey, cipherType); | ||
} else { | ||
throw new InvalidKeyException("The secret has to be 128 or 256 bits long, but was " + (rawSecret.length * 8) + " bits long."); | ||
} | ||
|
||
return instance; | ||
} | ||
|
||
public BinaryString generateNewInitializationVector() { | ||
return generateNewInitializationVector(BinaryStringEncodingType.BASE64); | ||
} | ||
|
||
public BinaryString generateNewInitializationVector(BinaryStringEncodingType encodingType) { | ||
byte[] initializationVector = new byte[IV_LENGTH_IN_BYTES]; | ||
|
||
SecureRandom random = new SecureRandom(); | ||
random.nextBytes(initializationVector); | ||
|
||
return BinaryStringFactory.createFromBytes(initializationVector, encodingType); | ||
} | ||
|
||
public BinaryString encrypt(String plaintext, BinaryString initializationVector) throws InvalidAlgorithmParameterException, InvalidKeyException { | ||
return encrypt(plaintext, initializationVector, BinaryStringEncodingType.BASE64); | ||
} | ||
|
||
public String decrypt(BinaryString ciphertext, BinaryString initializationVector) | ||
throws InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { | ||
Cipher cipher; | ||
try { | ||
cipher = Cipher.getInstance(ALGORITHM, cryptoProvider); | ||
|
||
SecretKeySpec keySpec = new SecretKeySpec(secret.getEncoded(), "AES"); | ||
|
||
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(AUTHENTICATION_TAG_LENGTH_IN_BITS, initializationVector.getBytes()); | ||
|
||
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec); | ||
|
||
byte[] ciphertextBytes = ciphertext.getBytes(); | ||
|
||
byte[] plaintextBytes = cipher.doFinal(ciphertextBytes); | ||
|
||
String plaintext = new String(plaintextBytes); | ||
|
||
return plaintext; | ||
} catch (NoSuchAlgorithmException | NoSuchPaddingException providerException) { | ||
throw new IllegalStateException("Decryption not possible, please check the provider", providerException); | ||
} | ||
} | ||
|
||
@Override | ||
public PersistenceCipherType getCipherType() { | ||
return cipherType; | ||
} | ||
|
||
@Override | ||
public BinaryString encrypt(String plaintext, BinaryString initializationVector, BinaryStringEncodingType encodingType) | ||
throws InvalidAlgorithmParameterException, InvalidKeyException { | ||
try { | ||
Cipher cipher = Cipher.getInstance(ALGORITHM, cryptoProvider); | ||
|
||
SecretKeySpec keySpec = new SecretKeySpec(secret.getEncoded(), "AES"); | ||
|
||
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(AUTHENTICATION_TAG_LENGTH_IN_BITS, initializationVector.getBytes()); | ||
|
||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec); | ||
|
||
byte[] ciphertext = cipher.doFinal(plaintext.getBytes()); | ||
|
||
return BinaryStringFactory.createFromBytes(ciphertext, encodingType); | ||
} catch (NoSuchAlgorithmException | NoSuchPaddingException providerException) { | ||
throw new IllegalStateException("Encryption not possible, please check the provider", providerException); | ||
} catch (BadPaddingException | IllegalBlockSizeException paddingBlockException) { | ||
throw new IllegalStateException("Should not occure. AES in GCM-SIV mode does not require padding.", paddingBlockException); | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
...src/main/java/com/mercedesbenz/sechub/commons/core/security/persistence/Base64String.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.mercedesbenz.sechub.commons.core.security.persistence; | ||
|
||
import java.util.Base64; | ||
|
||
/** | ||
* A base64 encoded string. | ||
* | ||
* @author Jeremias Eppler | ||
* | ||
*/ | ||
public class Base64String extends AbstractBinaryString { | ||
|
||
Base64String(byte[] bytes) { | ||
super(bytes); | ||
} | ||
|
||
Base64String(String string) { | ||
super(string); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return Base64.getEncoder().encodeToString(bytes); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = 1; | ||
result = prime * result + java.util.Arrays.hashCode(bytes); | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
Base64String other = (Base64String) obj; | ||
return java.util.Arrays.equals(bytes, other.bytes); | ||
} | ||
|
||
@Override | ||
public BinaryStringEncodingType getType() { | ||
return BinaryStringEncodingType.BASE64; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...src/main/java/com/mercedesbenz/sechub/commons/core/security/persistence/BinaryString.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.mercedesbenz.sechub.commons.core.security.persistence; | ||
|
||
/** | ||
* A binary string type which knows it's encoding. | ||
* | ||
* The binary string keeps it's internal representation in binary format. In | ||
* addition, the binary string knows it's encoding (e.g. base64 etc.). | ||
* | ||
* @see BinaryStringEncodingType | ||
* | ||
* @author Jeremias Eppler | ||
*/ | ||
public interface BinaryString { | ||
public byte[] getBytes(); | ||
|
||
public String toString(); | ||
|
||
public BinaryStringEncodingType getType(); | ||
} |
25 changes: 25 additions & 0 deletions
25
...a/com/mercedesbenz/sechub/commons/core/security/persistence/BinaryStringEncodingType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.mercedesbenz.sechub.commons.core.security.persistence; | ||
|
||
/** | ||
* Encoding type of a binary string. | ||
* | ||
* @see BinaryString | ||
* | ||
* @author Jeremias Eppler | ||
*/ | ||
public enum BinaryStringEncodingType { | ||
/** | ||
* A string with no encoding. | ||
*/ | ||
PLAIN, | ||
|
||
/** | ||
* A string encoded in hexadecimal format | ||
*/ | ||
HEX, | ||
|
||
/** | ||
* A string encoded in base64 format | ||
*/ | ||
BASE64, | ||
} |
Oops, something went wrong.