Code Examples – Verifying digital signatures

Introduction  |  Message Digest  |  Symmetric ciphers  |  RSA  |  ECIES  |  Digital signatures (S/MIME)

Download code

Verifying digital signatures: here we want to show how to verify the digital signature of a message. By verifying the signature of a message, the receiver can be sure that the message is from the expected sender and hasn't been modified by anyone else.

First, we do the necessary imports:

01 import java.io.File;
02 import java.io.FileInputStream;
03 import java.security.MessageDigest;
04 import java.security.PrivateKey;
05 import java.security.Security;
06 import java.security.Signature;
07
08 import codec.x509.X509Certificate;
09 import de.flexiprovider.common.util.ByteUtils;
10 import de.flexiprovider.core.FlexiCoreProvider;
11
12 public class ExampleSMIMEVerifyRSA {
13
14 public static void main(String[] args) throws Exception {
15
16 Security.addProvider(new FlexiCoreProvider());

Next, we read the signed message we want to verify:

18 File file = new File("MyEmail");
19 byte[] message = new byte[(int) file.length()];
20 FileInputStream fis = new FileInputStream(file);
21 fis.read(message);
22 fis.close();

The signature belonging to the message must be read as well. This is the signature we will verifiy later.

24 File file = new File("RSASignature.sig");
25 byte[] sigBytes = new byte[(int) file.length()];
26 FileInputStream fis = new FileInputStream(file);
27 fis.read(sigBytes);
28 fis.close();

In order to do the verification, we will need two public certificates: the one of the user who signed the message, and the one of the certificate authority which signed the user's certificate. The first one is used to verify the signature of the file itself, and the latter one lets us verify the user's certificate. We store both certificates in X509Certificate classes:

30 File file = new File("CertRSA.cer");
31 byte[] encCertRSA = new byte[(int) file.length()];
32 FileInputStream fis = new FileInputStream(file);
33 fis.read(encCertRSA);
34 fis.close();
35
36 File file = new File("UserCA.cer");
37 byte[] encCertCA = new byte[(int) file.length()];
38 FileInputStream fis = new FileInputStream(file);
39 fis.read(encCertCA);
40 fis.close();
41
42 X509Certificate certRSA = new X509Certificate(encCertRSA);
43 X509Certificate certCA = new X509Certificate(encCertCA);

In lines 42 and 43, we use the X509Certificate(byte[] cert) constructor to get the certificate data. This provides us access to all the attributes in a X.509 certificate and methods needed to check its validity.

Before verifying the signed message, we compute the SHA1 fingerprints of the certificates. For the sample certificates, you may compare these fingerprints with the values on the index page for digital signatures to be sure that you have the correct certificates.

47 MessageDigest md = MessageDigest.getInstance("SHA1", "FlexiCore");
48
49 md.update(encCertRSA);
50 System.out.println("SHA1 fingerprint of \"CertRSA.cer\": "
51 + ByteUtils.toHexString(md.digest()));
52
53 md.update(encCertCA);
54 System.out.println("SHA1 fingerprint of \"UserCA.cer\" : "
55 + ByteUtils.toHexString(md.digest()));

For more information about computing digests, please look at the code example for message digests.

We also want to check the validity of the certificate chain. For the verification, we employ the shell model.

57 PublicKey pubKeyCA = certCA.getPublicKey();
58
59 certRSA.checkValidity();
60 certRSA.verify(pubKeyCA, "FlexiCore");
61 System.out.println("The signature of \"CertRSA.cer\" verifies : true");
62
63 certCA.checkValidity();
64 certCA.verify(pubKeyCA, "FlexiCore");
65 System.out.println("The signature of \"UserCA.cer\" verifies : true");
66
67 System.out.println("=> The certificate chain is valid!\n");

In lines 59 and 63, we call the checkValidity() method on both certificates. This checks the certificate's date by comparing it to the current time. If the certificate has expired or is not valid yet, the method will throw an exception.

In lines 60 and 64, the verify(PublicKey key) method is called on both certificates with the public key of the certificate authority (UserCA) as parameter. If the signatures of the certificates are invalid, this method throws an exception. The verification of the CA's certificate is possible because the sample certificate is selfsigned. In real life, you would check this certificate chain up to a trusted CA to be sure to have valid certificates.

Now we are ready to verify the signature of the received message:

69 PublicKey pubKeyRSA = certRSA.getPublicKey();
70
71 Signature sig = Signature.getInstance("SHA1withRSA", "FlexiCore");
72
73 sig.initVerify(pubKeyRSA);
74 sig.update(message);
75 boolean isValid = sig.verify(sigBytes);
76 System.out.println("The signature of the email verifies: " + isValid);
77 }
78
79 }

We can see that the process for the verification of digital signatures is analogous to the process for creating digital signatures. In line 71, we instantiate a Signature class for the desired algorithm, and in line 73, we initialize it for verification with the user's public key from the user's certificate. The public key is acquired in line 69 with the getPublicKey() method of the X509Certificate class. The data for verifaction is read via the update(byte[] data) method in line 74. The verification is finally done in line 75 with the verify(byte[] signature) method. If the signature is valid, it returns true, otherwise, it return false. The result of the verification is printed to standard output.

Druckerenglisch deutsche Flagge   Impressum