Skip to content

Commit 32119f9

Browse files
Adding the start of what is needed for salt encryption
1 parent 415cf4e commit 32119f9

File tree

5 files changed

+70
-16
lines changed

5 files changed

+70
-16
lines changed

src/main/java/com/uid2/shared/store/EncryptedScopedStoreReader.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,7 @@ protected String getDecryptedContent(String encryptedContent) throws Exception {
5050
JsonObject json = new JsonObject(encryptedContent);
5151
int keyId = json.getInteger("key_id");
5252
String encryptedPayload = json.getString("encrypted_payload");
53-
Map<Integer, CloudEncryptionKey> cloudEncryptionKeys = cloudEncryptionKeyProvider.getAll();
54-
CloudEncryptionKey decryptionKey = null;
55-
for (CloudEncryptionKey key : cloudEncryptionKeys.values()) {
56-
if (key.getId() == keyId) {
57-
decryptionKey = key;
58-
break;
59-
}
60-
}
53+
CloudEncryptionKey decryptionKey = cloudEncryptionKeyProvider.getKey(keyId);
6154

6255
if (decryptionKey == null) {
6356
throw new IllegalStateException("No matching S3 key found for decryption for key ID: " + keyId);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.uid2.shared.store;
2+
3+
import com.uid2.shared.cloud.DownloadCloudStorage;
4+
import com.uid2.shared.encryption.AesGcm;
5+
import com.uid2.shared.model.CloudEncryptionKey;
6+
import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider;
7+
8+
import io.vertx.core.json.JsonObject;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.Base64;
13+
14+
public class RotatingEncryptedSaltProvider extends RotatingSaltProvider{
15+
private final RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider;
16+
17+
public RotatingEncryptedSaltProvider(DownloadCloudStorage fileStreamProvider, String metadataPath, RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider) {
18+
super(fileStreamProvider, metadataPath);
19+
this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider;
20+
}
21+
22+
@Override
23+
protected String readInputStream(InputStream inputStream) throws IOException {
24+
String encryptedContent = super.readInputStream(inputStream);
25+
26+
JsonObject json = new JsonObject(encryptedContent);
27+
int keyId = json.getInteger("key_id");
28+
String encryptedPayload = json.getString("encrypted_payload");
29+
CloudEncryptionKey decryptionKey = cloudEncryptionKeyProvider.getKey(keyId);
30+
31+
if (decryptionKey == null) {
32+
throw new IllegalStateException("No matching S3 key found for decryption for key ID: " + keyId);
33+
}
34+
35+
byte[] secret = Base64.getDecoder().decode(decryptionKey.getSecret());
36+
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedPayload);
37+
byte[] decryptedBytes = AesGcm.decrypt(encryptedBytes, 0, secret);
38+
39+
return new String(decryptedBytes, StandardCharsets.UTF_8);
40+
}
41+
}

src/main/java/com/uid2/shared/store/RotatingSaltProvider.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.hashids.Hashids;
1414

1515
import java.io.BufferedReader;
16+
import java.io.IOException;
1617
import java.io.InputStream;
1718
import java.io.InputStreamReader;
1819
import java.nio.charset.StandardCharsets;
@@ -21,6 +22,7 @@
2122
import java.util.*;
2223
import java.util.concurrent.atomic.AtomicReference;
2324
import java.util.stream.Collectors;
25+
import java.util.stream.Stream;
2426

2527
/*
2628
1. metadata.json format
@@ -132,20 +134,29 @@ private SaltSnapshot loadSnapshot(JsonObject spec, String firstLevelSalt, SaltEn
132134
final String path = spec.getString("location");
133135
int idx = 0;
134136
final SaltEntry[] entries = new SaltEntry[spec.getInteger("size")];
135-
136-
try (InputStream inputStream = this.contentStreamProvider.download(path);
137-
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
138-
BufferedReader reader = new BufferedReader(inputStreamReader)) {
139-
for (String l; (l = reader.readLine()) != null; ++idx) {
140-
final SaltEntry entry = entryBuilder.toEntry(l);
141-
entries[idx] = entry;
142-
}
137+
Stream<String> stream = readInputStream(this.contentStreamProvider.download(path)).lines();
138+
for (String l : stream.toList()) {
139+
final SaltEntry entry = entryBuilder.toEntry(l);
140+
entries[idx] = entry;
141+
idx++;
143142
}
144143

145144
LOGGER.info("Loaded " + idx + " salts");
146145
return new SaltSnapshot(effective, expires, entries, firstLevelSalt);
147146
}
148147

148+
protected String readInputStream(InputStream inputStream) throws IOException {
149+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
150+
StringBuilder stringBuilder = new StringBuilder();
151+
String line;
152+
while ((line = reader.readLine()) != null) {
153+
stringBuilder.append(line);
154+
stringBuilder.append(System.lineSeparator());
155+
}
156+
return stringBuilder.toString();
157+
}
158+
}
159+
149160
public static class SaltSnapshot implements ISaltSnapshot {
150161
private final Instant effective;
151162
private final Instant expires;

src/main/java/com/uid2/shared/store/reader/RotatingCloudEncryptionKeyProvider.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public Map<Integer, CloudEncryptionKey> getAll() {
6161
return keys != null ? keys : new HashMap<>();
6262
}
6363

64+
public CloudEncryptionKey getKey(int id) {
65+
return reader.getSnapshot().get(id);
66+
}
67+
6468
public void updateSiteToKeysMapping() {
6569
Map<Integer, CloudEncryptionKey> allKeys = getAll();
6670
siteToKeysMap.clear();

src/test/java/com/uid2/shared/store/EncryptedScopedStoreReaderTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import static com.uid2.shared.TestUtilites.toInputStream;
2121
import static org.assertj.core.api.Assertions.assertThat;
2222
import static org.assertj.core.api.Assertions.assertThatThrownBy;
23+
import static org.mockito.ArgumentMatchers.any;
24+
import static org.mockito.ArgumentMatchers.anyInt;
2325
import static org.mockito.Mockito.mock;
2426
import static org.mockito.Mockito.when;
2527

@@ -52,6 +54,7 @@ void setUp() {
5254
Map<Integer, CloudEncryptionKey> mockKeyMap = new HashMap<>();
5355
mockKeyMap.put(encryptionKey.getId(), encryptionKey);
5456
when(keyProvider.getAll()).thenReturn(mockKeyMap);
57+
when(keyProvider.getKey(1)).thenReturn(mockKeyMap.get(1));
5558
}
5659

5760
@Test
@@ -127,6 +130,7 @@ void testDecryptionOfEncryptedContent() throws Exception {
127130
void testHandlingInvalidEncryptionKey() throws Exception {
128131
// Set key provider to return an empty map
129132
when(keyProvider.getAll()).thenReturn(new HashMap<>());
133+
when(keyProvider.getKey(anyInt())).thenReturn(null);
130134

131135
String secretKey = encryptionKey.getSecret();
132136
byte[] secretKeyBytes = Base64.getDecoder().decode(secretKey);
@@ -159,6 +163,7 @@ void testLoadWithMultipleEncryptionKeys() throws Exception {
159163
mockKeyMap.put(encryptionKey.getId(), encryptionKey);
160164
mockKeyMap.put(newKey.getId(), newKey);
161165
when(keyProvider.getAll()).thenReturn(mockKeyMap);
166+
when(keyProvider.getKey(2)).thenReturn(mockKeyMap.get(2));
162167

163168
byte[] encryptedPayload = AesGcm.encrypt("value1,value2".getBytes(StandardCharsets.UTF_8), newKeyBytes);
164169
String encryptedPayloadBase64 = Base64.getEncoder().encodeToString(encryptedPayload);

0 commit comments

Comments
 (0)