Reputation: 4207
I am totally new to security and signature verification and so far I couldn't find a place which explained the basics of signature verification. I need to verify the signature of a file by obtaining the public key from the appropriate certificate available from certificate store. the tutorial in Java (https://docs.oracle.com/javase/tutorial/security/apisign/versig.html) doesn't teach how to obtain a certificate from the trusted certificate store and verify using that. I went through Bouncy castle WIKI http://www.bouncycastle.org/wiki/display/JA1/BC+Version+2+APIs but its not really explanatory for a beginner. How do I do this? Given a signed file, how can I check for its public key from the certificate store and verify if its the right person who has sent the file? Please advice.
Upvotes: 0
Views: 8296
Reputation: 1141
Because you did not provide what build management you use, I assume it will be Maven.
First, include BouncyCastle in your dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.53</version>
</dependency>
After that, you need to make a util class that you will be using for sign or verify the certificate. Something like this:
package your.pack.location;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* Author: harunalfat
*/
public class SignatureUtils {
private static final Logger log = LogManager.getLogger(SignatureUtils.class);
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privateKey);
signature.update(data);
return Base64.toBase64String(signature.sign());
}
public static boolean verify(String plainText, String signString, PublicKey publicKey) throws Exception{
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initVerify(publicKey);
signature.update(data);
byte[] signByte = Base64.decode(signString);
return signature.verify(signByte);
}
private static PemObject getPemObjectFromResource(String fileLocation) throws IOException {
Resource resource = new ClassPathResource(fileLocation);
InputStream is = resource.getInputStream();
PemObject pemObject = new PemReader(new InputStreamReader( is )).readPemObject();
return pemObject;
}
private static X509EncodedKeySpec getPubKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
return keySpec;
}
private static PKCS8EncodedKeySpec getPriKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
return keySpec;
}
public static PublicKey getPublicKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPubKeySpec(fileLocation);
return kf.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPriKeySpec(fileLocation);
return kf.generatePrivate(keySpec);
}
}
And then you will use it like this
package your.another.pack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import static org.junit.Assert.assertTrue;
/**
* Author: harunalfat
*/
public class SignatureUtilsTest {
private static final Logger log = LogManager.getLogger(SignatureUtilsTest.class);
private static final String PLAIN = "attack at dawn";
@Test
public void testSignAndVerify() throws Exception {
Security.addProvider(new BouncyCastleProvider()); // <-- IMPORTANT!!! This will add BouncyCastle as provider in Java Security
PrivateKey privateKey = SignatureUtils.getPrivateKey("key/private2.pem"); // This is located on src/main/resources/key/private2.pem
PublicKey publicKey = SignatureUtils.getPublicKey("key/public2.pem"); // This is located on src/main/resources/key/public2.pem
// In this example, I use junit test, so it will be on src/test/resources/...
log.info("Private Key : "+Base64.encodeBase64String(privateKey.getEncoded()));
log.info("Public Key : "+Base64.encodeBase64String(publicKey.getEncoded()));
String sign = SignatureUtils.sign(PLAIN, privateKey);
log.info("Plain String : "+PLAIN);
log.info("Sign : "+sign);
boolean result = SignatureUtils.verify(PLAIN,sign, publicKey);
log.info("Result : "+result);
assertTrue(result);
}
}
Of course, you can change the Signature instance with another Algorithm. In my case I use "SHA1WithRSA"
, but you get the point right?
With this, someone will encrypt their data using their private key, and send it to you. After that, you will verify the data using the public key they give.
In example, Bob send to you message about money amount he sent to you ($5000
), and sign it using their private key, become encrypted. When the data arrived to you, you know Bob supposed to send $5000, then you verify the encrypted data with text $5000
and public key Bob share, but is it really $5000
OR does it comes from Bob?
If the data has been changed, OR when someday you ask for some Money to Bob, but the message tapped by someone else and s/he send you the amount message with private key other than Bob's, you will know.
Feel free to ask :)
Upvotes: 3