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:
parent
6abe6473da
commit
17c26f91c9
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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-----
|
Binary file not shown.
Loading…
Reference in New Issue