Bael 5190: Verify Digital Signatures in Java article (#13439)

* #BAEL-5190: add keystore and certificate files

* #BAEL-5190: add keystore address

* #BAEL-5190: update hashing

* #BAEL-5190: delete main classes

* #BAEL-5190: move keystore files to test directory

* #BAEL-5190: rename to DigitalSignatureUtils

* #BAEL-5190: main source code

* #BAEL-5190: main test source

* #BAEL-5190: update for testing

* #BAEL-5190: update keystore type

* #BAEL-5190: remove p12 keystores

* #BAEL-5190: add jks keystores

---------

Co-authored-by: h_sharifi <h_sharifi@modernisc.com>
This commit is contained in:
Hamid Reza Sharifi 2023-02-19 17:53:38 +03:30 committed by GitHub
parent 6abe6473da
commit 17c26f91c9
10 changed files with 179 additions and 149 deletions

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -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-----