Small fixes

This commit is contained in:
crschnick
2023-04-19 01:44:33 +00:00
parent aaf4ab9560
commit ccb8072625
24 changed files with 489 additions and 119 deletions
@@ -50,12 +50,13 @@ public abstract class QueryConverter<T> {
public static final QueryConverter<SecretValue> SECRET = new QueryConverter<SecretValue>() {
@Override
protected SecretValue fromString(String s) {
return new SecretValue(s);
//TODO
return null;
}
@Override
protected String toString(SecretValue value) {
return value.getEncryptedValue();
return value.getSecretValue();
}
};
@@ -0,0 +1,69 @@
package io.xpipe.core.util;
import lombok.SneakyThrows;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
@SuperBuilder
@Jacksonized
public class AesSecretValue extends EncryptedSecretValue {
private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding";
private static final int TAG_LENGTH_BIT = 128;
private static final int IV_LENGTH_BYTE = 12;
private static final int AES_KEY_BIT = 128;
private static final byte[] IV = getFixedNonce(IV_LENGTH_BYTE);
public AesSecretValue(char[] secret) {
super(secret);
}
private static byte[] getFixedNonce(int numBytes) {
byte[] nonce = new byte[numBytes];
new SecureRandom(new byte[] {1, -28, 123}).nextBytes(nonce);
return nonce;
}
protected SecretKey getAESKey(int keysize) throws NoSuchAlgorithmException, InvalidKeySpecException {
throw new UnsupportedOperationException();
}
@Override
@SneakyThrows
public byte[] encrypt(byte[] c) {
SecretKey secretKey = getAESKey(AES_KEY_BIT);
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH_BIT, IV));
var bytes = cipher.doFinal(c);
bytes = ByteBuffer.allocate(IV.length + bytes.length)
.order(ByteOrder.LITTLE_ENDIAN)
.put(IV)
.put(bytes)
.array();
return bytes;
}
@Override
@SneakyThrows
public byte[] decrypt(byte[] c) {
ByteBuffer bb = ByteBuffer.wrap(c).order(ByteOrder.LITTLE_ENDIAN);
byte[] iv = new byte[IV_LENGTH_BYTE];
bb.get(iv);
byte[] cipherText = new byte[bb.remaining()];
bb.get(cipherText);
SecretKey secretKey = getAESKey(AES_KEY_BIT);
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
return cipher.doFinal(cipherText);
}
}
@@ -67,9 +67,6 @@ public class CoreJacksonModule extends SimpleModule {
addSerializer(Path.class, new LocalPathSerializer());
addDeserializer(Path.class, new LocalPathDeserializer());
addSerializer(SecretValue.class, new SecretSerializer());
addDeserializer(SecretValue.class, new SecretDeserializer());
addSerializer(DataSourceReference.class, new DataSourceReferenceSerializer());
addDeserializer(DataSourceReference.class, new DataSourceReferenceDeserializer());
@@ -179,22 +176,6 @@ public class CoreJacksonModule extends SimpleModule {
}
}
public static class SecretSerializer extends JsonSerializer<SecretValue> {
@Override
public void serialize(SecretValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(value.getEncryptedValue());
}
}
public static class SecretDeserializer extends JsonDeserializer<SecretValue> {
@Override
public SecretValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return new SecretValue(p.getValueAsString());
}
}
@JsonSerialize(as = Throwable.class)
public abstract static class ThrowableTypeMixIn {
@@ -0,0 +1,52 @@
package io.xpipe.core.util;
import lombok.Getter;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@SuperBuilder
@Jacksonized
public class EncryptedSecretValue implements SecretValue {
@Getter
String encryptedValue;
public EncryptedSecretValue(char[] c) {
var utf8 = StandardCharsets.UTF_8.encode(CharBuffer.wrap(c));
var bytes = new byte[utf8.limit()];
utf8.get(bytes);
encryptedValue = SecretValue.base64e(encrypt(bytes));
}
@Override
public String toString() {
return "<encrypted secret>";
}
@Override
public char[] getSecret() {
try {
var bytes = Base64.getDecoder().decode(encryptedValue.replace("-", "/"));
bytes = decrypt(bytes);
var charBuffer = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes));
var chars = new char[charBuffer.limit()];
charBuffer.get(chars);
return chars;
} catch (Exception ex) {
return new char[0];
}
}
public byte[] encrypt(byte[] c) {
throw new UnsupportedOperationException();
}
public byte[] decrypt(byte[] c) {
throw new UnsupportedOperationException();
}
}
@@ -1,81 +1,28 @@
package io.xpipe.core.util;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.function.Consumer;
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@EqualsAndHashCode
public class SecretValue {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public interface SecretValue {
String value;
public static SecretValue encrypt(char[] c) {
if (c == null) {
return null;
}
var utf8 = StandardCharsets.UTF_8.encode(CharBuffer.wrap(c));
var bytes = new byte[utf8.limit()];
utf8.get(bytes);
Arrays.fill(c, (char) 0);
bytes = SecretProvider.get().encrypt(bytes);
var base64 = Base64.getEncoder().encodeToString(bytes);
return new SecretValue(base64.replace("/", "-"));
public static String base64e(byte[] b) {
var base64 = Base64.getEncoder().encodeToString(b);
return base64.replace("/", "-");
}
public static SecretValue encrypt(String s) {
if (s == null) {
return null;
}
return encrypt(s.toCharArray());
}
public void withSecretValue(Consumer<char[]> con) {
var chars = decryptChars();
public default void withSecretValue(Consumer<char[]> con) {
var chars = getSecret();
con.accept(chars);
Arrays.fill(chars, (char) 0);
}
@Override
public String toString() {
return "<secret>";
}
public abstract char[] getSecret();
public String getEncryptedValue() {
return value;
}
public char[] decryptChars() {
try {
var bytes = Base64.getDecoder().decode(value.replace("-", "/"));
bytes = SecretProvider.get().decrypt(bytes);
var charBuffer = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes));
var chars = new char[charBuffer.limit()];
charBuffer.get(chars);
return chars;
} catch (Exception ex) {
return new char[0];
}
}
public String decrypt() {
return new String(decryptChars());
}
public static SecretValue ofSecret(String s) {
return new SecretValue(s);
}
public String getSecretValue() {
return decrypt();
public default String getSecretValue() {
return new String(getSecret());
}
}