Java crypto sample project using Google Tink to encrypt/ decrypt and sign/ verify data. Each class
- provides its own main method to get started.
+ Java crypto sample project using Google Tink to encrypt/ decrypt and sign/ verify data. Each class has
+ its own tests to demonstrate various aspects.
@@ -26,28 +26,28 @@
tink-awskms
- org.apache.logging.log4j
- log4j-api
+ org.apache.httpcomponents
+ httpclient
- org.apache.logging.log4j
- log4j-core
+ javax.xml.bind
+ jaxb-api
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
- org.apache.logging.log4j
- log4j-slf4j-impl
+ org.mockito
+ mockito-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
-
-
-
-
- com.google.cloud.tools
- jib-maven-plugin
-
- true
-
-
-
-
\ No newline at end of file
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/TinkUtils.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/TinkUtils.java
deleted file mode 100644
index 196d939b..00000000
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/TinkUtils.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
- *
- * This file is part of the Java Security project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package de.dominikschadow.javasecurity.tink;
-
-import com.google.common.io.BaseEncoding;
-import com.google.crypto.tink.CleartextKeysetHandle;
-import com.google.crypto.tink.JsonKeysetWriter;
-import com.google.crypto.tink.KeysetHandle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-/**
- * Google Tink utils for this demo project.
- *
- * @author Dominik Schadow
- */
-public class TinkUtils {
- private static final Logger log = LoggerFactory.getLogger(TinkUtils.class);
- public static final String AWS_MASTER_KEY_URI = "aws-kms://arn:aws:kms:eu-central-1:776241929911:key/cce9ce6d-526c-44ca-9189-45c54b90f070";
-
- public static void printKeyset(String type, KeysetHandle keysetHandle) {
- try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(outputStream));
-
- log.info("{}: {}", type, new String(outputStream.toByteArray()));
- } catch (IOException ex) {
- log.error("Failed to write keyset", ex);
- }
- }
-
- public static void printSymmetricEncryptionData(KeysetHandle keysetHandle, String initialText, byte[] cipherText, byte[] plainText) {
- log.info("initial text: {}", initialText);
- log.info("cipher text: {}", BaseEncoding.base16().encode(cipherText));
- log.info("plain text: {}", new String(plainText, StandardCharsets.UTF_8));
-
- printKeyset("keyset data", keysetHandle);
- }
-
- public static void printHybridEncryptionData(KeysetHandle privateKeysetHandle, KeysetHandle publicKeysetHandle, String initialText, byte[] cipherText, byte[] plainText) {
- log.info("initial text: {}", initialText);
- log.info("cipher text: {}", BaseEncoding.base16().encode(cipherText));
- log.info("plain text: {}", new String(plainText, StandardCharsets.UTF_8));
-
- printKeyset("private key set data", privateKeysetHandle);
- printKeyset("public key set data", publicKeysetHandle);
- }
-
- public static void printMacData(KeysetHandle keysetHandle, String initialText, byte[] tag, boolean valid) {
- log.info("initial text: {}", initialText);
- log.info("MAC: {}", BaseEncoding.base16().encode(tag));
- log.info("MAC is valid: {}", valid);
-
- printKeyset("keyset data", keysetHandle);
- }
-
- public static void printSignatureData(KeysetHandle privateKeysetHandle, KeysetHandle publicKeysetHandle, String initialText, byte[] signature, boolean valid) {
- log.info("initial text: {}", initialText);
- log.info("signature: {}", BaseEncoding.base16().encode(signature));
- log.info("signature is valid: {}", valid);
-
- printKeyset("private key set data", privateKeysetHandle);
- printKeyset("public key set data", publicKeysetHandle);
- }
-}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKey.java
index ba6853d2..985bf318 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,12 +18,9 @@
package de.dominikschadow.javasecurity.tink.aead;
import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.aead.AeadConfig;
-import com.google.crypto.tink.aead.AeadKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.security.GeneralSecurityException;
@@ -34,49 +31,26 @@
* @author Dominik Schadow
*/
public class AesEaxWithGeneratedKey {
- private static final Logger log = LoggerFactory.getLogger(AesEaxWithGeneratedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String ASSOCIATED_DATA = "Some additional data";
-
/**
* Init AeadConfig in the Tink library.
*/
- private AesEaxWithGeneratedKey() {
- try {
- AeadConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- AesEaxWithGeneratedKey demo = new AesEaxWithGeneratedKey();
-
- try {
- KeysetHandle keysetHandle = demo.generateKey();
-
- byte[] cipherText = demo.encrypt(keysetHandle);
- byte[] plainText = demo.decrypt(keysetHandle, cipherText);
-
- TinkUtils.printSymmetricEncryptionData(keysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- }
+ public AesEaxWithGeneratedKey() throws GeneralSecurityException {
+ AeadConfig.register();
}
- private KeysetHandle generateKey() throws GeneralSecurityException {
- return KeysetHandle.generateNew(AeadKeyTemplates.AES256_EAX);
+ public KeysetHandle generateKey() throws GeneralSecurityException {
+ return KeysetHandle.generateNew(KeyTemplates.get("AES256_EAX"));
}
- private byte[] encrypt(KeysetHandle keysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle keysetHandle, byte[] initialText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.encrypt(INITIAL_TEXT.getBytes(), ASSOCIATED_DATA.getBytes());
+ return aead.encrypt(initialText, associatedData);
}
- private byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.decrypt(cipherText, ASSOCIATED_DATA.getBytes());
+ return aead.decrypt(cipherText, associatedData);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKey.java
index 053eaa01..dc09e96d 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,29 +17,27 @@
*/
package de.dominikschadow.javasecurity.tink.aead;
-import com.google.crypto.tink.Aead;
-import com.google.crypto.tink.JsonKeysetReader;
-import com.google.crypto.tink.JsonKeysetWriter;
-import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.*;
import com.google.crypto.tink.aead.AeadConfig;
-import com.google.crypto.tink.aead.AeadKeyTemplates;
import com.google.crypto.tink.integration.awskms.AwsKmsClient;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
-import static de.dominikschadow.javasecurity.tink.TinkUtils.AWS_MASTER_KEY_URI;
-
/**
+ *
* Shows crypto usage with Google Tink for the Authenticated Encryption with Associated Data (AEAD) primitive. The used
- * key is stored and loaded from AWS KMS. Requires a master key available in AWS KMS and correctly configured
- * credentials to access AWS KMS: AWS_ACCESS_KEY_ID and AWS_SECRET_KEY must be set as environment variables.
+ * key is stored and loaded from AWS KMS. Selected algorithm is AES-GCM with 128 bit. Requires a master key available in
+ * AWS KMS and correctly configured credentials to access AWS KMS: AWS_ACCESS_KEY_ID and AWS_SECRET_KEY must be set as
+ * environment variables.
+ *
*
- * Selected algorithm is AES-GCM with 128 bit.
+ * Using your own AWS Master Key requires to delete the stored keyset in src/test/resources/keysets/aead-aes-gcm-kms.json
+ * because this key was created with the used sample AWS KMS master key and will not work with any other master key.
+ *
*
* @author Dominik Schadow
* @see Creating Keys
@@ -47,39 +45,17 @@
* the Default Credential Provider Chain
*/
public class AesGcmWithAwsKmsSavedKey {
- private static final Logger log = LoggerFactory.getLogger(AesGcmWithAwsKmsSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String ASSOCIATED_DATA = "Some additional data";
- private static final String KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/aead-aes-gcm-kms.json";
+ private static final String AWS_MASTER_KEY_URI = "aws-kms://arn:aws:kms:us-east-1:776241929911:key/7aeb00c6-d416-4130-bed1-a8ee6064d7d9";
+ private final AwsKmsClient awsKmsClient;
/**
- * Init AeadConfig in the Tink library.
+ * Init AeadConfig in the Tink library with provided AwsKmsClient.
+ *
+ * @param awsKmsClient the AWS KMS client to use
*/
- private AesGcmWithAwsKmsSavedKey() {
- try {
- AeadConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- AesGcmWithAwsKmsSavedKey demo = new AesGcmWithAwsKmsSavedKey();
-
- try {
- demo.generateAndStoreKey();
-
- KeysetHandle keysetHandle = demo.loadKey();
-
- byte[] cipherText = demo.encrypt(keysetHandle);
- byte[] plainText = demo.decrypt(keysetHandle, cipherText);
-
- TinkUtils.printSymmetricEncryptionData(keysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
+ public AesGcmWithAwsKmsSavedKey(AwsKmsClient awsKmsClient) throws GeneralSecurityException {
+ this.awsKmsClient = awsKmsClient;
+ AeadConfig.register();
}
/**
@@ -88,29 +64,26 @@ public static void main(String[] args) {
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStoreKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
- keysetHandle.write(JsonKeysetWriter.withFile(keysetFile), new AwsKmsClient().withDefaultCredentials().getAead(AWS_MASTER_KEY_URI));
+ public void generateAndStoreKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));
+ keysetHandle.write(JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))), awsKmsClient.getAead(AWS_MASTER_KEY_URI));
}
}
- private KeysetHandle loadKey() throws IOException, GeneralSecurityException {
- return KeysetHandle.read(JsonKeysetReader.withFile(new File(KEYSET_FILENAME)),
- new AwsKmsClient().withDefaultCredentials().getAead(AWS_MASTER_KEY_URI));
+ public KeysetHandle loadKey(File keyset) throws IOException, GeneralSecurityException {
+ return KeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)), awsKmsClient.getAead(AWS_MASTER_KEY_URI));
}
- private byte[] encrypt(KeysetHandle keysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle keysetHandle, byte[] initialText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.encrypt(INITIAL_TEXT.getBytes(), ASSOCIATED_DATA.getBytes());
+ return aead.encrypt(initialText, associatedData);
}
- private byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.decrypt(cipherText, ASSOCIATED_DATA.getBytes());
+ return aead.decrypt(cipherText, associatedData);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKey.java
index 63afe490..c643220e 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,12 +19,10 @@
import com.google.crypto.tink.*;
import com.google.crypto.tink.aead.AeadConfig;
-import com.google.crypto.tink.aead.AeadKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -35,39 +33,11 @@
* @author Dominik Schadow
*/
public class AesGcmWithSavedKey {
- private static final Logger log = LoggerFactory.getLogger(AesGcmWithSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String ASSOCIATED_DATA = "Some additional data";
- private static final String KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/aead-aes-gcm.json";
-
/**
* Init AeadConfig in the Tink library.
*/
- private AesGcmWithSavedKey() {
- try {
- AeadConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- AesGcmWithSavedKey demo = new AesGcmWithSavedKey();
-
- try {
- demo.generateAndStoreKey();
-
- KeysetHandle keysetHandle = demo.loadKey();
-
- byte[] cipherText = demo.encrypt(keysetHandle);
- byte[] plainText = demo.decrypt(keysetHandle, cipherText);
-
- TinkUtils.printSymmetricEncryptionData(keysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
+ public AesGcmWithSavedKey() throws GeneralSecurityException {
+ AeadConfig.register();
}
/**
@@ -76,28 +46,26 @@ public static void main(String[] args) {
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStoreKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ public void generateAndStoreKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream(keyset)));
}
}
- private KeysetHandle loadKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(KEYSET_FILENAME)));
+ public KeysetHandle loadKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
- private byte[] encrypt(KeysetHandle keysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle keysetHandle, byte[] initialText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.encrypt(INITIAL_TEXT.getBytes(), ASSOCIATED_DATA.getBytes());
+ return aead.encrypt(initialText, associatedData);
}
- private byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText, byte[] associatedData) throws GeneralSecurityException {
Aead aead = keysetHandle.getPrimitive(Aead.class);
- return aead.decrypt(cipherText, ASSOCIATED_DATA.getBytes());
+ return aead.decrypt(cipherText, associatedData);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKey.java
index dd81d837..a0e15f54 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,24 +19,25 @@
import com.google.crypto.tink.*;
import com.google.crypto.tink.hybrid.HybridConfig;
-import com.google.crypto.tink.hybrid.HybridKeyTemplates;
import com.google.crypto.tink.integration.awskms.AwsKmsClient;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
-import static de.dominikschadow.javasecurity.tink.TinkUtils.AWS_MASTER_KEY_URI;
-
/**
- * Shows crypto usage with Google Tink for the HybridEncrypt primitive. The used key is stored and loaded from AWS KMS.
- * Requires a master key available in AWS KMS and correctly configured credentials to access AWS KMS: AWS_ACCESS_KEY_ID
- * and AWS_SECRET_KEY must be set as environment variables.
*
- * Selected algorithm is ECIES with AEAD and HKDF.
+ * Shows crypto usage with Google Tink for the HybridEncrypt (AEAD) primitive. The used key is stored and loaded from #
+ * AWS KMS. Selected algorithm is AES-GCM with 128 bit. Requires a master key available in AWS KMS and correctly
+ * configured credentials to access AWS KMS: AWS_ACCESS_KEY_ID and AWS_SECRET_KEY must be set as environment variables.
+ *
+ *
+ * Using your own AWS Master Key requires to delete the stored keyset in src/test/resources/keysets/hybrid-ecies-kms-private.json
+ * and src/test/resources/keysets/hybrid-ecies-kms-public.json because these keys were created with the used sample AWS
+ * KMS master key and will not work with any other master key.
+ *
*
* @author Dominik Schadow
* @see Creating Keys
@@ -44,42 +45,17 @@
* the Default Credential Provider Chain
*/
public class EciesWithAwsKmsSavedKey {
- private static final Logger log = LoggerFactory.getLogger(EciesWithAwsKmsSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String CONTEXT_INFO = "Some additional data";
- private static final String PRIVATE_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-private.json";
- private static final String PUBLIC_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-public.json";
+ private static final String AWS_MASTER_KEY_URI = "aws-kms://arn:aws:kms:us-east-1:776241929911:key/7aeb00c6-d416-4130-bed1-a8ee6064d7d9";
+ private final AwsKmsClient awsKmsClient;
/**
- * Init AeadConfig in the Tink library.
+ * Init HybridConfig in the Tink library with provided AwsKmsClient.
+ *
+ * @param awsKmsClient the AWS KMS client to use
*/
- private EciesWithAwsKmsSavedKey() {
- try {
- HybridConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- EciesWithAwsKmsSavedKey demo = new EciesWithAwsKmsSavedKey();
-
- try {
- demo.generateAndStorePrivateKey();
- KeysetHandle privateKeysetHandle = demo.loadPrivateKey();
-
- demo.generateAndStorePublicKey(privateKeysetHandle);
- KeysetHandle publicKeysetHandle = demo.loadPublicKey();
-
- byte[] cipherText = demo.encrypt(publicKeysetHandle);
- byte[] plainText = demo.decrypt(privateKeysetHandle, cipherText);
-
- TinkUtils.printHybridEncryptionData(privateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
+ public EciesWithAwsKmsSavedKey(AwsKmsClient awsKmsClient) throws GeneralSecurityException {
+ this.awsKmsClient = awsKmsClient;
+ HybridConfig.register();
}
/**
@@ -88,18 +64,15 @@ public static void main(String[] args) {
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePrivateKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(PRIVATE_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM);
- keysetHandle.write(JsonKeysetWriter.withFile(keysetFile), new AwsKmsClient().withDefaultCredentials().getAead(AWS_MASTER_KEY_URI));
+ public void generateAndStorePrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"));
+ keysetHandle.write(JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))), awsKmsClient.getAead(AWS_MASTER_KEY_URI));
}
}
- private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityException {
- return KeysetHandle.read(JsonKeysetReader.withFile(new File(PRIVATE_KEYSET_FILENAME)),
- new AwsKmsClient().withDefaultCredentials().getAead(AWS_MASTER_KEY_URI));
+ public KeysetHandle loadPrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ return KeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)), awsKmsClient.getAead(AWS_MASTER_KEY_URI));
}
/**
@@ -108,28 +81,26 @@ private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityExcepti
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePublicKey(KeysetHandle privateKeysetHandle) throws IOException, GeneralSecurityException {
- File keysetFile = new File(PUBLIC_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
+ public void generateAndStorePublicKey(KeysetHandle privateKeysetHandle, File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
KeysetHandle keysetHandle = privateKeysetHandle.getPublicKeysetHandle();
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
}
}
- private KeysetHandle loadPublicKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(PUBLIC_KEYSET_FILENAME)));
+ public KeysetHandle loadPublicKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
- private byte[] encrypt(KeysetHandle publicKeysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle publicKeysetHandle, byte[] initialText, byte[] contextInfo) throws GeneralSecurityException {
HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class);
- return hybridEncrypt.encrypt(INITIAL_TEXT.getBytes(), CONTEXT_INFO.getBytes());
+ return hybridEncrypt.encrypt(initialText, contextInfo);
}
- private byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText, byte[] contextInfo) throws GeneralSecurityException {
HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class);
- return hybridDecrypt.decrypt(cipherText, CONTEXT_INFO.getBytes());
+ return hybridDecrypt.decrypt(cipherText, contextInfo);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKey.java
index 88aafe30..ea82e769 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,12 +19,9 @@
import com.google.crypto.tink.HybridDecrypt;
import com.google.crypto.tink.HybridEncrypt;
+import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.hybrid.HybridConfig;
-import com.google.crypto.tink.hybrid.HybridKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.security.GeneralSecurityException;
@@ -35,54 +32,30 @@
* @author Dominik Schadow
*/
public class EciesWithGeneratedKey {
- private static final Logger log = LoggerFactory.getLogger(EciesWithGeneratedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String CONTEXT_INFO = "Some additional data";
-
/**
* Init HybridConfig in the Tink library.
*/
- private EciesWithGeneratedKey() {
- try {
- HybridConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- EciesWithGeneratedKey demo = new EciesWithGeneratedKey();
-
- try {
- KeysetHandle privateKeysetHandle = demo.generatePrivateKey();
- KeysetHandle publicKeysetHandle = demo.generatePublicKey(privateKeysetHandle);
-
- byte[] cipherText = demo.encrypt(publicKeysetHandle);
- byte[] plainText = demo.decrypt(privateKeysetHandle, cipherText);
-
- TinkUtils.printHybridEncryptionData(privateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- }
+ public EciesWithGeneratedKey() throws GeneralSecurityException {
+ HybridConfig.register();
}
- private KeysetHandle generatePrivateKey() throws GeneralSecurityException {
- return KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256);
+ public KeysetHandle generatePrivateKey() throws GeneralSecurityException {
+ return KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"));
}
- private KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
+ public KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
return privateKeysetHandle.getPublicKeysetHandle();
}
- private byte[] encrypt(KeysetHandle publicKeysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle publicKeysetHandle, byte[] initialText, byte[] contextInfo) throws GeneralSecurityException {
HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class);
- return hybridEncrypt.encrypt(INITIAL_TEXT.getBytes(), CONTEXT_INFO.getBytes());
+ return hybridEncrypt.encrypt(initialText, contextInfo);
}
- private byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText, byte[] contextInfo) throws GeneralSecurityException {
HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class);
- return hybridDecrypt.decrypt(cipherText, CONTEXT_INFO.getBytes());
+ return hybridDecrypt.decrypt(cipherText, contextInfo);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotation.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotation.java
index 4b74609e..31397a56 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotation.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,15 +17,8 @@
*/
package de.dominikschadow.javasecurity.tink.hybrid;
-import com.google.crypto.tink.HybridDecrypt;
-import com.google.crypto.tink.HybridEncrypt;
-import com.google.crypto.tink.KeysetHandle;
-import com.google.crypto.tink.KeysetManager;
+import com.google.crypto.tink.*;
import com.google.crypto.tink.hybrid.HybridConfig;
-import com.google.crypto.tink.hybrid.HybridKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.security.GeneralSecurityException;
@@ -36,73 +29,42 @@
* @author Dominik Schadow
*/
public class EciesWithGeneratedKeyAndKeyRotation {
- private static final Logger log = LoggerFactory.getLogger(EciesWithGeneratedKeyAndKeyRotation.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String CONTEXT_INFO = "Some additional data";
-
/**
* Init HybridConfig in the Tink library.
*/
- private EciesWithGeneratedKeyAndKeyRotation() {
- try {
- HybridConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- EciesWithGeneratedKeyAndKeyRotation demo = new EciesWithGeneratedKeyAndKeyRotation();
-
- try {
- KeysetHandle privateKeysetHandle = demo.generatePrivateKey();
- TinkUtils.printKeyset("original keyset data", privateKeysetHandle);
- KeysetHandle rotatedPrivateKeysetHandle = demo.rotateKey(privateKeysetHandle);
- TinkUtils.printKeyset("rotated keyset data", rotatedPrivateKeysetHandle);
- rotatedPrivateKeysetHandle = demo.disableOriginalKey(rotatedPrivateKeysetHandle);
- TinkUtils.printKeyset("disabled rotated keyset data", rotatedPrivateKeysetHandle);
- KeysetHandle publicKeysetHandle = demo.generatePublicKey(rotatedPrivateKeysetHandle);
-
- byte[] cipherText = demo.encrypt(publicKeysetHandle);
- byte[] plainText = demo.decrypt(rotatedPrivateKeysetHandle, cipherText);
-
- TinkUtils.printHybridEncryptionData(rotatedPrivateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- }
+ public EciesWithGeneratedKeyAndKeyRotation() throws GeneralSecurityException {
+ HybridConfig.register();
}
/**
- * Generate a new key with different ECIES properties and add it to the keyset.
+ * Generate a new key with different ECIES properties and add it to the keyset. Sets the new key as primary key and
+ * disables the original primary key.
*/
- private KeysetHandle rotateKey(KeysetHandle keysetHandle) throws GeneralSecurityException {
- return KeysetManager.withKeysetHandle(keysetHandle).rotate(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256).getKeysetHandle();
- }
+ public KeysetHandle rotateKey(KeysetHandle keysetHandle) throws GeneralSecurityException {
+ KeysetHandle handle = KeysetManager.withKeysetHandle(keysetHandle).add(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256")).getKeysetHandle();
- /**
- * Optional step to disable the original key.
- */
- private KeysetHandle disableOriginalKey(KeysetHandle keysetHandle) throws GeneralSecurityException {
- return KeysetManager.withKeysetHandle(keysetHandle).disable(keysetHandle.getKeysetInfo().getKeyInfo(0).getKeyId()).getKeysetHandle();
+ handle = KeysetManager.withKeysetHandle(handle).setPrimary(handle.getKeysetInfo().getKeyInfo(1).getKeyId()).getKeysetHandle();
+
+ return KeysetManager.withKeysetHandle(handle).disable(handle.getKeysetInfo().getKeyInfo(0).getKeyId()).getKeysetHandle();
}
- private KeysetHandle generatePrivateKey() throws GeneralSecurityException {
- return KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM);
+ public KeysetHandle generatePrivateKey() throws GeneralSecurityException {
+ return KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"));
}
- private KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
+ public KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
return privateKeysetHandle.getPublicKeysetHandle();
}
- private byte[] encrypt(KeysetHandle publicKeysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle publicKeysetHandle, byte[] initialText, byte[] contextInfo) throws GeneralSecurityException {
HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class);
- return hybridEncrypt.encrypt(INITIAL_TEXT.getBytes(), CONTEXT_INFO.getBytes());
+ return hybridEncrypt.encrypt(initialText, contextInfo);
}
- private byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText, byte[] contextInfo) throws GeneralSecurityException {
HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class);
- return hybridDecrypt.decrypt(cipherText, CONTEXT_INFO.getBytes());
+ return hybridDecrypt.decrypt(cipherText, contextInfo);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKey.java
index 8e2a28b7..816d4a70 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,12 +19,10 @@
import com.google.crypto.tink.*;
import com.google.crypto.tink.hybrid.HybridConfig;
-import com.google.crypto.tink.hybrid.HybridKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -35,42 +33,11 @@
* @author Dominik Schadow
*/
public class EciesWithSavedKey {
- private static final Logger log = LoggerFactory.getLogger(EciesWithSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String CONTEXT_INFO = "Some additional data";
- private static final String PRIVATE_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/hybrid-ecies-private.json";
- private static final String PUBLIC_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/hybrid-ecies-public.json";
-
/**
* Init HybridConfig in the Tink library.
*/
- private EciesWithSavedKey() {
- try {
- HybridConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- EciesWithSavedKey demo = new EciesWithSavedKey();
-
- try {
- demo.generateAndStorePrivateKey();
- KeysetHandle privateKeysetHandle = demo.loadPrivateKey();
-
- demo.generateAndStorePublicKey(privateKeysetHandle);
- KeysetHandle publicKeysetHandle = demo.loadPublicKey();
-
- byte[] cipherText = demo.encrypt(publicKeysetHandle);
- byte[] plainText = demo.decrypt(privateKeysetHandle, cipherText);
-
- TinkUtils.printHybridEncryptionData(privateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, cipherText, plainText);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
+ public EciesWithSavedKey() throws GeneralSecurityException {
+ HybridConfig.register();
}
/**
@@ -79,17 +46,15 @@ public static void main(String[] args) {
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePrivateKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(PRIVATE_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM);
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ public void generateAndStorePrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
}
}
- private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(PRIVATE_KEYSET_FILENAME)));
+ public KeysetHandle loadPrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
/**
@@ -98,28 +63,26 @@ private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityExcepti
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePublicKey(KeysetHandle privateKeysetHandle) throws IOException, GeneralSecurityException {
- File keysetFile = new File(PUBLIC_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
+ public void generateAndStorePublicKey(KeysetHandle privateKeysetHandle, File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
KeysetHandle keysetHandle = privateKeysetHandle.getPublicKeysetHandle();
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
}
}
- private KeysetHandle loadPublicKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(PUBLIC_KEYSET_FILENAME)));
+ public KeysetHandle loadPublicKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
- private byte[] encrypt(KeysetHandle publicKeysetHandle) throws GeneralSecurityException {
+ public byte[] encrypt(KeysetHandle publicKeysetHandle, byte[] initialText, byte[] contextInfo) throws GeneralSecurityException {
HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class);
- return hybridEncrypt.encrypt(INITIAL_TEXT.getBytes(), CONTEXT_INFO.getBytes());
+ return hybridEncrypt.encrypt(initialText, contextInfo);
}
- private byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText) throws GeneralSecurityException {
+ public byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText, byte[] contextInfo) throws GeneralSecurityException {
HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class);
- return hybridDecrypt.decrypt(cipherText, CONTEXT_INFO.getBytes());
+ return hybridDecrypt.decrypt(cipherText, contextInfo);
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKey.java
new file mode 100644
index 00000000..b2f8ed9a
--- /dev/null
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKey.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.mac;
+
+import com.google.crypto.tink.KeyTemplates;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.Mac;
+import com.google.crypto.tink.mac.MacConfig;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * Shows crypto usage with Google Tink for the Hash-based Message Authentication Code (HMAC) primitive. The used key is
+ * generated during runtime and not saved. Selected algorithm is SHA 256 with 128 bit.
+ *
+ * @author Dominik Schadow
+ */
+public class HmacShaWithGeneratedKey {
+ /**
+ * Init MacConfig in the Tink library.
+ */
+ public HmacShaWithGeneratedKey() throws GeneralSecurityException {
+ MacConfig.register();
+ }
+
+ public byte[] computeMac(KeysetHandle keysetHandle, byte[] initialText) throws GeneralSecurityException {
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+
+ return mac.computeMac(initialText);
+ }
+
+ public boolean verifyMac(KeysetHandle keysetHandle, byte[] initialMac, byte[] initialText) {
+ try {
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+ mac.verifyMac(initialMac, initialText);
+
+ return true;
+ } catch (GeneralSecurityException ex) {
+ // MAC is invalid
+ return false;
+ }
+ }
+
+ public KeysetHandle generateKey() throws GeneralSecurityException {
+ return KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG"));
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKey.java
new file mode 100644
index 00000000..f21add1a
--- /dev/null
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKey.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.mac;
+
+import com.google.crypto.tink.*;
+import com.google.crypto.tink.mac.MacConfig;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/**
+ * Shows crypto usage with Google Tink for the Hash-based Message Authentication Code (HMAC) primitive. The used key is
+ * stored and loaded from the project. Selected algorithm is SHA 256 with 128 bit.
+ *
+ * @author Dominik Schadow
+ */
+public class HmacShaWithSavedKey {
+ /**
+ * Init MacConfig in the Tink library.
+ */
+ public HmacShaWithSavedKey() throws GeneralSecurityException {
+ MacConfig.register();
+ }
+
+ /**
+ * Stores the keyset in the projects resources/keysets directory if it does not exist yet.
+ *
+ * @throws IOException Failure during saving
+ * @throws GeneralSecurityException Failure during keyset generation
+ */
+ public void generateAndStoreKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG"));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
+ }
+ }
+
+ public KeysetHandle loadKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
+ }
+
+ public byte[] computeMac(KeysetHandle keysetHandle, byte[] initialText) throws GeneralSecurityException {
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+
+ return mac.computeMac(initialText);
+ }
+
+ public boolean verifyMac(KeysetHandle keysetHandle, byte[] initialMac, byte[] initialText) {
+ try {
+ Mac mac = keysetHandle.getPrimitive(Mac.class);
+ mac.verifyMac(initialMac, initialText);
+
+ return true;
+ } catch (GeneralSecurityException ex) {
+ // MAC is invalid
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithGeneratedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithGeneratedKey.java
deleted file mode 100644
index f1a20ab0..00000000
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithGeneratedKey.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
- *
- * This file is part of the Java Security project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package de.dominikschadow.javasecurity.tink.mac;
-
-import com.google.crypto.tink.KeysetHandle;
-import com.google.crypto.tink.Mac;
-import com.google.crypto.tink.mac.MacConfig;
-import com.google.crypto.tink.mac.MacKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.security.GeneralSecurityException;
-
-/**
- * Shows crypto usage with Google Tink for the Hash-based Message Authentication Code (HMAC) primitive. The used key is
- * generated during runtime and not saved. Selected algorithm is SHA 256 with 128 bit.
- *
- * @author Dominik Schadow
- */
-public class HmcShaWithGeneratedKey {
- private static final Logger log = LoggerFactory.getLogger(HmcShaWithGeneratedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
-
- /**
- * Init MacConfig in the Tink library.
- */
- private HmcShaWithGeneratedKey() {
- try {
- MacConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- HmcShaWithGeneratedKey demo = new HmcShaWithGeneratedKey();
-
- try {
- KeysetHandle keysetHandle = demo.generateKey();
-
- byte[] tag = demo.computeMac(keysetHandle);
- boolean valid = demo.verifyMac(keysetHandle, tag);
-
- TinkUtils.printMacData(keysetHandle, INITIAL_TEXT, tag, valid);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- }
- }
-
- private byte[] computeMac(KeysetHandle keysetHandle) throws GeneralSecurityException {
- Mac mac = keysetHandle.getPrimitive(Mac.class);
-
- return mac.computeMac(INITIAL_TEXT.getBytes());
- }
-
- private boolean verifyMac(KeysetHandle keysetHandle, byte[] tag) {
- try {
- Mac mac = keysetHandle.getPrimitive(Mac.class);
- mac.verifyMac(tag, INITIAL_TEXT.getBytes());
- return true;
- } catch (GeneralSecurityException ex) {
- log.error("MAC is invalid", ex);
- }
-
- return false;
- }
-
- private KeysetHandle generateKey() throws GeneralSecurityException {
- return KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG);
- }
-}
\ No newline at end of file
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithSavedKey.java
deleted file mode 100644
index 18306215..00000000
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmcShaWithSavedKey.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
- *
- * This file is part of the Java Security project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package de.dominikschadow.javasecurity.tink.mac;
-
-import com.google.crypto.tink.*;
-import com.google.crypto.tink.mac.MacConfig;
-import com.google.crypto.tink.mac.MacKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-
-/**
- * Shows crypto usage with Google Tink for the Hash-based Message Authentication Code (HMAC) primitive. The used key is
- * stored and loaded from the project. Selected algorithm is SHA 256 with 128 bit.
- *
- * @author Dominik Schadow
- */
-public class HmcShaWithSavedKey {
- private static final Logger log = LoggerFactory.getLogger(HmcShaWithSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/hmac-sha.json";
-
- /**
- * Init MacConfig in the Tink library.
- */
- private HmcShaWithSavedKey() {
- try {
- MacConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- HmcShaWithSavedKey demo = new HmcShaWithSavedKey();
-
- try {
- demo.generateAndStoreKey();
-
- KeysetHandle keysetHandle = demo.loadKey();
-
- byte[] tag = demo.computeMac(keysetHandle);
- boolean valid = demo.verifyMac(keysetHandle, tag);
-
- TinkUtils.printMacData(keysetHandle, INITIAL_TEXT, tag, valid);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
- }
-
- /**
- * Stores the keyset in the projects resources/keysets directory if it does not exist yet.
- *
- * @throws IOException Failure during saving
- * @throws GeneralSecurityException Failure during keyset generation
- */
- private void generateAndStoreKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG);
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
- }
- }
-
- private KeysetHandle loadKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(KEYSET_FILENAME)));
- }
-
- private byte[] computeMac(KeysetHandle keysetHandle) throws GeneralSecurityException {
- Mac mac = keysetHandle.getPrimitive(Mac.class);
-
- return mac.computeMac(INITIAL_TEXT.getBytes());
- }
-
- private boolean verifyMac(KeysetHandle keysetHandle, byte[] tag) {
- try {
- Mac mac = keysetHandle.getPrimitive(Mac.class);
- mac.verifyMac(tag, INITIAL_TEXT.getBytes());
- return true;
- } catch (GeneralSecurityException ex) {
- log.error("MAC is invalid", ex);
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKey.java
index ad21c7fe..3361258f 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,14 +17,11 @@
*/
package de.dominikschadow.javasecurity.tink.signature;
+import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.signature.SignatureConfig;
-import com.google.crypto.tink.signature.SignatureKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.security.GeneralSecurityException;
@@ -35,59 +32,35 @@
* @author Dominik Schadow
*/
public class EcdsaWithGeneratedKey {
- private static final Logger log = LoggerFactory.getLogger(EcdsaWithGeneratedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
-
/**
* Init SignatureConfig in the Tink library.
*/
- private EcdsaWithGeneratedKey() {
- try {
- SignatureConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
+ public EcdsaWithGeneratedKey() throws GeneralSecurityException {
+ SignatureConfig.register();
}
- public static void main(String[] args) {
- EcdsaWithGeneratedKey demo = new EcdsaWithGeneratedKey();
-
- try {
- KeysetHandle privateKeysetHandle = demo.generatePrivateKey();
- KeysetHandle publicKeysetHandle = demo.generatePublicKey(privateKeysetHandle);
-
- byte[] signature = demo.sign(privateKeysetHandle);
- boolean valid = demo.verify(publicKeysetHandle, signature);
-
- TinkUtils.printSignatureData(privateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, signature, valid);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- }
+ public KeysetHandle generatePrivateKey() throws GeneralSecurityException {
+ return KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
}
- private KeysetHandle generatePrivateKey() throws GeneralSecurityException {
- return KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P384);
- }
-
- private KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
+ public KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
return privateKeysetHandle.getPublicKeysetHandle();
}
- private byte[] sign(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
+ public byte[] sign(KeysetHandle privateKeysetHandle, byte[] initialText) throws GeneralSecurityException {
PublicKeySign signer = privateKeysetHandle.getPrimitive(PublicKeySign.class);
- return signer.sign(INITIAL_TEXT.getBytes());
+ return signer.sign(initialText);
}
- private boolean verify(KeysetHandle publicKeysetHandle, byte[] signature) {
+ public boolean verify(KeysetHandle publicKeysetHandle, byte[] signature, byte[] initialText) {
try {
PublicKeyVerify verifier = publicKeysetHandle.getPrimitive(PublicKeyVerify.class);
- verifier.verify(signature, INITIAL_TEXT.getBytes());
+ verifier.verify(signature, initialText);
return true;
} catch (GeneralSecurityException ex) {
- log.error("Signature is invalid", ex);
+ // Signature is invalid
+ return false;
}
-
- return false;
}
}
diff --git a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKey.java b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKey.java
index b859f549..fc398a50 100644
--- a/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKey.java
+++ b/crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,12 +19,10 @@
import com.google.crypto.tink.*;
import com.google.crypto.tink.signature.SignatureConfig;
-import com.google.crypto.tink.signature.SignatureKeyTemplates;
-import de.dominikschadow.javasecurity.tink.TinkUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -35,41 +33,11 @@
* @author Dominik Schadow
*/
public class EcdsaWithSavedKey {
- private static final Logger log = LoggerFactory.getLogger(EcdsaWithSavedKey.class);
- private static final String INITIAL_TEXT = "Some dummy text to work with";
- private static final String PRIVATE_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/signature-ecdsa-private.json";
- private static final String PUBLIC_KEYSET_FILENAME = "crypto-tink/src/main/resources/keysets/signature-ecdsa-public.json";
-
/**
* Init SignatureConfig in the Tink library.
*/
- private EcdsaWithSavedKey() {
- try {
- SignatureConfig.register();
- } catch (GeneralSecurityException ex) {
- log.error("Failed to initialize Tink", ex);
- }
- }
-
- public static void main(String[] args) {
- EcdsaWithSavedKey demo = new EcdsaWithSavedKey();
-
- try {
- demo.generateAndStorePrivateKey();
- KeysetHandle privateKeysetHandle = demo.loadPrivateKey();
-
- demo.generateAndStorePublicKey(privateKeysetHandle);
- KeysetHandle publicKeysetHandle = demo.loadPublicKey();
-
- byte[] signature = demo.sign(privateKeysetHandle);
- boolean valid = demo.verify(publicKeysetHandle, signature);
-
- TinkUtils.printSignatureData(privateKeysetHandle, publicKeysetHandle, INITIAL_TEXT, signature, valid);
- } catch (GeneralSecurityException ex) {
- log.error("Failure during Tink usage", ex);
- } catch (IOException ex) {
- log.error("Failure during storing key", ex);
- }
+ public EcdsaWithSavedKey() throws GeneralSecurityException {
+ SignatureConfig.register();
}
/**
@@ -78,17 +46,15 @@ public static void main(String[] args) {
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePrivateKey() throws IOException, GeneralSecurityException {
- File keysetFile = new File(PRIVATE_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
- KeysetHandle keysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256);
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ public void generateAndStorePrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
}
}
- private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(PRIVATE_KEYSET_FILENAME)));
+ public KeysetHandle loadPrivateKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
/**
@@ -97,34 +63,31 @@ private KeysetHandle loadPrivateKey() throws IOException, GeneralSecurityExcepti
* @throws IOException Failure during saving
* @throws GeneralSecurityException Failure during keyset generation
*/
- private void generateAndStorePublicKey(KeysetHandle privateKeysetHandle) throws IOException, GeneralSecurityException {
- File keysetFile = new File(PUBLIC_KEYSET_FILENAME);
-
- if (!keysetFile.exists()) {
+ public void generateAndStorePublicKey(KeysetHandle privateKeysetHandle, File keyset) throws IOException, GeneralSecurityException {
+ if (!keyset.exists()) {
KeysetHandle keysetHandle = privateKeysetHandle.getPublicKeysetHandle();
- CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(keysetFile));
+ CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withOutputStream(new FileOutputStream((keyset))));
}
}
- private KeysetHandle loadPublicKey() throws IOException, GeneralSecurityException {
- return CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(PUBLIC_KEYSET_FILENAME)));
+ public KeysetHandle loadPublicKey(File keyset) throws IOException, GeneralSecurityException {
+ return CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(new FileInputStream(keyset)));
}
- private byte[] sign(KeysetHandle privateKeysetHandle) throws GeneralSecurityException {
+ public byte[] sign(KeysetHandle privateKeysetHandle, byte[] initialText) throws GeneralSecurityException {
PublicKeySign signer = privateKeysetHandle.getPrimitive(PublicKeySign.class);
- return signer.sign(INITIAL_TEXT.getBytes());
+ return signer.sign(initialText);
}
- private boolean verify(KeysetHandle publicKeysetHandle, byte[] signature) {
+ public boolean verify(KeysetHandle publicKeysetHandle, byte[] signature, byte[] initialText) {
try {
PublicKeyVerify verifier = publicKeysetHandle.getPrimitive(PublicKeyVerify.class);
- verifier.verify(signature, INITIAL_TEXT.getBytes());
+ verifier.verify(signature, initialText);
return true;
} catch (GeneralSecurityException ex) {
- log.error("Signature is invalid", ex);
+ // Signature is invalid
+ return false;
}
-
- return false;
}
}
diff --git a/crypto-tink/src/main/resources/keysets/aead-aes-gcm-kms.json b/crypto-tink/src/main/resources/keysets/aead-aes-gcm-kms.json
deleted file mode 100644
index 4dbb7bcc..00000000
--- a/crypto-tink/src/main/resources/keysets/aead-aes-gcm-kms.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "keysetInfo": {
- "primaryKeyId": 1351580745,
- "keyInfo": [{
- "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
- "outputPrefixType": "TINK",
- "keyId": 1351580745,
- "status": "ENABLED"
- }]
- },
- "encryptedKeyset": "AQICAHiHki7c9xeXD8haAwCxa10hOyyX2RaEmNlP9qo0skL9DwFBPtBz3Tidf5UPgp0/ebWrAAAAvjCBuwYJKoZIhvcNAQcGoIGtMIGqAgEAMIGkBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHySzk1uw3KkalRDrQIBEIB3VbgoYk7KBie+OALsCLF06iX51RCDdMUwpaqgPbdziM94IVNPxItjqDHruYmBp11sTdD6h8/yMJwLQlRCQfCBTswrdUiGkE+87tkXtgVPRWVRCUa2Q215ZxNDM0v9lRjt8bqKdERrWOr3TU1OcexPL6y4bYy+c2Q="
-}
\ No newline at end of file
diff --git a/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-private.json b/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-private.json
deleted file mode 100644
index 8e711e11..00000000
--- a/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-private.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "keysetInfo": {
- "primaryKeyId": 383437302,
- "keyInfo": [{
- "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey",
- "outputPrefixType": "TINK",
- "keyId": 383437302,
- "status": "ENABLED"
- }]
- },
- "encryptedKeyset": "AQICAHiHki7c9xeXD8haAwCxa10hOyyX2RaEmNlP9qo0skL9DwFXlI7T9O44yMLFgqrHvtPPAAABdDCCAXAGCSqGSIb3DQEHBqCCAWEwggFdAgEAMIIBVgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzwKxK1nJ3zZd5L1GMCARCAggEnY7bz9Q8eOAhnrWHLDWHaFUw1opfti2B/vG6xjwS/VaF53MVDVF0SMRDfGJmeg5CwgAI9jSgo8FBKGjh8MepMjpauz6iZpNXrqMaP1YgbuEgPxK6pBaBd2wX1LaCrNelY70hAQSRbNbLFQC+aEaHer8TkDJMFCsuZnz5uKXqWtF+/6wkcOlwr2VI52tHOEbDDluKiyB5lvx36TiV3s0X+jfbPlybBDrj56QkbDBDaUFoZ9pLEcGNzY8nIzupt+IvDxDnE95n9VbXCZHRPPZ+bzjkxL0iYCUHPrevUugui4zyiOZCH6ra/O8YhuiUHpXRbB3jEXkcFHdXotml3VSu05QSmSZL+u7J7/6Q3It1ZWj5qh+bR+aPOkamSMNUdLG1FePx/6tdQ+Q=="
-}
\ No newline at end of file
diff --git a/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-public.json b/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-public.json
deleted file mode 100644
index de893bfd..00000000
--- a/crypto-tink/src/main/resources/keysets/hybrid-ecies-kms-public.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "primaryKeyId": 383437302,
- "key": [{
- "keyData": {
- "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey",
- "keyMaterialType": "ASYMMETRIC_PUBLIC",
- "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARohAJxuWyN5/mVUPs7zwfvZYf+aJTpjz0pC4SQzCPqReL72IiEArX9AUfFLzRVp1UOBDZiZpdklIojUBCMWexFmKQkgTVw="
- },
- "outputPrefixType": "TINK",
- "keyId": 383437302,
- "status": "ENABLED"
- }]
-}
\ No newline at end of file
diff --git a/crypto-tink/src/main/resources/log4j2.xml b/crypto-tink/src/main/resources/log4j2.xml
deleted file mode 100644
index 35a6a3cc..00000000
--- a/crypto-tink/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKeyTest.java
new file mode 100644
index 00000000..1c7d1758
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKeyTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.aead;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AesEaxWithGeneratedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] ASSOCIATED_DATA = "Some additional data".getBytes(StandardCharsets.UTF_8);
+
+ private AesEaxWithGeneratedKey aes;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ aes = new AesEaxWithGeneratedKey();
+ }
+
+ @Test
+ void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
+ KeysetHandle secretKey = aes.generateKey();
+
+ byte[] cipherText = aes.encrypt(secretKey, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] plainText = aes.decrypt(secretKey, cipherText, ASSOCIATED_DATA);
+
+ Assertions.assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+
+ @Test
+ void decryptionWithInvalidAssociatedDataFails() throws Exception {
+ KeysetHandle secretKey = aes.generateKey();
+
+ byte[] cipherText = aes.encrypt(secretKey, INITIAL_TEXT, ASSOCIATED_DATA);
+
+ Exception exception = assertThrows(GeneralSecurityException.class, () -> aes.decrypt(secretKey, cipherText, "manipulation".getBytes(StandardCharsets.UTF_8)));
+
+ assertTrue(exception.getMessage().contains("decryption failed"));
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKeyTest.java
new file mode 100644
index 00000000..75874731
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithAwsKmsSavedKeyTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.aead;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.KeyTemplates;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.aead.AeadConfig;
+import com.google.crypto.tink.integration.awskms.AwsKmsClient;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class AesGcmWithAwsKmsSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] ASSOCIATED_DATA = "Some additional data".getBytes(StandardCharsets.UTF_8);
+
+ @Mock
+ private AwsKmsClient awsKmsClient;
+
+ @TempDir
+ File tempDir;
+
+ private AesGcmWithAwsKmsSavedKey aes;
+ private KeysetHandle testKeysetHandle;
+
+ @BeforeAll
+ static void initTink() throws GeneralSecurityException {
+ AeadConfig.register();
+ }
+
+ @BeforeEach
+ void setup() throws Exception {
+ aes = new AesGcmWithAwsKmsSavedKey(awsKmsClient);
+ testKeysetHandle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));
+ }
+
+ @Test
+ void constructorInitializesSuccessfully() throws GeneralSecurityException {
+ AesGcmWithAwsKmsSavedKey instance = new AesGcmWithAwsKmsSavedKey(awsKmsClient);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void constructorWithNullAwsKmsClientThrowsNoException() throws GeneralSecurityException {
+ // The constructor accepts null - validation happens later when using the client
+ AesGcmWithAwsKmsSavedKey instance = new AesGcmWithAwsKmsSavedKey(null);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void encryptReturnsEncryptedData() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+
+ assertNotNull(cipherText);
+ assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void encryptWithEmptyAssociatedDataSucceeds() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, new byte[0]);
+
+ assertNotNull(cipherText);
+ assertTrue(cipherText.length > 0);
+ }
+
+ @Test
+ void decryptReturnsOriginalData() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] plainText = aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA);
+
+ assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void decryptWithWrongAssociatedDataThrowsException() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] wrongAssociatedData = "Wrong associated data".getBytes(StandardCharsets.UTF_8);
+
+ assertThrows(GeneralSecurityException.class, () ->
+ aes.decrypt(testKeysetHandle, cipherText, wrongAssociatedData)
+ );
+ }
+
+ @Test
+ void decryptWithCorruptedCipherTextThrowsException() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+ // Corrupt the ciphertext
+ cipherText[0] = (byte) (cipherText[0] ^ 0xFF);
+
+ assertThrows(GeneralSecurityException.class, () ->
+ aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA)
+ );
+ }
+
+ @Test
+ void encryptionAndDecryptionRoundTripIsSuccessful() throws Exception {
+ byte[] cipherText = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] plainText = aes.decrypt(testKeysetHandle, cipherText, ASSOCIATED_DATA);
+
+ assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+
+ @Test
+ void encryptProducesDifferentCipherTextForSameInput() throws Exception {
+ byte[] cipherText1 = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] cipherText2 = aes.encrypt(testKeysetHandle, INITIAL_TEXT, ASSOCIATED_DATA);
+
+ // AES-GCM uses random nonces, so encrypting the same plaintext twice should produce different ciphertexts
+ assertNotEquals(new String(cipherText1, StandardCharsets.UTF_8), new String(cipherText2, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void generateAndStoreKeyDoesNotOverwriteExistingFile() throws Exception {
+ File keysetFile = new File(tempDir, "existing-keyset.json");
+ assertTrue(keysetFile.createNewFile());
+ long originalLength = keysetFile.length();
+
+ aes.generateAndStoreKey(keysetFile);
+
+ // File should remain unchanged (empty) since it already existed
+ assertEquals(originalLength, keysetFile.length());
+ verify(awsKmsClient, never()).getAead(any());
+ }
+
+ @Test
+ void generateAndStoreKeyCallsAwsKmsClientForNewFile() throws Exception {
+ File keysetFile = new File(tempDir, "new-keyset.json");
+ Aead mockAead = mock(Aead.class);
+ when(awsKmsClient.getAead(any())).thenReturn(mockAead);
+ // Tink internally validates the encrypted keyset, so we need to throw an exception
+ // to simulate what happens when AWS KMS is not available, but still verify the call
+ when(mockAead.encrypt(any(), any())).thenThrow(new GeneralSecurityException("Mocked AWS KMS encryption"));
+
+ assertFalse(keysetFile.exists());
+
+ assertThrows(GeneralSecurityException.class, () -> aes.generateAndStoreKey(keysetFile));
+
+ // Verify that AWS KMS client was called
+ verify(awsKmsClient).getAead(contains("aws-kms://"));
+ verify(mockAead).encrypt(any(), any());
+ }
+
+ @Test
+ void loadKeyCallsAwsKmsClient() throws Exception {
+ // First create a keyset file using the same mock setup
+ File keysetFile = new File(tempDir, "load-test-keyset.json");
+ Aead mockAead = mock(Aead.class);
+ when(awsKmsClient.getAead(any())).thenReturn(mockAead);
+
+ // Mock encrypt to return the plaintext (simulating encryption that returns same bytes)
+ when(mockAead.encrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
+ // Mock decrypt to return the ciphertext (simulating decryption that returns same bytes)
+ when(mockAead.decrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
+
+ aes.generateAndStoreKey(keysetFile);
+
+ KeysetHandle loadedKey = aes.loadKey(keysetFile);
+
+ assertNotNull(loadedKey);
+ // Verify getAead was called twice - once for generate, once for load
+ verify(awsKmsClient, times(2)).getAead(contains("aws-kms://"));
+ }
+
+ @Test
+ void encryptWithNullKeysetHandleThrowsException() {
+ assertThrows(NullPointerException.class, () ->
+ aes.encrypt(null, INITIAL_TEXT, ASSOCIATED_DATA)
+ );
+ }
+
+ @Test
+ void decryptWithNullKeysetHandleThrowsException() {
+ assertThrows(NullPointerException.class, () ->
+ aes.decrypt(null, INITIAL_TEXT, ASSOCIATED_DATA)
+ );
+ }
+}
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKeyTest.java
new file mode 100644
index 00000000..cf76217c
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKeyTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.aead;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+class AesGcmWithSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] ASSOCIATED_DATA = "Some additional data".getBytes(StandardCharsets.UTF_8);
+ private static final String KEYSET_FILENAME = "src/test/resources/keysets/aead-aes-gcm.json";
+ private final File keysetFile = new File(KEYSET_FILENAME);
+ private KeysetHandle secretKey;
+
+ private AesGcmWithSavedKey aes;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ aes = new AesGcmWithSavedKey();
+
+ aes.generateAndStoreKey(keysetFile);
+ secretKey = aes.loadKey(keysetFile);
+ }
+
+ @Test
+ void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
+ byte[] cipherText = aes.encrypt(secretKey, INITIAL_TEXT, ASSOCIATED_DATA);
+ byte[] plainText = aes.decrypt(secretKey, cipherText, ASSOCIATED_DATA);
+
+ Assertions.assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKeyTest.java
new file mode 100644
index 00000000..26ce4e23
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithAwsKmsSavedKeyTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.hybrid;
+
+import com.google.crypto.tink.Aead;
+import com.google.crypto.tink.KeyTemplates;
+import com.google.crypto.tink.KeysetHandle;
+import com.google.crypto.tink.hybrid.HybridConfig;
+import com.google.crypto.tink.integration.awskms.AwsKmsClient;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class EciesWithAwsKmsSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] CONTEXT_INFO = "Some context info".getBytes(StandardCharsets.UTF_8);
+
+ @Mock
+ private AwsKmsClient awsKmsClient;
+
+ @TempDir
+ File tempDir;
+
+ private EciesWithAwsKmsSavedKey ecies;
+ private KeysetHandle testPrivateKeysetHandle;
+ private KeysetHandle testPublicKeysetHandle;
+
+ @BeforeAll
+ static void initTink() throws GeneralSecurityException {
+ HybridConfig.register();
+ }
+
+ @BeforeEach
+ void setup() throws Exception {
+ ecies = new EciesWithAwsKmsSavedKey(awsKmsClient);
+ testPrivateKeysetHandle = KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"));
+ testPublicKeysetHandle = testPrivateKeysetHandle.getPublicKeysetHandle();
+ }
+
+ @Test
+ void constructorInitializesSuccessfully() throws GeneralSecurityException {
+ EciesWithAwsKmsSavedKey instance = new EciesWithAwsKmsSavedKey(awsKmsClient);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void constructorWithNullAwsKmsClientThrowsNoException() throws GeneralSecurityException {
+ // The constructor accepts null - validation happens later when using the client
+ EciesWithAwsKmsSavedKey instance = new EciesWithAwsKmsSavedKey(null);
+ assertNotNull(instance);
+ }
+
+ @Test
+ void encryptReturnsEncryptedData() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+
+ assertNotNull(cipherText);
+ assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void encryptWithEmptyContextInfoSucceeds() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, new byte[0]);
+
+ assertNotNull(cipherText);
+ assertTrue(cipherText.length > 0);
+ }
+
+ @Test
+ void decryptReturnsOriginalData() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(testPrivateKeysetHandle, cipherText, CONTEXT_INFO);
+
+ assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void decryptWithWrongContextInfoThrowsException() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] wrongContextInfo = "Wrong context info".getBytes(StandardCharsets.UTF_8);
+
+ assertThrows(GeneralSecurityException.class, () ->
+ ecies.decrypt(testPrivateKeysetHandle, cipherText, wrongContextInfo)
+ );
+ }
+
+ @Test
+ void decryptWithCorruptedCipherTextThrowsException() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ // Corrupt the ciphertext
+ cipherText[0] = (byte) (cipherText[0] ^ 0xFF);
+
+ assertThrows(GeneralSecurityException.class, () ->
+ ecies.decrypt(testPrivateKeysetHandle, cipherText, CONTEXT_INFO)
+ );
+ }
+
+ @Test
+ void encryptionAndDecryptionRoundTripIsSuccessful() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(testPrivateKeysetHandle, cipherText, CONTEXT_INFO);
+
+ assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+
+ @Test
+ void encryptProducesDifferentCipherTextForSameInput() throws Exception {
+ byte[] cipherText1 = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] cipherText2 = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+
+ // ECIES uses random nonces, so encrypting the same plaintext twice should produce different ciphertexts
+ assertNotEquals(new String(cipherText1, StandardCharsets.UTF_8), new String(cipherText2, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ void generateAndStorePrivateKeyDoesNotOverwriteExistingFile() throws Exception {
+ File keysetFile = new File(tempDir, "existing-private-keyset.json");
+ assertTrue(keysetFile.createNewFile());
+ long originalLength = keysetFile.length();
+
+ ecies.generateAndStorePrivateKey(keysetFile);
+
+ // File should remain unchanged (empty) since it already existed
+ assertEquals(originalLength, keysetFile.length());
+ verify(awsKmsClient, never()).getAead(any());
+ }
+
+ @Test
+ void generateAndStorePrivateKeyCallsAwsKmsClientForNewFile() throws Exception {
+ File keysetFile = new File(tempDir, "new-private-keyset.json");
+ Aead mockAead = mock(Aead.class);
+ when(awsKmsClient.getAead(any())).thenReturn(mockAead);
+ // Tink internally validates the encrypted keyset, so we need to throw an exception
+ // to simulate what happens when AWS KMS is not available, but still verify the call
+ when(mockAead.encrypt(any(), any())).thenThrow(new GeneralSecurityException("Mocked AWS KMS encryption"));
+
+ assertFalse(keysetFile.exists());
+
+ assertThrows(GeneralSecurityException.class, () -> ecies.generateAndStorePrivateKey(keysetFile));
+
+ // Verify that AWS KMS client was called
+ verify(awsKmsClient).getAead(contains("aws-kms://"));
+ verify(mockAead).encrypt(any(), any());
+ }
+
+ @Test
+ void generateAndStorePublicKeyDoesNotOverwriteExistingFile() throws Exception {
+ File keysetFile = new File(tempDir, "existing-public-keyset.json");
+ assertTrue(keysetFile.createNewFile());
+ long originalLength = keysetFile.length();
+
+ ecies.generateAndStorePublicKey(testPrivateKeysetHandle, keysetFile);
+
+ // File should remain unchanged (empty) since it already existed
+ assertEquals(originalLength, keysetFile.length());
+ }
+
+ @Test
+ void generateAndStorePublicKeyCreatesNewFile() throws Exception {
+ File keysetFile = new File(tempDir, "new-public-keyset.json");
+ assertFalse(keysetFile.exists());
+
+ ecies.generateAndStorePublicKey(testPrivateKeysetHandle, keysetFile);
+
+ assertTrue(keysetFile.exists());
+ assertTrue(keysetFile.length() > 0);
+ }
+
+ @Test
+ void loadPrivateKeyCallsAwsKmsClient() throws Exception {
+ // First create a keyset file using the same mock setup
+ File keysetFile = new File(tempDir, "load-test-private-keyset.json");
+ Aead mockAead = mock(Aead.class);
+ when(awsKmsClient.getAead(any())).thenReturn(mockAead);
+
+ // Mock encrypt to return the plaintext (simulating encryption that returns same bytes)
+ when(mockAead.encrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
+ // Mock decrypt to return the ciphertext (simulating decryption that returns same bytes)
+ when(mockAead.decrypt(any(), any())).thenAnswer(invocation -> invocation.getArgument(0));
+
+ ecies.generateAndStorePrivateKey(keysetFile);
+
+ KeysetHandle loadedKey = ecies.loadPrivateKey(keysetFile);
+
+ assertNotNull(loadedKey);
+ // Verify getAead was called twice - once for generate, once for load
+ verify(awsKmsClient, times(2)).getAead(contains("aws-kms://"));
+ }
+
+ @Test
+ void loadPublicKeyReturnsKeysetHandle() throws Exception {
+ File keysetFile = new File(tempDir, "load-test-public-keyset.json");
+ ecies.generateAndStorePublicKey(testPrivateKeysetHandle, keysetFile);
+
+ KeysetHandle loadedKey = ecies.loadPublicKey(keysetFile);
+
+ assertNotNull(loadedKey);
+ }
+
+ @Test
+ void encryptWithNullKeysetHandleThrowsException() {
+ assertThrows(NullPointerException.class, () ->
+ ecies.encrypt(null, INITIAL_TEXT, CONTEXT_INFO)
+ );
+ }
+
+ @Test
+ void decryptWithNullKeysetHandleThrowsException() {
+ assertThrows(NullPointerException.class, () ->
+ ecies.decrypt(null, INITIAL_TEXT, CONTEXT_INFO)
+ );
+ }
+
+ @Test
+ void encryptWithPublicKeyAndDecryptWithPrivateKeySucceeds() throws Exception {
+ // This test verifies the asymmetric nature of hybrid encryption
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(testPrivateKeysetHandle, cipherText, CONTEXT_INFO);
+
+ assertArrayEquals(INITIAL_TEXT, plainText);
+ }
+
+ @Test
+ void decryptWithPublicKeyThrowsException() throws Exception {
+ byte[] cipherText = ecies.encrypt(testPublicKeysetHandle, INITIAL_TEXT, CONTEXT_INFO);
+
+ // Decrypting with public key should fail - only private key can decrypt
+ assertThrows(GeneralSecurityException.class, () ->
+ ecies.decrypt(testPublicKeysetHandle, cipherText, CONTEXT_INFO)
+ );
+ }
+}
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotationTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotationTest.java
new file mode 100644
index 00000000..8c8c8c8b
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotationTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.hybrid;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+class EciesWithGeneratedKeyAndKeyRotationTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] CONTEXT_INFO = "Some additional data".getBytes(StandardCharsets.UTF_8);
+
+ private EciesWithGeneratedKeyAndKeyRotation ecies;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ ecies = new EciesWithGeneratedKeyAndKeyRotation();
+ }
+
+ @Test
+ void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
+ KeysetHandle originalKey = ecies.generatePrivateKey();
+ KeysetHandle rotatedKey = ecies.rotateKey(originalKey);
+ KeysetHandle publicKey = ecies.generatePublicKey(rotatedKey);
+
+ byte[] cipherText = ecies.encrypt(publicKey, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(rotatedKey, cipherText, CONTEXT_INFO);
+
+ Assertions.assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertNotEquals(originalKey.getKeysetInfo().getPrimaryKeyId(), rotatedKey.getKeysetInfo().getPrimaryKeyId()),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyTest.java
new file mode 100644
index 00000000..3b507e58
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.hybrid;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EciesWithGeneratedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] CONTEXT_INFO = "Some additional data".getBytes(StandardCharsets.UTF_8);
+
+ private EciesWithGeneratedKey ecies;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ ecies = new EciesWithGeneratedKey();
+ }
+
+ @Test
+ void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
+ KeysetHandle privateKey = ecies.generatePrivateKey();
+ KeysetHandle publicKey = ecies.generatePublicKey(privateKey);
+
+ byte[] cipherText = ecies.encrypt(publicKey, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(privateKey, cipherText, CONTEXT_INFO);
+
+ Assertions.assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+
+ @Test
+ void decryptionWithInvalidAssociatedDataFails() throws Exception {
+ KeysetHandle privateKey = ecies.generatePrivateKey();
+ KeysetHandle publicKey = ecies.generatePublicKey(privateKey);
+
+ byte[] cipherText = ecies.encrypt(publicKey, INITIAL_TEXT, CONTEXT_INFO);
+
+ Exception exception = assertThrows(GeneralSecurityException.class, () -> ecies.decrypt(privateKey, cipherText, "manipulation".getBytes(StandardCharsets.UTF_8)));
+
+ assertTrue(exception.getMessage().contains("decryption failed"));
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKeyTest.java
new file mode 100644
index 00000000..63b688c7
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithSavedKeyTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.hybrid;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+class EciesWithSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] CONTEXT_INFO = "Some additional data".getBytes(StandardCharsets.UTF_8);
+ private static final String PRIVATE_KEYSET_FILENAME = "src/test/resources/keysets/hybrid-ecies-private.json";
+ private static final String PUBLIC_KEYSET_FILENAME = "src/test/resources/keysets/hybrid-ecies-public.json";
+ private final File privateKeysetFile = new File(PRIVATE_KEYSET_FILENAME);
+ private final File publicKeysetFile = new File(PUBLIC_KEYSET_FILENAME);
+ private KeysetHandle publicKey;
+ private KeysetHandle privateKey;
+
+ private EciesWithSavedKey ecies;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ ecies = new EciesWithSavedKey();
+
+ ecies.generateAndStorePrivateKey(privateKeysetFile);
+ privateKey = ecies.loadPrivateKey(privateKeysetFile);
+
+ ecies.generateAndStorePublicKey(privateKey, publicKeysetFile);
+ publicKey = ecies.loadPublicKey(publicKeysetFile);
+ }
+
+ @Test
+ void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception {
+ byte[] cipherText = ecies.encrypt(publicKey, INITIAL_TEXT, CONTEXT_INFO);
+ byte[] plainText = ecies.decrypt(privateKey, cipherText, CONTEXT_INFO);
+
+ Assertions.assertAll(
+ () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)),
+ () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8))
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKeyTest.java
new file mode 100644
index 00000000..65043140
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKeyTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.mac;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HmacShaWithGeneratedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+
+ private HmacShaWithGeneratedKey hmac;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ hmac = new HmacShaWithGeneratedKey();
+ }
+
+ @Test
+ void unchangedInputValidatesSuccessful() throws Exception {
+ KeysetHandle keysetHandle = hmac.generateKey();
+
+ byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT);
+ boolean validation = hmac.verifyMac(keysetHandle, initialMac, INITIAL_TEXT);
+
+ Assertions.assertAll(
+ () -> assertNotNull(initialMac),
+ () -> assertTrue(validation)
+ );
+ }
+
+ @Test
+ void changedInputValidationFails() throws Exception {
+ KeysetHandle keysetHandle = hmac.generateKey();
+
+ byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT);
+ boolean validation = hmac.verifyMac(keysetHandle, initialMac, "manipulation".getBytes(StandardCharsets.UTF_8));
+
+ Assertions.assertAll(
+ () -> assertNotNull(initialMac),
+ () -> assertFalse(validation)
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKeyTest.java
new file mode 100644
index 00000000..33ad59b3
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithSavedKeyTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.mac;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HmacShaWithSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final String KEYSET_FILENAME = "src/test/resources/keysets/hmac-sha.json";
+ private final File keysetFile = new File(KEYSET_FILENAME);
+
+ private HmacShaWithSavedKey hmac;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ hmac = new HmacShaWithSavedKey();
+
+ hmac.generateAndStoreKey(keysetFile);
+ }
+
+ @Test
+ void unchangedInputValidatesSuccessful() throws Exception {
+ KeysetHandle keysetHandle = hmac.loadKey(keysetFile);
+
+ byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT);
+ boolean validation = hmac.verifyMac(keysetHandle, initialMac, INITIAL_TEXT);
+
+ Assertions.assertAll(
+ () -> assertNotNull(initialMac),
+ () -> assertTrue(validation)
+ );
+ }
+
+ @Test
+ void changedInputValidationFails() throws Exception {
+ KeysetHandle keysetHandle = hmac.loadKey(keysetFile);
+
+ byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT);
+ boolean validation = hmac.verifyMac(keysetHandle, initialMac, "manipulation".getBytes(StandardCharsets.UTF_8));
+
+ Assertions.assertAll(
+ () -> assertNotNull(initialMac),
+ () -> assertFalse(validation)
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKeyTest.java
new file mode 100644
index 00000000..b302f499
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithGeneratedKeyTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.signature;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class EcdsaWithGeneratedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+
+ private EcdsaWithGeneratedKey ecdsa ;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ ecdsa = new EcdsaWithGeneratedKey();
+ }
+
+ @Test
+ void unchangedInputValidatesSuccessful() throws Exception {
+ KeysetHandle privateKey = ecdsa.generatePrivateKey();
+ KeysetHandle publicKey = ecdsa.generatePublicKey(privateKey);
+
+ byte[] signature = ecdsa.sign(privateKey, INITIAL_TEXT);
+ boolean validation = ecdsa.verify(publicKey, signature, INITIAL_TEXT);
+
+ Assertions.assertAll(
+ () -> assertTrue(signature.length > 0),
+ () -> assertTrue(validation)
+ );
+ }
+
+ @Test
+ void changedInputValidationFails() throws Exception {
+ KeysetHandle privateKey = ecdsa.generatePrivateKey();
+ KeysetHandle publicKey = ecdsa.generatePublicKey(privateKey);
+
+ byte[] signature = ecdsa.sign(privateKey, INITIAL_TEXT);
+ boolean validation = ecdsa.verify(publicKey, signature, "Manipulation".getBytes(StandardCharsets.UTF_8));
+
+ Assertions.assertAll(
+ () -> assertTrue(signature.length > 0),
+ () -> assertFalse(validation)
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKeyTest.java b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKeyTest.java
new file mode 100644
index 00000000..0c661bcd
--- /dev/null
+++ b/crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/signature/EcdsaWithSavedKeyTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.tink.signature;
+
+import com.google.crypto.tink.KeysetHandle;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class EcdsaWithSavedKeyTest {
+ private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8);
+ private static final String PRIVATE_KEYSET_FILENAME = "src/test/resources/keysets/signature-ecdsa-private.json";
+ private static final String PUBLIC_KEYSET_FILENAME = "src/test/resources/keysets/signature-ecdsa-public.json";
+ private final File privateKeysetFile = new File(PRIVATE_KEYSET_FILENAME);
+ private final File publicKeysetFile = new File(PUBLIC_KEYSET_FILENAME);
+ private KeysetHandle publicKey;
+ private KeysetHandle privateKey;
+
+ private EcdsaWithSavedKey ecdsa;
+
+ @BeforeEach
+ protected void setup() throws Exception {
+ ecdsa = new EcdsaWithSavedKey();
+
+ ecdsa.generateAndStorePrivateKey(privateKeysetFile);
+ privateKey = ecdsa.loadPrivateKey(privateKeysetFile);
+
+ ecdsa.generateAndStorePublicKey(privateKey, publicKeysetFile);
+ publicKey = ecdsa.loadPublicKey(publicKeysetFile);
+ }
+
+ @Test
+ void unchangedInputValidatesSuccessful() throws Exception {
+ byte[] signature = ecdsa.sign(privateKey, INITIAL_TEXT);
+ boolean validation = ecdsa.verify(publicKey, signature, INITIAL_TEXT);
+
+ Assertions.assertAll(
+ () -> assertTrue(signature.length > 0),
+ () -> assertTrue(validation)
+ );
+ }
+
+ @Test
+ void changedInputValidationFails() throws Exception {
+ byte[] signature = ecdsa.sign(privateKey, INITIAL_TEXT);
+ boolean validation = ecdsa.verify(publicKey, signature, "Manipulation".getBytes(StandardCharsets.UTF_8));
+
+ Assertions.assertAll(
+ () -> assertTrue(signature.length > 0),
+ () -> assertFalse(validation)
+ );
+ }
+}
\ No newline at end of file
diff --git a/crypto-tink/src/test/resources/keysets/aead-aes-gcm-kms.json b/crypto-tink/src/test/resources/keysets/aead-aes-gcm-kms.json
new file mode 100644
index 00000000..6d381393
--- /dev/null
+++ b/crypto-tink/src/test/resources/keysets/aead-aes-gcm-kms.json
@@ -0,0 +1 @@
+{"encryptedKeyset":"AQICAHjXd7WP9NB78zMSpXCiIaQEPB/K2Ud3VinJdPgxys8yuQHWCk8U1SMe+Z/R8hW6opG3AAAAvjCBuwYJKoZIhvcNAQcGoIGtMIGqAgEAMIGkBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDOLJ88WqVDo7mor5QwIBEIB3IusYc6T8mAhMFyeBN3xtOqJM1oShYrrQ6GON23dorIvFcK9uzFwk5vd5oh0Db6Zb02+f5ORGSu7McLNZvNh4NjPUz9u9E3/Vi0NLXaIMvHvXRuFVPIWWQ+dP2BN7FtRYQHQvspBOuKc4y3JM9GZFtMF6O/6XKpE=","keysetInfo":{"primaryKeyId":1300661024,"keyInfo":[{"typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey","status":"ENABLED","keyId":1300661024,"outputPrefixType":"TINK"}]}}
diff --git a/crypto-tink/src/main/resources/keysets/aead-aes-gcm.json b/crypto-tink/src/test/resources/keysets/aead-aes-gcm.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/aead-aes-gcm.json
rename to crypto-tink/src/test/resources/keysets/aead-aes-gcm.json
diff --git a/crypto-tink/src/main/resources/keysets/hmac-sha.json b/crypto-tink/src/test/resources/keysets/hmac-sha.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/hmac-sha.json
rename to crypto-tink/src/test/resources/keysets/hmac-sha.json
diff --git a/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-private.json b/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-private.json
new file mode 100644
index 00000000..ba9d1076
--- /dev/null
+++ b/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-private.json
@@ -0,0 +1 @@
+{"encryptedKeyset":"AQICAHjXd7WP9NB78zMSpXCiIaQEPB/K2Ud3VinJdPgxys8yuQEsHuHirJFAlSA97EngGNevAAABczCCAW8GCSqGSIb3DQEHBqCCAWAwggFcAgEAMIIBVQYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzHlEQEosgJyOUa7fwCARCAggEm2YA+KQgvMvKDPaXW/0wBdujU/kR6O7G0EO079rL55qqTVmeRnMZN4vInQYtDVPdX9wXpASTnmDR5YBK5KAC6rOhWHBqmnbNxYr+HIuQfwNmuwcBMDHh9OEXQCxrufOrEXj/MkB9NeTlWNqmIIZmDcRsx4ry7CH4jXciUhkSl4S7oFNT1BrFo9/rKSYxUeGlnKJ5WmRiTwS+BOBZyHJpQ2rVMCbwdO+8DGU69wOInO2a6q2xG+m+5nbujNKreZTi4ovxqN0FghOvxXshY8CgmUJ6cSwupn8LFVsKIu3tEEjyqfSedd7by6DqALexPQp4dHBgIt374FjIKla1Lps9q6BfzCWaQ3TCdjUtv3K09Wz+Y2JwpsO44nLfd9mN+zHMRAdWAXjx8","keysetInfo":{"primaryKeyId":1816387889,"keyInfo":[{"typeUrl":"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey","status":"ENABLED","keyId":1816387889,"outputPrefixType":"TINK"}]}}
diff --git a/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-public.json b/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-public.json
new file mode 100644
index 00000000..26bbbb4d
--- /dev/null
+++ b/crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-public.json
@@ -0,0 +1 @@
+{"primaryKeyId":1816387889,"key":[{"keyData":{"typeUrl":"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey","value":"EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogHp9oy6ikN+tZ7XEvCgXYHzfM5r5Lre+o8RrRYHocYy4iIQC9JUU69dvUdZAXR2ycmF2lE/E0Mkwq39vACd22tqwGiA==","keyMaterialType":"ASYMMETRIC_PUBLIC"},"status":"ENABLED","keyId":1816387889,"outputPrefixType":"TINK"}]}
diff --git a/crypto-tink/src/main/resources/keysets/hybrid-ecies-private.json b/crypto-tink/src/test/resources/keysets/hybrid-ecies-private.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/hybrid-ecies-private.json
rename to crypto-tink/src/test/resources/keysets/hybrid-ecies-private.json
diff --git a/crypto-tink/src/main/resources/keysets/hybrid-ecies-public.json b/crypto-tink/src/test/resources/keysets/hybrid-ecies-public.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/hybrid-ecies-public.json
rename to crypto-tink/src/test/resources/keysets/hybrid-ecies-public.json
diff --git a/crypto-tink/src/main/resources/keysets/signature-ecdsa-private.json b/crypto-tink/src/test/resources/keysets/signature-ecdsa-private.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/signature-ecdsa-private.json
rename to crypto-tink/src/test/resources/keysets/signature-ecdsa-private.json
diff --git a/crypto-tink/src/main/resources/keysets/signature-ecdsa-public.json b/crypto-tink/src/test/resources/keysets/signature-ecdsa-public.json
similarity index 100%
rename from crypto-tink/src/main/resources/keysets/signature-ecdsa-public.json
rename to crypto-tink/src/test/resources/keysets/signature-ecdsa-public.json
diff --git a/csp-spring-security/pom.xml b/csp-spring-security/pom.xml
index 7b87f38d..c378a7ac 100644
--- a/csp-spring-security/pom.xml
+++ b/csp-spring-security/pom.xml
@@ -5,7 +5,7 @@
de.dominikschadow.javasecurity
javasecurity
- 3.1.1
+ 4.0.0
4.0.0
csp-spring-security
@@ -37,20 +37,25 @@
org.webjars
webjars-locator-core
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
- ${project.artifactId}
spring-boot:run
org.springframework.boot
spring-boot-maven-plugin
-
- com.google.cloud.tools
- jib-maven-plugin
-
\ No newline at end of file
diff --git a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
index 83304fe1..25d24b82 100644
--- a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
+++ b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,6 +19,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
/**
* Starter class for the Spring Boot application.
@@ -26,8 +27,9 @@
* @author Dominik Schadow
*/
@SpringBootApplication
+@EnableWebSecurity
public class Application {
- public static void main(String[] args) {
+ static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
diff --git a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/config/WebSecurityConfig.java b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
similarity index 54%
rename from csp-spring-security/src/main/java/de/dominikschadow/javasecurity/config/WebSecurityConfig.java
rename to csp-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
index c74169c4..5b810947 100644
--- a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/config/WebSecurityConfig.java
+++ b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2025 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,25 +15,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.config;
+package de.dominikschadow.javasecurity;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.SecurityFilterChain;
/**
* Spring Security configuration.
*
* @author Dominik Schadow
*/
-@EnableWebSecurity
-public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
+@Configuration
+public class SecurityConfig {
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
- .headers()
- .contentSecurityPolicy("default-src 'self'");
+ .headers(headers -> headers
+ .contentSecurityPolicy(csp -> csp
+ .policyDirectives("default-src 'self'"))
+ );
// @formatter:on
+
+ return http.build();
}
}
diff --git a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/Greeting.java b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/Greeting.java
index 6b777765..915f27c7 100644
--- a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/Greeting.java
+++ b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/Greeting.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,14 +17,5 @@
*/
package de.dominikschadow.javasecurity.greetings;
-public class Greeting {
- private String name;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
+public record Greeting(String name) {
}
diff --git a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/GreetingController.java b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/GreetingController.java
index b8766eaa..9d08f1b0 100644
--- a/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/GreetingController.java
+++ b/csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/GreetingController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,7 +32,7 @@
public class GreetingController {
@GetMapping("/")
public String home(Model model) {
- model.addAttribute("greeting", new Greeting());
+ model.addAttribute("greeting", new Greeting(""));
return "index";
}
diff --git a/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java b/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java
new file mode 100644
index 00000000..31f24449
--- /dev/null
+++ b/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class ApplicationTest {
+ @Test
+ public void contextLoads() {
+ }
+}
\ No newline at end of file
diff --git a/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/greetings/GreetingControllerTest.java b/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/greetings/GreetingControllerTest.java
new file mode 100644
index 00000000..8361ce6d
--- /dev/null
+++ b/csp-spring-security/src/test/java/de/dominikschadow/javasecurity/greetings/GreetingControllerTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2026 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity.greetings;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.hamcrest.Matchers.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+@WebMvcTest(controllers = GreetingController.class)
+class GreetingControllerTest {
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ @WithMockUser
+ void home_returnsIndexView() throws Exception {
+ mockMvc.perform(get("/"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("index"))
+ .andExpect(model().attributeExists("greeting"))
+ .andExpect(model().attribute("greeting", instanceOf(Greeting.class)));
+ }
+
+ @Test
+ @WithMockUser
+ void greeting_returnsResultView() throws Exception {
+ mockMvc.perform(post("/greeting")
+ .with(csrf())
+ .param("name", "TestUser"))
+ .andExpect(status().isOk())
+ .andExpect(view().name("result"))
+ .andExpect(model().attributeExists("result"))
+ .andExpect(model().attribute("result", instanceOf(Greeting.class)));
+ }
+
+ @Test
+ void home_unauthenticated_returnsUnauthorized() throws Exception {
+ mockMvc.perform(get("/"))
+ .andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void greeting_unauthenticated_returnsUnauthorized() throws Exception {
+ mockMvc.perform(post("/greeting")
+ .with(csrf())
+ .param("name", "TestUser"))
+ .andExpect(status().isUnauthorized());
+ }
+}
diff --git a/csrf-spring-security/pom.xml b/csrf-spring-security/pom.xml
index 0967c6b2..6fc49a22 100644
--- a/csrf-spring-security/pom.xml
+++ b/csrf-spring-security/pom.xml
@@ -5,7 +5,7 @@
de.dominikschadow.javasecurity
javasecurity
- 3.1.1
+ 4.0.0
4.0.0
csrf-spring-security
@@ -51,17 +51,12 @@
- ${project.artifactId}
spring-boot:run
org.springframework.boot
spring-boot-maven-plugin
-
- com.google.cloud.tools
- jib-maven-plugin
-
\ No newline at end of file
diff --git a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
index 42b7c00f..25d24b82 100644
--- a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
+++ b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,7 +29,7 @@
@SpringBootApplication
@EnableWebSecurity
public class Application {
- public static void main(String[] args) {
+ static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
diff --git a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/config/WebSecurityConfig.java b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
similarity index 59%
rename from csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/config/WebSecurityConfig.java
rename to csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
index 08b36493..6e6f7dd6 100644
--- a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/config/WebSecurityConfig.java
+++ b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2026 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,11 +15,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.config;
+package de.dominikschadow.javasecurity;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.SecurityFilterChain;
/**
* Simple Spring Security configuration. Deactivates authentication and automatically protects from CSRF attacks with an
@@ -27,10 +28,12 @@
*
* @author Dominik Schadow
*/
-@EnableWebSecurity
-public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.httpBasic().disable();
+@Configuration
+public class SecurityConfig {
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
+
+ return http.build();
}
}
diff --git a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/home/IndexController.java b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/home/IndexController.java
similarity index 83%
rename from csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/home/IndexController.java
rename to csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/home/IndexController.java
index 23bca64f..ed71a66a 100644
--- a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/home/IndexController.java
+++ b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/home/IndexController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,9 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.home;
+package de.dominikschadow.javasecurity.home;
-import de.dominikschadow.javasecurity.csrf.orders.Order;
+import de.dominikschadow.javasecurity.orders.Order;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -35,7 +35,7 @@
public class IndexController {
@ModelAttribute("order")
public Order order() {
- return new Order();
+ return new Order("");
}
@GetMapping
diff --git a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/Order.java b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/Order.java
similarity index 64%
rename from csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/Order.java
rename to csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/Order.java
index 0498d011..52498fa1 100644
--- a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/Order.java
+++ b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/Order.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,21 +15,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.orders;
+package de.dominikschadow.javasecurity.orders;
/**
* Order entity.
*
* @author Dominik Schadow
*/
-public class Order {
- private String item;
-
- public String getItem() {
- return item;
- }
-
- public void setItem(String item) {
- this.item = item;
- }
+public record Order (String item) {
}
diff --git a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/OrderController.java b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/OrderController.java
similarity index 87%
rename from csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/OrderController.java
rename to csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/OrderController.java
index 759ff244..d3154136 100644
--- a/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/csrf/orders/OrderController.java
+++ b/csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/OrderController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.orders;
+package de.dominikschadow.javasecurity.orders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
diff --git a/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java
new file mode 100644
index 00000000..31f24449
--- /dev/null
+++ b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
+ *
+ * This file is part of the Java Security project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.dominikschadow.javasecurity;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class ApplicationTest {
+ @Test
+ public void contextLoads() {
+ }
+}
\ No newline at end of file
diff --git a/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/home/IndexControllerTest.java b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/home/IndexControllerTest.java
similarity index 81%
rename from csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/home/IndexControllerTest.java
rename to csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/home/IndexControllerTest.java
index 5abb4167..db78370f 100644
--- a/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/home/IndexControllerTest.java
+++ b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/home/IndexControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,26 +15,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.home;
+package de.dominikschadow.javasecurity.home;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
-@RunWith(SpringRunner.class)
@WebMvcTest(IndexController.class)
public class IndexControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
+ @WithMockUser
public void testHomePage() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
diff --git a/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/orders/OrderControllerTest.java b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/orders/OrderControllerTest.java
similarity index 86%
rename from csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/orders/OrderControllerTest.java
rename to csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/orders/OrderControllerTest.java
index dacbb4da..dfd7727c 100644
--- a/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/csrf/orders/OrderControllerTest.java
+++ b/csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/orders/OrderControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 Dominik Schadow, dominikschadow@gmail.com
+ * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,14 +15,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package de.dominikschadow.javasecurity.csrf.orders;
+package de.dominikschadow.javasecurity.orders;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.containsString;
@@ -30,13 +29,13 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
-@RunWith(SpringRunner.class)
@WebMvcTest(OrderController.class)
public class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
+ @WithMockUser
public void testWithCsrfToken() throws Exception {
mockMvc.perform(post("/order").with(csrf())
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
@@ -47,6 +46,7 @@ public void testWithCsrfToken() throws Exception {
}
@Test
+ @WithMockUser
public void testWithoutCsrfToken() throws Exception {
mockMvc.perform(post("/order")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
diff --git a/csrf/pom.xml b/csrf/pom.xml
index 05511281..564b4211 100644
--- a/csrf/pom.xml
+++ b/csrf/pom.xml
@@ -5,7 +5,7 @@
de.dominikschadow.javasecurity
javasecurity
- 3.1.1
+ 4.0.0
4.0.0
csrf
@@ -22,38 +22,28 @@
javax.servlet-api
- org.apache.logging.log4j
- log4j-api
-
-
- org.apache.logging.log4j
- log4j-core
+ com.google.guava
+ guava
- org.apache.logging.log4j
- log4j-slf4j-impl
+ org.junit.jupiter
+ junit-jupiter
+ test
- com.google.guava
- guava
+ org.mockito
+ mockito-core
+ test
- ${project.artifactId}
tomcat7:run-war
org.apache.tomcat.maven
tomcat7-maven-plugin
-
- com.google.cloud.tools
- jib-maven-plugin
-
- true
-
-
\ No newline at end of file
diff --git a/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/CSRFTokenHandler.java b/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/CSRFTokenHandler.java
index 16748039..472caac6 100644
--- a/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/CSRFTokenHandler.java
+++ b/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/CSRFTokenHandler.java
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,8 +31,7 @@
* Calculates a random token for each user and stores it in the session. Compares the token of incoming requests with
* the one stored in the session.
*
- * This implementation is based on the OWASP Enterprise Security API (ESAPI), available at
- * https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
+ * This implementation is based on the OWASP Enterprise Security API (ESAPI).
*
* @author Dominik Schadow
*/
diff --git a/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/OrderServlet.java b/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/OrderServlet.java
index 474033c1..ad41b9ef 100644
--- a/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/OrderServlet.java
+++ b/csrf/src/main/java/de/dominikschadow/javasecurity/csrf/OrderServlet.java
@@ -7,7 +7,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,9 +17,6 @@
*/
package de.dominikschadow.javasecurity.csrf;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@@ -27,6 +24,7 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.Serial;
/**
* CSRF secured order servlet for POST requests. Processes the order and returns the result.
@@ -35,15 +33,16 @@
*/
@WebServlet(name = "OrderServlet", urlPatterns = {"/OrderServlet"})
public class OrderServlet extends HttpServlet {
+ @Serial
private static final long serialVersionUID = 168055850789919449L;
- private static final Logger log = LoggerFactory.getLogger(OrderServlet.class);
+ private static final System.Logger LOG = System.getLogger(OrderServlet.class.getName());
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
- log.info("Processing order servlet...");
+ LOG.log(System.Logger.Level.INFO, "Processing order servlet...");
if (!CSRFTokenHandler.isValid(request)) {
- log.info("Order servlet: CSRF token is invalid");
+ LOG.log(System.Logger.Level.INFO, "Order servlet: CSRF token is invalid");
response.setStatus(401);
try (PrintWriter out = response.getWriter()) {
@@ -60,13 +59,13 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
out.println("