The basic idea in the use of digital signatures is as follows.
- You "sign" the document or code using one of your private keys, which you can generate by using
keytool
or security API methods. That is, you generate a digital signature for the document or code, using thejarsigner
tool or Security API methods. - You send your signed document to your recipient.
- You also supply your recipient with your public key. This public key corresponds to the private key you originally used to generate the signature.
- Your recipient uses your public key to verify that your document came from you and was not modified before it reached him/her.
Generating and Verifying Signatures
This lesson walks you through the steps necessary to use the JDK Security API to generate a digital signature for data and to verify that a signature is authentic. This lesson is meant for developers who wish to incorporate security functionality into their programs, including cryptography services.
This lesson demonstrates the use of the JDK Security API with respect to signing documents. The lesson shows what one program, executed by the person who has the original document, would do to generate keys, generate a digital signature for the document using the private key, and export the public key and the signature to files.
Then it shows an example of another program, executed by the receiver of the document, signature, and public key. It shows how the program could import the public key and verify the authenticity of the signature. The lesson also discusses and demonstrates possible alternative approaches and methods of supplying and importing keys, including in certificates.
For further information about the concepts and terminology (digital signatures, certificates, keystores), see the API and Tools Use for Secure Code and File Exchanges lesson.
In this lesson you create two basic applications, one for the digital signature generation and the other for the verification. This is followed by a discussion and demonstration of potential enhancements. The lesson contains three sections.
- Generating a Digital Signature shows using the API to generate keys and a digital signature for data using the private key and to export the public key and the signature to files. The application gets the data file name from the command line.
- Verifying a Digital Signature shows using the API to import a public key and a signature that is alleged to be the signature of a specified data file and to verify the authenticity of the signature. The data, public key, and signature file names are specified on the command line.
- Weaknesses and Alternatives discusses potential weaknesses of the approach used by the basic programs. It then presents and demonstrates possible alternative approaches and methods of supplying and importing keys, including the use of files containing encoded key bytes and the use of certificates containing public keys.
Generating a Digital Signature
- The
GenSig
program you are about to create will use the JDK Security API to generate keys and a digital signature for data using the private key and to export the public key and the signature to files. The application gets the data file name from the command line.
The following steps create theGenSig
sample program.
- Prepare Initial Program Structure Create a text file named
GenSig.java
. Type in the initial program structure (import statements, class name,main
method, and so on).
- Generate Public and Private Keys Generate a key pair (public key and private key). The private key is needed for signing the data. The public key will be used by the
VerSig
program for verifying the signature.
- Sign the Data Get a
Signature
object and initialize it for signing. Supply it with the data to be signed, and generate the signature.
- Save the Signature and the Public Key in Files Save the signature bytes in one file and the public key bytes in another.
- Compile and Run the Program
Prepare Initial Program Structure
Here's the basic structure of theGenSig
program. Place it in a file calledGenSig.java
.
import java.io.*; import java.security.*; class GenSig { public static void main(String[] args) { /* Generate a DSA signature */ if (args.length != 1) { System.out.println("Usage: GenSig nameOfFileToSign"); } else try { // the rest of the code goes here } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } }
Notes:
- The methods for signing data are in the
java.security
package, so the program imports everything from that package. The program also imports thejava.io
package, which contains the methods needed to input the file data to be signed.- A single argument is expected, specifying the data file to be signed.
- The code written in subsequent steps will go between the
try
and thecatch
blocks.
Generate Public and Private Keys
In order to be able to create a digital signature, you need a private key. (Its corresponding public key will be needed in order to verify the authenticity of the signature.) In some cases the key pair (private key and corresponding public key) are already available in files. In that case the program can import and use the private key for signing, as shown in Weaknesses and Alternatives.
In other cases the program needs to generate the key pair. A key pair is generated by using the
KeyPairGenerator
class. In this example you will generate a public/private key pair for the Digital Signature Algorithm (DSA). You will generate keys with a 1024-bit length.
Generating a key pair requires several steps:
Create a Key Pair Generator
The first step is to get a key-pair generator object for generating keys for the DSA signature algorithm.Initialize the Key-Pair Generator
As with all engine classes, the way to get aKeyPairGenerator
object for a particular type of algorithm is to call thegetInstance
static factory method on theKeyPairGenerator
class. This method has two forms, both of which hava aString algorithm
first argument; one form also has aString provider
second argument.
A caller may thus optionally specify the name of a provider, which will guarantee that the implementation of the algorithm requested is from the named provider. The sample code of this lesson always specifies the default SUN provider built into the JDK.
Put the following statement after the
line in the file created in the previous step, Prepare Initial Program Structure:else try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
The next step is to initialize the key-pair generator. All key-pair generators share the concepts of a keysize and a source of randomness. TheGenerate the Pair of KeysKeyPairGenerator
class has aninitialize
method that takes these two types of arguments.
The keysize for a DSA key generator is the key length (in bits), which you will set to 1024.
The source of randomness must be an instance of theSecureRandom
class. This example requests one that uses the SHA1PRNG pseudo-random-number generation algorithm, as provided by the built-in SUN provider. The example then passes thisSecureRandom
instance to the key-pair generator initialization method.
Note: TheSecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); keyGen.initialize(1024, random);SecureRandom
implementation attempts to completely randomize the internal state of the generator itself unless the caller follows the call to thegetInstance
method with a call to thesetSeed
method. So if you had a specific seed value that you wanted used, you would call the following prior to theinitialize
call:
random.setSeed(seed);
The final step is to generate the key pair and to store the keys in
PrivateKey
and PublicKey
objects. KeyPair pair = keyGen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic();
In order to be able to create a digital signature, you need a private key. (Its corresponding public key will be needed in order to verify the authenticity of the signature.)
In some cases the key pair (private key and corresponding public key) are already available in files. In that case the program can import and use the private key for signing, as shown in Weaknesses and Alternatives.
In other cases the program needs to generate the key pair. A key pair is generated by using the
KeyPairGenerator
class. In this example you will generate a public/private key pair for the Digital Signature Algorithm (DSA). You will generate keys with a 1024-bit length.
Generating a key pair requires several steps:
Create a Key Pair Generator
The first step is to get a key-pair generator object for generating keys for the DSA signature algorithm.
As with all engine classes, the way to get aKeyPairGenerator
object for a particular type of algorithm is to call thegetInstance
static factory method on theKeyPairGenerator
class. This method has two forms, both of which hava aString algorithm
first argument; one form also has aString provider
second argument.
A caller may thus optionally specify the name of a provider, which will guarantee that the implementation of the algorithm requested is from the named provider. The sample code of this lesson always specifies the default SUN provider built into the JDK.
Put the following statement after the
line in the file created in the previous step, Prepare Initial Program Structure:else try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
Initialize the Key-Pair Generator
The next step is to initialize the key-pair generator. All key-pair generators share the concepts of a keysize and a source of randomness. TheKeyPairGenerator
class has aninitialize
method that takes these two types of arguments.
The keysize for a DSA key generator is the key length (in bits), which you will set to 1024.
The source of randomness must be an instance of theSecureRandom
class. This example requests one that uses the SHA1PRNG pseudo-random-number generation algorithm, as provided by the built-in SUN provider. The example then passes thisSecureRandom
instance to the key-pair generator initialization method.
Note: TheSecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); keyGen.initialize(1024, random);SecureRandom
implementation attempts to completely randomize the internal state of the generator itself unless the caller follows the call to thegetInstance
method with a call to thesetSeed
method. So if you had a specific seed value that you wanted used, you would call the following prior to theinitialize
call:
random.setSeed(seed);
Generate the Pair of Keys
The final step is to generate the key pair and to store the keys in PrivateKey
and PublicKey
objects. KeyPair pair = keyGen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic();
Sign the Data
Now that you have created a public key and a private key, you are ready to sign the data. In this example you will sign the data contained in a file.GenSig
gets the file name from the command line. A digital signature is created (or verified) using an instance of theSignature
class.
Signing data, generating a digital signature for that data, is done with the following steps.
Get a Signature Object:
The following gets aInitialize the Signature ObjectSignature
object for generating or verifying signatures using the DSA algorithm, the same algorithm for which the program generated keys in the previous step, Generate Public and Private Keys.
Note: When specifying the signature algorithm name, you should also include the name of the message digest algorithm used by the signature algorithm. SHA1withDSA is a way of specifying the DSA signature algorithm, using the SHA-1 message digest algorithm.Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
Before aSupply the Signature Object the Data to Be SignedSignature
object can be used for signing or verifying, it must be initialized. The initialization method for signing requires a private key. Use the private key placed into thePrivateKey
object namedpriv
in the previous step.
dsa.initSign(priv);
This program will use the data from the file whose name is specified as the first (and only) command line argument. The program will read in the data a buffer at a time and will supply it to theGenerate the SignatureSignature
object by calling theupdate
method.
FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = bufin.read(buffer)) >= 0) { dsa.update(buffer, 0, len); }; bufin.close();
Once all of the data has been supplied to theSignature
object, you can generate the digital signature of that data.
byte[] realSig = dsa.sign();
Save the Signature and the Public Key in Files
Now that you have generated a signature for some data, you need to save the signature bytes in one file and the public key bytes in another so you can send (via modem, floppy, mail, and so on) someone else
The receiver can verify that the data came from you and was not modified in transit by running the
- the data for which the signature was generated,
- the signature, and
- the public key
VerSig
program you will generate in the upcoming Verifying a Digital Signature steps. That program uses the public key to verify that the signature received is the true signature for the data received. Recall that the signature was placed in a byte array namedrealSig
. You can save the signature bytes in a file namedsig
via the following.
Recall from the Generate Public and Private Keys step that the public key was placed in a PublicKey object named/* save the signature in a file */ FileOutputStream sigfos = new FileOutputStream("sig"); sigfos.write(realSig); sigfos.close();pub
. You can get the encoded key bytes by calling thegetEncoded
method and then store the encoded bytes in a file. You can name the file whatever you want. If, for example, your name is Susan, you might name it something likesuepk
(for "Sue's public key"), as in the following:
/* save the public key in a file */ byte[] key = pub.getEncoded(); FileOutputStream keyfos = new FileOutputStream("suepk"); keyfos.write(key); keyfos.close();
Compile and Run the Program
Here
is the complete source code for theGenSig.java
program, with some comments added. Compile and run it. Remember, you need to specify the name of a file to be signed, as in
You can download and use this sample file namedjava GenSig datadata
or any other file you like. The file will not be modified. It will be read so that a signature can be generated for it.
After executing the program, you should see the savedsuepk
(public key) andsig
(signature) files.
Verifying a Digital Signature
If you have data for which a digital signature was generated, you can verify the authenticity of the signature. To do so, you need
In this example you write a
- the data
- the signature
- the public key corresponding to the private key used to sign the data
VerSig
program to verify the signature generated by theGenSig
program. This demonstrates the steps required to verify the authenticity of an alleged signature.
VerSig
imports a public key and a signature that is alleged to be the signature of a specified data file and then verifies the authenticity of the signature. The public key, signature, and data file names are specified on the command line.
The steps to create theVerSig
sample program to import the files and to verify the signature are the following.
- Prepare Initial Program Structure Create a text file named
VerSig.java
. Type in the initial program structure (import statements, class name,main
method, and so on).
- Input and Convert the Encoded Public Key Bytes Import the encoded public key bytes from the file specified as the first command line argument and convert them to a
PublicKey
.
- Input the Signature Bytes Input the signature bytes from the file specified as the second command line argument.
- Verify the Signature Get a
Signature
object and initialize it with the public key for verifying the signature. Supply it with the data whose signature is to be verified (from the file specified as the third command line argument), and verify the signature.
- Compile and Run the Program
No comments:
Post a Comment