Generating or Verifying Signatures Using Key Specifications and KeyFactory

Suppose that, rather than having a public-private key pair (as, for example, was generated in the key pair example), you simply have the components of your DSA private key: x (the private key), p (the prime), q (the sub-prime), and g (the base).

Further suppose you want to use your private key to digitally sign some data, which is in a byte array named someData. You would do the following steps, which also illustrate creating a key specification and using a key factory to obtain a PrivateKey from the key specification (initSign requires a PrivateKey):
DSAPrivateKeySpec dsaPrivKeySpec = new DSAPrivateKeySpec(x, p, q, g);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privKey = keyFactory.generatePrivate(dsaPrivKeySpec);
Signature sig = Signature.getInstance("SHA1withDSA");
sig.initSign(privKey);
sig.update(someData);
byte[] signature = sig.sign();
Suppose Alice wants to use the data you signed. In order for her to do so, and to verify your signature, you need to send three things to her:
  • the data,
  • the signature, and
  • the public key corresponding to the private key you used to sign the data.

You can store the someData bytes in one file, and the signature bytes in another, and send those to Alice.

For the public key, assume, as in the signing example, that you have the components of the DSA public key that corresponds to the DSA private key that was used to sign the data. Then you can create a DSAPublicKeySpec from those components:
DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(y, p, q, g);
You still need to extract the key bytes so that you can put them in a file. To do so, you can first call the generatePublic method on the DSA key factory already created in the last example:
PublicKey pubKey = keyFactory.generatePublic(dsaPubKeySpec);
Then you can extract the (encoded) key bytes using the following method:
byte[] encKey = pubKey.getEncoded();

You can now store these bytes in a file, and send it to Alice along with the files that contain the data and the signature.

Now, assume Alice has received these files, and that she copied the data bytes from the data file to a byte array named data, the signature bytes from the signature file to a byte array named signature, and the encoded public key bytes from the public key file to a byte array named encodedPubKey.

Alice can now execute the following code to verify the signature. The code also illustrates how to use a key factory in order to instantiate a DSA public key from its encoding (initVerify requires a PublicKey).
 X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Signature sig = Signature.getInstance("SHA1withDSA");
sig.initVerify(pubKey);
sig.update(data);
sig.verify(signature);
Note: In the preceding example, Alice needed to generate a PublicKey from the encoded key bits, because initVerify requires a PublicKey. After she has a PublicKey, she could also use the KeyFactory getKeySpec method to convert it to a DSAPublicKeySpec so that she can access the components, if desired, as in:
 DSAPublicKeySpec dsaPubKeySpec =
 (DSAPublicKeySpec)keyFactory.getKeySpec(pubKey, DSAPublicKeySpec.class)
Now she can access the DSA public key components y, p, q, and g through the corresponding get methods on the DSAPublicKeySpec class (getY, getP, getQ, and getG).