Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tink functions #4

Merged
merged 5 commits into from
Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

<groupId>no.ssb.dapla.dlp.pseudo.func</groupId>
<artifactId>dapla-dlp-pseudo-func</artifactId>
<version>1.0.3-SNAPSHOT</version>
<version>1.1.0-SNAPSHOT</version>
<name>dapla-dlp-pseudo-func</name>

<properties>
<java.version>8</java.version>
<java.version>11</java.version>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -25,6 +25,7 @@
<logback.version>1.2.10</logback.version>
<lombok.version>1.18.22</lombok.version>
<slf4j.version>1.7.36</slf4j.version>
<tink.version>1.7.0</tink.version>

<!-- Plugin/extension versions -->
<artifactregistry-maven-wagon.version>2.1.4</artifactregistry-maven-wagon.version>
Expand Down Expand Up @@ -52,6 +53,28 @@
<artifactId>format-preserving-encryption</artifactId>
<version>${format-preserving-encryption.version}</version>
</dependency>
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink</artifactId>
<version>${tink.version}</version>
</dependency>

<!--
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink-gcpkms</artifactId>
<version>${tinkVersion}</version>
</dependency>
-->
<!-- to fix CVE-2021-22573 in tink-gcpkms -->
<!--
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client</artifactId>
<version>1.34.1</version>
</dependency>
-->

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/no/ssb/dapla/dlp/pseudo/func/daead/DaeadFunc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package no.ssb.dapla.dlp.pseudo.func.daead;

import com.google.crypto.tink.DeterministicAead;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import no.ssb.dapla.dlp.pseudo.func.*;
import no.ssb.dapla.dlp.pseudo.func.util.FromString;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;

@Slf4j
public class DaeadFunc extends AbstractPseudoFunc {

// FIXME: Replace this with something real
private static final byte[] DAEAD_STAMP_BYTES = "".getBytes(StandardCharsets.UTF_8);
private final DaeadFuncConfigService configService = new DaeadFuncConfigService();
private final DaeadFuncConfig config;

public DaeadFunc(@NonNull PseudoFuncConfig genericConfig) {
super(genericConfig.getFuncDecl());
this.config = configService.resolve(genericConfig);
}

private DeterministicAead daead() {
return config.getDaead();
}

@Override
public PseudoFuncOutput apply(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();
input.getValues().forEach(in -> {
String plain = String.valueOf(in);
try {
byte[] ciphertext = daead().encryptDeterministically(plain.getBytes(StandardCharsets.UTF_8), DAEAD_STAMP_BYTES);
output.add(Base64.getEncoder().encodeToString(ciphertext));
}
catch (GeneralSecurityException e) {
throw new DaeadPseudoFuncException("DAEAD apply error. func=" + getFuncDecl() + ", contentType=" + input.getParamMetadata(), e);
}
});

return output;
}

@Override
public PseudoFuncOutput restore(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();
input.getValues().forEach(in -> {
byte[] ciphertext = Base64.getDecoder().decode(String.valueOf(in));
try {
byte[] plaintext = daead().decryptDeterministically(ciphertext, DAEAD_STAMP_BYTES);
output.add(FromString.convert(new String(plaintext), in.getClass()));
}
catch (GeneralSecurityException e) {
throw new DaeadPseudoFuncException("DAEAD restore error. func=" + getFuncDecl() + ", contentType=" + input.getParamMetadata(), e);
}
});

return output;
}

public static class DaeadPseudoFuncException extends PseudoFuncException {
public DaeadPseudoFuncException(String message, Throwable cause) {
super(message, cause);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package no.ssb.dapla.dlp.pseudo.func.daead;

import com.google.crypto.tink.DeterministicAead;
import lombok.Builder;
import lombok.Value;
import lombok.experimental.UtilityClass;

@Value
@Builder
public class DaeadFuncConfig {
private final String dataEncryptionKeyId;
private final String base64EncodedWrappedDataEncryptionKey;
private final DeterministicAead daead;

@UtilityClass
public static class Param {
public static final String DEK_ID = "dataEncryptionKeyId";
public static final String WDEK = "wrappedDataEncryptionKey";
public static final String DAEAD = "deterministicAead";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package no.ssb.dapla.dlp.pseudo.func.daead;

import com.google.crypto.tink.DeterministicAead;
import lombok.extern.slf4j.Slf4j;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncConfig;

import static no.ssb.dapla.dlp.pseudo.func.daead.DaeadFuncConfig.Param.DAEAD;

@Slf4j
public class DaeadFuncConfigService {

public DaeadFuncConfig resolve(PseudoFuncConfig cfg) {

return DaeadFuncConfig.builder()
.daead(cfg.getRequired(DAEAD, DeterministicAead.class))
.build();
}

}
54 changes: 54 additions & 0 deletions src/main/java/no/ssb/dapla/dlp/pseudo/func/map/MapFunc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package no.ssb.dapla.dlp.pseudo.func.map;

import lombok.extern.slf4j.Slf4j;
import no.ssb.dapla.dlp.pseudo.func.AbstractPseudoFunc;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncConfig;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncInput;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncOutput;

import java.util.ServiceLoader;

@Slf4j
public class MapFunc extends AbstractPseudoFunc {
private final MapFuncConfig config;
private final MapFuncConfigService mapFuncConfigService = new MapFuncConfigService();
private final Mapper mapper;

public MapFunc(PseudoFuncConfig genericConfig) {
super(genericConfig.getFuncDecl());
this.config = mapFuncConfigService.resolve(genericConfig);
// TODO: Filter Service Implementation by some annotation (to choose the implementation that is used)
this.mapper = ServiceLoader.load(Mapper.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName() + " requires a " + Mapper.class.getName() + " implementation to be present on the classpath"));
}

@Override
public PseudoFuncOutput apply(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();

for (Object inputValue : input.getValues()) {
String plain = String.valueOf(inputValue);
final Object pseudonymized = mapper.map(plain);
//output.add(FromString.convert(pseudonymized, inputValue.getClass()));
output.add(pseudonymized);
}

return output;
}

@Override
public PseudoFuncOutput restore(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();

for (Object inputValue : input.getValues()) {
String mapped = String.valueOf(inputValue);
final Object clear = mapper.restore(mapped);
//output.add(FromString.convert(clear, inputValue.getClass()));
output.add(clear);
}

return output;
}

}
16 changes: 16 additions & 0 deletions src/main/java/no/ssb/dapla/dlp/pseudo/func/map/MapFuncConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package no.ssb.dapla.dlp.pseudo.func.map;

import lombok.Builder;
import lombok.Value;
import lombok.experimental.UtilityClass;

@Value
@Builder
public class MapFuncConfig {
private final String context;

@UtilityClass
public static class Param {
public static final String CONTEXT = "context";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package no.ssb.dapla.dlp.pseudo.func.map;

import no.ssb.dapla.dlp.pseudo.func.PseudoFuncConfig;

public class MapFuncConfigService {

public MapFuncConfig resolve(PseudoFuncConfig genericConfig) {

String context = genericConfig.getRequired(MapFuncConfig.Param.CONTEXT, String.class);

return MapFuncConfig.builder()
.context(context)
.build();
}

}
9 changes: 9 additions & 0 deletions src/main/java/no/ssb/dapla/dlp/pseudo/func/map/Mapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package no.ssb.dapla.dlp.pseudo.func.map;

public interface Mapper {

Object map(Object data);

Object restore(Object mapped);

}
44 changes: 44 additions & 0 deletions src/main/java/no/ssb/dapla/dlp/pseudo/func/redact/RedactFunc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package no.ssb.dapla.dlp.pseudo.func.redact;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import no.ssb.dapla.dlp.pseudo.func.AbstractPseudoFunc;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncConfig;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncInput;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncOutput;

@Slf4j
public class RedactFunc extends AbstractPseudoFunc {
private final RedactFuncConfigService configService = new RedactFuncConfigService();
private final RedactFuncConfig config;

public RedactFunc(@NonNull PseudoFuncConfig genericConfig) {
super(genericConfig.getFuncDecl());
this.config = configService.resolve(genericConfig);
}

@Override
public PseudoFuncOutput apply(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();
input.getValues().forEach(in -> {
String plain = String.valueOf(in);
if (config.getRegex() != null) {
output.add(plain.replaceAll(config.getRegex(), config.getPlaceholder()));
}
else {
output.add(config.getPlaceholder());
}
});

return output;
}

@Override
public PseudoFuncOutput restore(PseudoFuncInput input) {
PseudoFuncOutput output = new PseudoFuncOutput();
input.getValues().forEach(in -> output.add(in));

return output;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package no.ssb.dapla.dlp.pseudo.func.redact;

import lombok.Builder;
import lombok.Value;
import lombok.experimental.UtilityClass;

@Value
@Builder
public class RedactFuncConfig {
private final String placeholder;
private final String regex;

@UtilityClass
public static class Param {
public static final String PLACEHOLDER = "placeholder";
public static final String REGEX = "regex";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package no.ssb.dapla.dlp.pseudo.func.redact;

import lombok.extern.slf4j.Slf4j;
import no.ssb.dapla.dlp.pseudo.func.PseudoFuncConfig;

import static no.ssb.dapla.dlp.pseudo.func.redact.RedactFuncConfig.Param.PLACEHOLDER;
import static no.ssb.dapla.dlp.pseudo.func.redact.RedactFuncConfig.Param.REGEX;

@Slf4j
public class RedactFuncConfigService {

public RedactFuncConfig resolve(PseudoFuncConfig cfg) {
return RedactFuncConfig.builder()
.placeholder(cfg.get(PLACEHOLDER, String.class).orElse("***"))
.regex(cfg.get(REGEX, String.class).orElse(null))
.build();
}

}
Loading