Digital
signature is used to confirm the identity of the digital document. By using
digital signature, recipient makes sure that the document is authenticated
(Sent by correct person). Digital signature gives the receiver reason to
believe the claimed sender sent the message.
A typical
digital signature process comprises of three algorithms.
1. Key
Generation algorithm: Generates
public and private key pair.
2. Signature
algorithm: Takes given
message and private key as input and generates signature.
3. Signature
verifying algorithm: Takes
received message, public key and signature as input and verifies the message
authenticity.
In this
post, I am going to explain, how to generate digital signature and verify it. In
brief following are the steps.
1.
Sender
generates Public and private key pair.
2.
Sender
generates digital signature for given data using private key generated in step
1.
3.
Sender
sends the message, signature, and public key to receiver.
4.
Receiver
receives the data, signature, and public key. Verifies the signature using
public key and data sent by sender
Section 1
explains, how to generate digital signature and section 2 explains how to
verify digital signature. Final section gives complete program to generate and
verify digital signature.
Generate Digital signature
Step 1: To create digital signature, you
need a private key, and to verify digital signature, you need a public key. So First we need to generate key pair
(public key, private key). A key pair is generated by using the
KeyPairGenerator class. Go through following post, to get detailed information
on how to generate key pair.
public static KeyPair getKeyPair(String algorithm) throws NoSuchAlgorithmException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); return keyPairGenerator.generateKeyPair(); }
Above
snippet generates KeyPair specific to given algorithm.
Step 2: You can create digital signature using Signature class. Signing data
using Signature class is a four-step process.
a. Get Signature instance:
You can get
the Signature instance using getInstance method of Signature class. Signature
class provides 3 variants of getInstance method to get an instance of Signature
class.
getInstance(String algorithm)
Returns a
Signature object that implements the specified signature algorithm.
getInstance(String algorithm, Provider provider)
getInstance(String algorithm, String provider)
Returns a
Signature object that implements the specified signature algorithm using
specified provider.
Following
are the digital signature algorithms provided by Java.
Algorithm
|
Description
|
NONEwithRSA
|
The RSA
signature algorithm, which does not use a digesting algorithm before
performing the RSA operation.
|
MD2withRSA
MD5withRSA
|
Uses the
MD2/MD5 digest algorithm and RSA to create and verify RSA digital signatures
|
SHA1withRSA
SHA256withRSA
SHA384withRSA
SHA512withRSA
|
USE
SHA1/SHA256/SHA384/SHA512 digest algorithm and RSA to create and verify RSA
digital signatures.
|
NONEwithDSA
|
Implementation
of digital signature algorithm defined in http://csrc.nist.gov/publications/PubsFIPS.html.
|
SHA1withDSA
|
Uses the
SHA-1 digest algorithm and DSA to create and verify DSA digital signatures
|
NONEwithECDSA
SHA1withECDSA
SHA256withECDSA
SHA384withECDSA
SHA512withECDSA
(ECDSA)
|
Uses the
SHA digest algorithm and ECDSA to create and verify ECDSA digital signatures.
|
b.Initialize signature object
signature.initSign(privateKey);
c. Supply the Signature Object the Data to Be
Signed
/* Supply the Signature Object the Data to Be Signed */ FileInputStream fis = new FileInputStream(fileName); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = bufin.read(buffer)) >= 0) { signature.update(buffer, 0, len); } bufin.close();
d. Generate signature
byte[]
finalSig = signature.sign();
Step 3: Save the signature and public key in files.
public static void saveKey(Key key, String fileName) { byte[] keyBytes = key.getEncoded(); File keyFile = new File(fileName); FileOutputStream fOutStream = null; try { fOutStream = new FileOutputStream(keyFile); fOutStream.write(keyBytes); } catch (Exception e) { e.printStackTrace(); } finally { if (fOutStream != null) { try { fOutStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void saveSignature(String fileName, byte[] signature) throws Exception { FileOutputStream sigfos = new FileOutputStream(fileName); sigfos.write(signature); sigfos.close(); }
Verify digital signature
To verify
the signature we need three components.
a. Data (File contents which are
signed)
b. Signature
c. Public key corresponding to the
private key used to sign the data
Step 1: Get the public key instance from the key stored in
a file.
public static byte[] readKeyFromFile(String fileName) throws Exception { FileInputStream keyfis = new FileInputStream(fileName); byte[] key = new byte[keyfis.available()]; keyfis.read(key); keyfis.close(); return key; }
Step 2: Read the signature from file.
Step 3: Verify the signature.
a. Initialize
the Signature Object for Verification
Signature verifySignature =
Signature.getInstance(sigAlgorithm);
b. Initialize
signature object with the public key.
verifySignature.initVerify(pubKey);
c. Supply
the Signature Object With the Data to be Verified.
public static void feedData(Signature signature, String fileName) throws Exception { /* Supply the Signature Object the Data to Be Signed */ FileInputStream fis = new FileInputStream(fileName); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = bufin.read(buffer)) >= 0) { signature.update(buffer, 0, len); } bufin.close(); }
d.
Verify the signature
verifySignature.verify(receivedSignature);
Complete Application
import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.PrivateKey; import java.security.Signature; public class SignatureUtil { /** * Generates signature by taking file, PrivateKey and algorithm as input. * * @param fileName * : Generate signature for this file. * @param privateKey * @param algorithm * @return * @throws Exception */ public static byte[] getSignature(String fileName, PrivateKey privateKey, String algorithm) throws Exception { /* Get instance of Signature object */ Signature signature = Signature.getInstance(algorithm); /* Initialize Signature object */ signature.initSign(privateKey); /* Feed data */ feedData(signature, fileName); /* Generate signature */ byte[] finalSig = signature.sign(); return finalSig; } /** * Save signature to a file * * @param fileName * : Signature saved here * @param signature * @throws Exception */ public static void saveSignature(String fileName, byte[] signature) throws Exception { FileOutputStream sigfos = new FileOutputStream(fileName); sigfos.write(signature); sigfos.close(); } /** * Read signature from a file and convert it into byte array. * * @param fileName * : contains signature information * @return signature as byte array * @throws Exception */ public static byte[] readSignatureFromFile(String fileName) throws Exception { return PublicKeyUtil.readKeyFromFile(fileName); } /** * Feed data to Signature instance * * @param signature * @param fileName * @throws Exception */ public static void feedData(Signature signature, String fileName) throws Exception { /* Supply the Signature Object the Data to Be Signed */ FileInputStream fis = new FileInputStream(fileName); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = bufin.read(buffer)) >= 0) { signature.update(buffer, 0, len); } bufin.close(); } }
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class PublicKeyUtil { /** * Generates KeyPair specific to given algorithm * * @param algorithm * @return * @throws NoSuchAlgorithmException */ public static KeyPair getKeyPair(String algorithm) throws NoSuchAlgorithmException { KeyPairGenerator keyPairGenerator = KeyPairGenerator .getInstance(algorithm); return keyPairGenerator.generateKeyPair(); } /** * Return PublicKey from given KeyPair * * @param keyPair * @return */ public static PublicKey getPublicKey(KeyPair keyPair) { return keyPair.getPublic(); } /** * Return PrivateKey from given KeyPair * * @param keyPair * @return */ public static PrivateKey getPrivateKey(KeyPair keyPair) { return keyPair.getPrivate(); } /** * Convert key to string. * * @param key * * @return String representation of key */ public static String keyToString(Key key) { /* Get key in encoding format */ byte encoded[] = key.getEncoded(); /* * Encodes the specified byte array into a String using Base64 encoding * scheme */ String encodedKey = Base64.getEncoder().encodeToString(encoded); return encodedKey; } /** * Save key to a file * * @param key * : key to save into file * @param fileName * : File name to store */ public static void saveKey(Key key, String fileName) { byte[] keyBytes = key.getEncoded(); File keyFile = new File(fileName); FileOutputStream fOutStream = null; try { fOutStream = new FileOutputStream(keyFile); fOutStream.write(keyBytes); } catch (Exception e) { e.printStackTrace(); } finally { if (fOutStream != null) { try { fOutStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * Returns the key stored in a file. * * @param fileName * @return * @throws Exception */ public static byte[] readKeyFromFile(String fileName) throws Exception { FileInputStream keyfis = new FileInputStream(fileName); byte[] key = new byte[keyfis.available()]; keyfis.read(key); keyfis.close(); return key; } /** * Generates public key from encoded byte array. * * @param encoded * @param algorithm * @return * @throws Exception */ public static PublicKey convertArrayToPubKey(byte encoded[], String algorithm) throws Exception { X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encoded); KeyFactory keyFactory = KeyFactory.getInstance(algorithm); PublicKey pubKey = keyFactory.generatePublic(pubKeySpec); return pubKey; } /** * Generates private key from encoded byte array. * * @param encoded * @param algorithm * @return * @throws Exception */ public static PrivateKey convertArrayToPriKey(byte encoded[], String algorithm) throws Exception { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); KeyFactory keyFactory = KeyFactory.getInstance(algorithm); PrivateKey priKey = keyFactory.generatePrivate(keySpec); return priKey; } }
import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import com.sample.PublicKeyUtil; import com.sample.SignatureUtil; public class TestDigitalSignature { public static void main(String args[]) throws Exception { String file = "/Users/harikrishna_gurram/emp.txt"; /* Public key stored in this file */ String publicKeyFile = "/Users/harikrishna_gurram/publicKey.txt"; /* Signature of given file stored here */ String signatureFile = "/Users/harikrishna_gurram/siganture.txt"; /* Signature algorithm to get Signature instance */ String sigAlgorithm = "SHA1withDSA"; /* generate public and private keys */ KeyPair keyPair = PublicKeyUtil.getKeyPair("DSA"); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); /* Generate signature for given file */ byte signature[] = SignatureUtil.getSignature(file, privateKey, sigAlgorithm); /* Save public key */ PublicKeyUtil.saveKey(publicKey, publicKeyFile); /* Save signature */ SignatureUtil.saveSignature(signatureFile, signature); // Verify Signature /* Read public key from file */ byte[] pubKeyBytes = PublicKeyUtil.readKeyFromFile(publicKeyFile); /* Convert publick key bytes into PublicKey object */ PublicKey pubKey = PublicKeyUtil.convertArrayToPubKey(pubKeyBytes, "DSA"); /* Read signature from file */ byte[] receivedSignature = SignatureUtil .readSignatureFromFile(signatureFile); /* Verify signature */ Signature verifySignature = Signature.getInstance(sigAlgorithm); /* initialize signature object */ verifySignature.initVerify(pubKey); /* Feed data */ SignatureUtil.feedData(verifySignature, file); /* Verify signature */ boolean isAuthenticated = verifySignature.verify(receivedSignature); if (isAuthenticated) { System.out.println("Data is authenticated"); } else { System.out.println("Data is not from expected sender"); } } }
Referred Articles
No comments:
Post a Comment