-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds the ability for a user to specify the algorithm/mode of operation/padding directly in their `application.yml`. This is pretty flexible and allows the user easy access to many JCA "transformations" without them needing to write any code. A new, incompatible format for the encrypted binary blob is introduced to achieve this. The versioned format allows us to make continuous improvements to it without rendering all previous outputs undecryptable. Provisions were made for version-1 outputs: these can still be decrypted. When migrating from version 1 to version 2, legacy key versions should be marked as such in the config. These key versions are then only allowed to decrypt: no new encryptions can be performed with them.
- Loading branch information
1 parent
97f5b5b
commit 1a8f1af
Showing
13 changed files
with
706 additions
and
268 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
70 changes: 45 additions & 25 deletions
70
src/main/java/com/bol/config/CryptVaultAutoConfiguration.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 |
---|---|---|
@@ -1,77 +1,97 @@ | ||
package com.bol.config; | ||
|
||
import com.bol.crypt.CryptVault; | ||
import com.bol.crypt.KeyVersion; | ||
import com.bol.crypt.KeyVersions; | ||
import org.springframework.boot.autoconfigure.AutoConfiguration; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Base64; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
@AutoConfiguration | ||
@ConditionalOnProperty("cryptvault.keys[0].key") | ||
@EnableConfigurationProperties(value = {CryptVaultAutoConfiguration.CryptVaultConfigurationProperties.class}) | ||
public class CryptVaultAutoConfiguration { | ||
|
||
@Bean | ||
CryptVault cryptVault(CryptVaultConfigurationProperties properties) { | ||
CryptVault cryptVault = new CryptVault(); | ||
if (properties.keys == null || properties.keys.isEmpty()) throw new IllegalArgumentException("property 'keys' is not set"); | ||
if (properties.keys == null || properties.keys.isEmpty()) { | ||
throw new IllegalStateException("property 'keys' is not set"); | ||
} | ||
|
||
for (Key key : properties.keys) { | ||
byte[] secretKeyBytes = Base64.getDecoder().decode(key.key); | ||
cryptVault.with256BitAesCbcPkcs5PaddingAnd128BitSaltKey(key.version, secretKeyBytes); | ||
KeyVersions versions = new KeyVersions(); | ||
for (KeyVersionProperties props : properties.keys) { | ||
Objects.requireNonNull(props.key, String.format("key version %d has a null key", props.version)); | ||
if (props.version < 1 || props.version > 255) { | ||
throw new IllegalArgumentException(String.format("version should be [1, 255], got %d", props.version)); | ||
} | ||
if (props.transformation == null) props.transformation = "AES/CBC/PKCS5Padding"; | ||
versions.addVersion(new KeyVersion(props.version, props.transformation, props.key, props.legacy)); | ||
} | ||
|
||
if (properties.defaultKey != null) { | ||
cryptVault.withDefaultKeyVersion(properties.defaultKey); | ||
if (properties.defaultKey < 1 || properties.defaultKey > 255) { | ||
var msg = String.format("default key version should be in [1, 255], was %d", properties.defaultKey); | ||
throw new IllegalStateException(msg); | ||
} | ||
versions.get(properties.defaultKey).ifPresentOrElse( | ||
versions::setDefault, | ||
() -> { | ||
var msg = String.format("no version %d registered; cannot make default", properties.defaultKey); | ||
throw new IllegalStateException(msg); | ||
}); | ||
} | ||
|
||
return cryptVault; | ||
return CryptVault.of(versions); | ||
} | ||
|
||
@Component | ||
@ConfigurationProperties("cryptvault") | ||
public static class CryptVaultConfigurationProperties { | ||
List<Key> keys; | ||
List<KeyVersionProperties> keys; | ||
Integer defaultKey; | ||
|
||
public void setKeys(List<Key> keys) { | ||
public void setKeys(List<KeyVersionProperties> keys) { | ||
this.keys = keys; | ||
} | ||
|
||
public void setDefaultKey(Integer defaultKey) { | ||
this.defaultKey = defaultKey; | ||
} | ||
|
||
public List<Key> getKeys() { | ||
return keys; | ||
} | ||
|
||
public Integer getDefaultKey() { | ||
return defaultKey; | ||
} | ||
} | ||
|
||
public static class Key { | ||
public static class KeyVersionProperties { | ||
int version; | ||
String transformation; | ||
String key; | ||
boolean legacy; | ||
|
||
public void setVersion(int version) { | ||
this.version = version; | ||
} | ||
|
||
public void setTransformation(String transformation) { | ||
this.transformation = transformation; | ||
} | ||
|
||
public void setKey(String key) { | ||
this.key = key; | ||
} | ||
|
||
public int getVersion() { | ||
return version; | ||
public void setLegacy(boolean legacy) { | ||
this.legacy = legacy; | ||
} | ||
|
||
public String getKey() { | ||
return key; | ||
@Override | ||
public String toString() { | ||
return "KeyVersionProperties{" + | ||
"version=" + version + | ||
", transformation='" + transformation + '\'' + | ||
", keyBase64='" + key + '\'' + | ||
'}'; | ||
} | ||
} | ||
} |
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
Oops, something went wrong.