Skip to content

Commit 5e9ab49

Browse files
committed
added tests
1 parent 652169e commit 5e9ab49

File tree

5 files changed

+408
-46
lines changed

5 files changed

+408
-46
lines changed

crypto-tink/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,15 @@
3939
<artifactId>junit-jupiter</artifactId>
4040
<scope>test</scope>
4141
</dependency>
42+
<dependency>
43+
<groupId>org.mockito</groupId>
44+
<artifactId>mockito-core</artifactId>
45+
<scope>test</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.mockito</groupId>
49+
<artifactId>mockito-junit-jupiter</artifactId>
50+
<scope>test</scope>
51+
</dependency>
4252
</dependencies>
4353
</project>

crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKey.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@
4646
*/
4747
public class AesGcmWithAwsKmsSavedKey {
4848
private static final String AWS_MASTER_KEY_URI = "aws-kms://arn:aws:kms:us-east-1:776241929911:key/7aeb00c6-d416-4130-bed1-a8ee6064d7d9";
49-
private final AwsKmsClient awsKmsClient = new AwsKmsClient();
49+
private final AwsKmsClient awsKmsClient;
5050

5151
/**
52-
* Init AeadConfig in the Tink library.
52+
* Init AeadConfig in the Tink library with provided AwsKmsClient.
53+
*
54+
* @param awsKmsClient the AWS KMS client to use
5355
*/
54-
public AesGcmWithAwsKmsSavedKey() throws GeneralSecurityException {
56+
public AesGcmWithAwsKmsSavedKey(AwsKmsClient awsKmsClient) throws GeneralSecurityException {
57+
this.awsKmsClient = awsKmsClient;
5558
AeadConfig.register();
5659
}
5760

crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKey.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@
4646
*/
4747
public class EciesWithAwsKmsSavedKey {
4848
private static final String AWS_MASTER_KEY_URI = "aws-kms://arn:aws:kms:us-east-1:776241929911:key/7aeb00c6-d416-4130-bed1-a8ee6064d7d9";
49-
private final AwsKmsClient awsKmsClient = new AwsKmsClient();
49+
private final AwsKmsClient awsKmsClient;
5050

5151
/**
52-
* Init HybridConfig in the Tink library.
52+
* Init HybridConfig in the Tink library with provided AwsKmsClient.
53+
*
54+
* @param awsKmsClient the AWS KMS client to use
5355
*/
54-
public EciesWithAwsKmsSavedKey() throws GeneralSecurityException {
56+
public EciesWithAwsKmsSavedKey(AwsKmsClient awsKmsClient) throws GeneralSecurityException {
57+
this.awsKmsClient = awsKmsClient;
5558
HybridConfig.register();
5659
}
5760

crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKeyTest.java

Lines changed: 166 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,193 @@
1717
*/
1818
package de.dominikschadow.javasecurity.tink.aead;
1919

20+
import com.google.crypto.tink.Aead;
21+
import com.google.crypto.tink.KeyTemplates;
2022
import com.google.crypto.tink.KeysetHandle;
21-
import org.junit.jupiter.api.Assertions;
23+
import com.google.crypto.tink.aead.AeadConfig;
24+
import com.google.crypto.tink.integration.awskms.AwsKmsClient;
25+
import org.junit.jupiter.api.BeforeAll;
2226
import org.junit.jupiter.api.BeforeEach;
23-
import org.junit.jupiter.api.Disabled;
2427
import org.junit.jupiter.api.Test;
28+
import org.junit.jupiter.api.extension.ExtendWith;
29+
import org.junit.jupiter.api.io.TempDir;
30+
import org.mockito.Mock;
31+
import org.mockito.junit.jupiter.MockitoExtension;
2532

2633
import java.io.File;
2734
import java.nio.charset.StandardCharsets;
35+
import java.security.GeneralSecurityException;
2836

29-
import static org.junit.jupiter.api.Assertions.assertEquals;
30-
import static org.junit.jupiter.api.Assertions.assertNotEquals;
37+
import static org.junit.jupiter.api.Assertions.*;
38+
import static org.mockito.ArgumentMatchers.any;
39+
import static org.mockito.Mockito.*;
3140

32-
@Disabled("These test require AWS KMS configuration")
41+
@ExtendWith(MockitoExtension.class)
3342
class AesGcmWithAwsKmsSavedKeyTest {
3443
private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
3544
private static final byte[] ASSOCIATED_DATA = "Some additional data".getBytes(StandardCharsets.UTF_8);
36-
private static final String KEYSET_FILENAME = "src/test/resources/keysets/aead-aes-gcm-kms.json";
37-
private final File keysetFile = new File(KEYSET_FILENAME);
38-
private KeysetHandle secretKey;
45+
46+
@Mock
47+
private AwsKmsClient awsKmsClient;
48+
49+
@TempDir
50+
File tempDir;
3951

4052
private AesGcmWithAwsKmsSavedKey aes;
53+
private KeysetHandle testKeysetHandle;
54+
55+
@BeforeAll
56+
static void initTink() throws GeneralSecurityException {
57+
AeadConfig.register();
58+
}
4159

4260
@BeforeEach
43-
protected void setup() throws Exception {
44-
aes = new AesGcmWithAwsKmsSavedKey();
61+
void setup() throws Exception {
62+
aes = new AesGcmWithAwsKmsSavedKey(awsKmsClient);
63+
testKeysetHandle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));
64+
}
4565

46-
aes.generateAndStoreKey(keysetFile);
47-
secretKey = aes.loadKey(keysetFile);
66+
@Test
67+
void constructorInitializesSuccessfully() throws GeneralSecurityException {
68+
AesGcmWithAwsKmsSavedKey instance = new AesGcmWithAwsKmsSavedKey(awsKmsClient);
69+
assertNotNull(instance);
70+
}
71+
72+
@Test
73+
void constructorWithNullAwsKmsClientThrowsNoException() throws GeneralSecurityException {
74+
// The constructor accepts null - validation happens later when using the client
75+
AesGcmWithAwsKmsSavedKey instance = new AesGcmWithAwsKmsSavedKey(null);
76+
assertNotNull(instance);
77+
}
78+
79+
@Test
80+
void encryptReturnsEncryptedData() throws Exception {
81+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
82+
83+
assertNotNull(cipherText);
84+
assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8));
4885
}
4986

5087
@Test
51-
void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
52-
byte[] cipherText = aes.encrypt(secretKey, INITIAL_TEXT, ASSOCIATED_DATA);
53-
byte[] plainText = aes.decrypt(secretKey, cipherText, ASSOCIATED_DATA);
88+
void encryptWithEmptyAssociatedDataSucceeds() throws Exception {
89+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, new byte[0]);
90+
91+
assertNotNull(cipherText);
92+
assertTrue(cipherText.length > 0);
93+
}
5494

55-
Assertions.assertAll(
95+
@Test
96+
void decryptReturnsOriginalData() throws Exception {
97+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
98+
byte[] plainText = aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA);
99+
100+
assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8));
101+
}
102+
103+
@Test
104+
void decryptWithWrongAssociatedDataThrowsException() throws Exception {
105+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
106+
byte[] wrongAssociatedData = "Wrong associated data".getBytes(StandardCharsets.UTF_8);
107+
108+
assertThrows(GeneralSecurityException.class, () ->
109+
aes.decrypt(testKeysetHandle, cipherText, wrongAssociatedData)
110+
);
111+
}
112+
113+
@Test
114+
void decryptWithCorruptedCipherTextThrowsException() throws Exception {
115+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
116+
// Corrupt the ciphertext
117+
cipherText[0] = (byte) (cipherText[0] ^ 0xFF);
118+
119+
assertThrows(GeneralSecurityException.class, () ->
120+
aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA)
121+
);
122+
}
123+
124+
@Test
125+
void encryptionAndDecryptionRoundTripIsSuccessful() throws Exception {
126+
byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
127+
byte[] plainText = aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA);
128+
129+
assertAll(
56130
() -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
57131
() -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
58132
);
59133
}
60-
}
134+
135+
@Test
136+
void encryptProducesDifferentCipherTextForSameInput() throws Exception {
137+
byte[] cipherText1 = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
138+
byte[] cipherText2 = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
139+
140+
// AES-GCM uses random nonces, so encrypting the same plaintext twice should produce different ciphertexts
141+
assertNotEquals(new String(cipherText1, StandardCharsets.UTF_8), new String(cipherText2, StandardCharsets.UTF_8));
142+
}
143+
144+
@Test
145+
void generateAndStoreKeyDoesNotOverwriteExistingFile() throws Exception {
146+
File keysetFile = new File(tempDir, "existing-keyset.json");
147+
assertTrue(keysetFile.createNewFile());
148+
long originalLength = keysetFile.length();
149+
150+
aes.generateAndStoreKey(keysetFile);
151+
152+
// File should remain unchanged (empty) since it already existed
153+
assertEquals(originalLength, keysetFile.length());
154+
verify(awsKmsClient, never()).getAead(any());
155+
}
156+
157+
@Test
158+
void generateAndStoreKeyCallsAwsKmsClientForNewFile() throws Exception {
159+
File keysetFile = new File(tempDir, "new-keyset.json");
160+
Aead mockAead = mock(Aead.class);
161+
when(awsKmsClient.getAead(any())).thenReturn(mockAead);
162+
// Tink internally validates the encrypted keyset, so we need to throw an exception
163+
// to simulate what happens when AWS KMS is not available, but still verify the call
164+
when(mockAead.encrypt(any(), any())).thenThrow(new GeneralSecurityException("Mocked AWS KMS encryption"));
165+
166+
assertFalse(keysetFile.exists());
167+
168+
assertThrows(GeneralSecurityException.class, () -> aes.generateAndStoreKey(keysetFile));
169+
170+
// Verify that AWS KMS client was called
171+
verify(awsKmsClient).getAead(contains("aws-kms://"));
172+
verify(mockAead).encrypt(any(), any());
173+
}
174+
175+
@Test
176+
void loadKeyCallsAwsKmsClient() throws Exception {
177+
// First create a keyset file using the same mock setup
178+
File keysetFile = new File(tempDir, "load-test-keyset.json");
179+
Aead mockAead = mock(Aead.class);
180+
when(awsKmsClient.getAead(any())).thenReturn(mockAead);
181+
182+
// Mock encrypt to return the plaintext (simulating encryption that returns same bytes)
183+
when(mockAead.encrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
184+
// Mock decrypt to return the ciphertext (simulating decryption that returns same bytes)
185+
when(mockAead.decrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
186+
187+
aes.generateAndStoreKey(keysetFile);
188+
189+
KeysetHandle loadedKey = aes.loadKey(keysetFile);
190+
191+
assertNotNull(loadedKey);
192+
// Verify getAead was called twice - once for generate, once for load
193+
verify(awsKmsClient, times(2)).getAead(contains("aws-kms://"));
194+
}
195+
196+
@Test
197+
void encryptWithNullKeysetHandleThrowsException() {
198+
assertThrows(NullPointerException.class, () ->
199+
aes.encrypt(null, INITIAL_TEXT, ASSOCIATED_DATA)
200+
);
201+
}
202+
203+
@Test
204+
void decryptWithNullKeysetHandleThrowsException() {
205+
assertThrows(NullPointerException.class, () ->
206+
aes.decrypt(null, INITIAL_TEXT, ASSOCIATED_DATA)
207+
);
208+
}
209+
}

0 commit comments

Comments
 (0)