diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java new file mode 100644 index 0000000000..cc0da187b9 --- /dev/null +++ b/libraries-security/src/main/java/com/baeldung/digitalsignature/DigitalSignatureUtils.java @@ -0,0 +1,86 @@ +package com.baeldung.digitalsignature; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; + +import javax.crypto.Cipher; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.*; +import java.security.cert.Certificate; +import java.util.Arrays; + +public class DigitalSignatureUtils { + + public static PrivateKey getPrivateKey(String file, char[] password, String storeType, String alias) throws Exception { + KeyStore keyStore = KeyStore.getInstance(storeType); + keyStore.load(new FileInputStream(file), password); + return (PrivateKey) keyStore.getKey(alias, password); + } + + public static PublicKey getPublicKey(String file, char[] password, String storeType, String alias) throws Exception { + KeyStore keyStore = KeyStore.getInstance(storeType); + keyStore.load(new FileInputStream(file), password); + Certificate certificate = keyStore.getCertificate(alias); + return certificate.getPublicKey(); + } + + public static byte[] sign(byte[] message, String signingAlgorithm, PrivateKey signingKey) throws SecurityException { + try { + Signature signature = Signature.getInstance(signingAlgorithm); + signature.initSign(signingKey); + signature.update(message); + return signature.sign(); + } catch (GeneralSecurityException exp) { + throw new SecurityException("Error during signature generation", exp); + } + } + + public static boolean verify(byte[] messageBytes, String signingAlgorithm, PublicKey publicKey, byte[] signedData) { + try { + Signature signature = Signature.getInstance(signingAlgorithm); + signature.initVerify(publicKey); + signature.update(messageBytes); + return signature.verify(signedData); + } catch (GeneralSecurityException exp) { + throw new SecurityException("Error during verifying", exp); + } + } + + public static byte[] signWithMessageDigestAndCipher(byte[] messageBytes, String hashingAlgorithm, PrivateKey privateKey) { + try { + MessageDigest md = MessageDigest.getInstance(hashingAlgorithm); + byte[] messageHash = md.digest(messageBytes); + DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new DefaultDigestAlgorithmIdentifierFinder(); + AlgorithmIdentifier hashingAlgorithmIdentifier = hashAlgorithmFinder.find(hashingAlgorithm); + DigestInfo digestInfo = new DigestInfo(hashingAlgorithmIdentifier, messageHash); + byte[] hashToEncrypt = digestInfo.getEncoded(); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + return cipher.doFinal(hashToEncrypt); + } catch (GeneralSecurityException | IOException exp) { + throw new SecurityException("Error during signature generation", exp); + } + } + + public static boolean verifyWithMessageDigestAndCipher(byte[] messageBytes, String hashingAlgorithm, PublicKey publicKey, byte[] encryptedMessageHash) { + try { + MessageDigest md = MessageDigest.getInstance(hashingAlgorithm); + byte[] newMessageHash = md.digest(messageBytes); + DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new DefaultDigestAlgorithmIdentifierFinder(); + AlgorithmIdentifier hashingAlgorithmIdentifier = hashAlgorithmFinder.find(hashingAlgorithm); + DigestInfo digestInfo = new DigestInfo(hashingAlgorithmIdentifier, newMessageHash); + byte[] hashToEncrypt = digestInfo.getEncoded(); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + byte[] decryptedMessageHash = cipher.doFinal(encryptedMessageHash); + return Arrays.equals(decryptedMessageHash, hashToEncrypt); + } catch (GeneralSecurityException | IOException exp) { + throw new SecurityException("Error during verifying", exp); + } + } +} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java deleted file mode 100644 index 9f1e5808c3..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/Utils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.digitalsignature; - -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; - -public class Utils { - - private static final String STORE_TYPE = "PKCS12"; - private static final char[] PASSWORD = "changeit".toCharArray(); - private static final String SENDER_KEYSTORE = "sender_keystore.p12"; - private static final String SENDER_ALIAS = "senderKeyPair"; - - public static final String SIGNING_ALGORITHM = "SHA256withRSA"; - - private static final String RECEIVER_KEYSTORE = "receiver_keystore.p12"; - private static final String RECEIVER_ALIAS = "receiverKeyPair"; - - public static PrivateKey getPrivateKey() throws Exception { - KeyStore keyStore = KeyStore.getInstance(STORE_TYPE); - keyStore.load(new FileInputStream(SENDER_KEYSTORE), PASSWORD); - return (PrivateKey) keyStore.getKey(SENDER_ALIAS, PASSWORD); - } - - public static PublicKey getPublicKey() throws Exception { - KeyStore keyStore = KeyStore.getInstance(STORE_TYPE); - keyStore.load(new FileInputStream(RECEIVER_KEYSTORE), PASSWORD); - Certificate certificate = keyStore.getCertificate(RECEIVER_ALIAS); - return certificate.getPublicKey(); - } -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java deleted file mode 100644 index 78d40dd365..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherSigning.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.digitalsignature.level1; - -import com.baeldung.digitalsignature.Utils; - -import javax.crypto.Cipher; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.PrivateKey; - -public class DigitalSignatureWithMessageDigestAndCipherSigning { - - public static void main(String[] args) throws Exception { - - PrivateKey privateKey = Utils.getPrivateKey(); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] messageHash = md.digest(messageBytes); - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - byte[] digitalSignature = cipher.doFinal(messageHash); - - Files.write(Paths.get("target/digital_signature_1"), digitalSignature); - } -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java deleted file mode 100644 index 0b242a44fb..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level1/DigitalSignatureWithMessageDigestAndCipherVerifying.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.digitalsignature.level1; - -import com.baeldung.digitalsignature.Utils; - -import javax.crypto.Cipher; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.PublicKey; -import java.util.Arrays; - -public class DigitalSignatureWithMessageDigestAndCipherVerifying { - - public static void main(String[] args) throws Exception { - - PublicKey publicKey = Utils.getPublicKey(); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] newMessageHash = md.digest(messageBytes); - - byte[] encryptedMessageHash = Files.readAllBytes(Paths.get("target/digital_signature_1")); - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - byte[] decryptedMessageHash = cipher.doFinal(encryptedMessageHash); - - boolean isCorrect = Arrays.equals(decryptedMessageHash, newMessageHash); - System.out.println("Signature " + (isCorrect ? "correct" : "incorrect")); - } - -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java deleted file mode 100644 index afc8fd1045..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureSigning.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.digitalsignature.level2; - -import com.baeldung.digitalsignature.Utils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.PrivateKey; -import java.security.Signature; - -public class DigitalSignatureWithSignatureSigning { - - public static void main(String[] args) throws Exception { - - PrivateKey privateKey = Utils.getPrivateKey(); - - Signature signature = Signature.getInstance(Utils.SIGNING_ALGORITHM); - signature.initSign(privateKey); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - signature.update(messageBytes); - byte[] digitalSignature = signature.sign(); - - Files.write(Paths.get("target/digital_signature_2"), digitalSignature); - } - -} diff --git a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java b/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java deleted file mode 100644 index ee34be989c..0000000000 --- a/libraries-security/src/main/java/com/baeldung/digitalsignature/level2/DigitalSignatureWithSignatureVerifying.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.digitalsignature.level2; - -import com.baeldung.digitalsignature.Utils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.PublicKey; -import java.security.Signature; - -public class DigitalSignatureWithSignatureVerifying { - - public static void main(String[] args) throws Exception { - - PublicKey publicKey = Utils.getPublicKey(); - - byte[] sig = Files.readAllBytes(Paths.get("target/digital_signature_2")); - - Signature signature = Signature.getInstance(Utils.SIGNING_ALGORITHM); - signature.initVerify(publicKey); - - byte[] messageBytes = Files.readAllBytes(Paths.get("src/test/resources/digitalsignature/message.txt")); - - signature.update(messageBytes); - - boolean isCorrect = signature.verify(sig); - System.out.println("Signature " + (isCorrect ? "correct" : "incorrect")); - } -} diff --git a/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java b/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java new file mode 100644 index 0000000000..65058dca52 --- /dev/null +++ b/libraries-security/src/test/java/com/baeldung/digitalsignature/DigitalSignatureUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.digitalsignature; + +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.PrivateKey; +import java.security.PublicKey; + +import static org.junit.Assert.assertTrue; + +public class DigitalSignatureUnitTest { + + String messagePath = "src/test/resources/digitalsignature/message.txt"; + String senderKeyStore = "src/test/resources/digitalsignature/sender_keystore.jks"; + String receiverKeyStore = "src/test/resources/digitalsignature/receiver_keystore.jks"; + String storeType = "JKS"; + String senderAlias = "senderKeyPair"; + String receiverAlias = "receiverKeyPair"; + char[] password = "changeit".toCharArray(); + String signingAlgorithm = "SHA256withRSA"; + String hashingAlgorithm = "SHA-256"; + + @Test + public void givenMessageData_whenSignWithSignatureSigning_thenVerify() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] digitalSignature = DigitalSignatureUtils.sign(messageBytes, signingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verify(messageBytes, signingAlgorithm, publicKey, digitalSignature); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithMessageDigestAndCipher_thenVerify() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] encryptedMessageHash = DigitalSignatureUtils.signWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verifyWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, publicKey, encryptedMessageHash); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithSignatureSigning_thenVerifyWithMessageDigestAndCipher() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] digitalSignature = DigitalSignatureUtils.sign(messageBytes, signingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verifyWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, publicKey, digitalSignature); + + assertTrue(isCorrect); + } + + @Test + public void givenMessageData_whenSignWithMessageDigestAndCipher_thenVerifyWithSignature() throws Exception { + PrivateKey privateKey = DigitalSignatureUtils.getPrivateKey(senderKeyStore, password, storeType, senderAlias); + byte[] messageBytes = Files.readAllBytes(Paths.get(messagePath)); + + byte[] encryptedMessageHash = DigitalSignatureUtils.signWithMessageDigestAndCipher(messageBytes, hashingAlgorithm, privateKey); + + PublicKey publicKey = DigitalSignatureUtils.getPublicKey(receiverKeyStore, password, storeType, receiverAlias); + boolean isCorrect = DigitalSignatureUtils.verify(messageBytes, signingAlgorithm, publicKey, encryptedMessageHash); + + assertTrue(isCorrect); + } + +} diff --git a/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks b/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks new file mode 100644 index 0000000000..184b5b8600 Binary files /dev/null and b/libraries-security/src/test/resources/digitalsignature/receiver_keystore.jks differ diff --git a/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer b/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer new file mode 100644 index 0000000000..98e306bd49 --- /dev/null +++ b/libraries-security/src/test/resources/digitalsignature/sender_certificate.cer @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICxTCCAa2gAwIBAgIEala2gjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhC +YWVsZHVuZzAeFw0yMzAyMTkwNjA5NTdaFw0yNDAyMTkwNjA5NTdaMBMxETAPBgNV +BAMTCEJhZWxkdW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAifku +JnJM3U/x3jWpjpUZeSVpbdUTirdB2Ta0mwXXaZmGwtrwZvS8pXdmegFUMnYB92RJ +98j4iYjivXElwwjFIc4YRa7hQicqMfa1H3BUtDwIpqlXM1jISr5TYAE/t/wpkrVH +A1QPNv7Fb07ormWKwktTMWyUoLo0chInv07Ip3m6F3X3O0jZFjE8N+7Fnv9oMdsN +sAAq+f/7jJSdzo/vzHebR0XUxB1YP6sTWRH6nlNw2h+0kTMf33CkXyDG1Y1qsBRK +MoOia10bi21B7Yd+lJo0ZnT1JNei4eEdPYxWQa43JMY6PnpJI9d5WKvye2NewXvO +pLap8WR3dgX6n6bUtwIDAQABoyEwHzAdBgNVHQ4EFgQUQVqwZ6AlNlPeeUOmw89A +u86n09gwDQYJKoZIhvcNAQELBQADggEBAGoV1ECn0h0IYEoQ8pxF1zbXnt35XEO4 +ZPbq8cPuYj92X3c9TWeHJIHGO3ZYMS7eaBRL5HhCTqG3YjAsm6+bea9cBffeZwG3 +EAl0u7e8CI6Ri6065Og4s0c7Y3ZJIJ4i6c5bVqPep8Oj3IFUUAwxz+95c2LX9cfL +hxzH8N2RzWvGoJBrmWNeQUuKVlMBVBX6n/EcWmCS/VYORw0mwJ9vdmPhGU3hGggG +S0rAVnQlIdvzWsaNllNWf6ETrrHceCflKsOuettjODZUAqiZ9aEd9WMDGHLtZw94 +zONYICWg2o3Sx9/F26wHdjHn+gxB2Z45Dvd0rBMuCHqwJELxyvofc1E= +-----END CERTIFICATE----- diff --git a/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks b/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks new file mode 100644 index 0000000000..1ad4db895b Binary files /dev/null and b/libraries-security/src/test/resources/digitalsignature/sender_keystore.jks differ