Generating a MD5 message digest

What MD5 is and why it it important is explained well on the following page:

http://www.enteract.com/~lspitz/md5.html

A digest has two properties:
- it is computationally infeasible to find another input string that generates the same digest
- the digest does not reveal anything about the input that was used to generate it.

The engine class MessageDigest provides the functionality of several
types of cryptographic algorithms. What algorithms are available depends
on the provider you are using. For example, Sun (the default provider) supplies
implementations of the MD5 and SHA-1 message digest algorithms. Other providers
may have their own implementation of these algorithms or other algorithms.

As an implementation is supplied by Sun in the JDK, you don’t even have to
install another provider. Here’s is an example using the implementation by Cryptix:

 
import cryptix.util.core.Hex;
import cryptix.util.test.BaseTest;
import java.security.MessageDigest;
 
class TestMD5 
{
   public static void main(String[] args) {
      String plaintext = "The sun is green and the grass shines";

      MessageDigest md = null;
      try {
         // first create an instance, given the provider
         md = MessageDigest.getInstance("MD5", "Cryptix");
      }
      catch(java.security.NoSuchProviderException e) {
         System.out.println(e);
         System.exit(1);
      }
      catch(java.security.NoSuchAlgorithmException e) {
         System.out.println(e);
         System.exit(1);
      }

      md.reset();

      // call the update method one or more times 
      // (useful when you don't know the size of your data, eg. stream)
      md.update(plaintext.getBytes());

      // now calculate the hash
      byte[] hash = md.digest();

      System.out.println("Plaintext:nt" + plaintext + "n");
      // Hex is a function provided by Cryptix to produce a nice output
      System.out.println("Message Digest:nt" + Hex.toString(hash));
   }
}

generates the output:

 
Plaintext:
	The sun is green and the grass shines

Message Digest:
	470DB3B23F9D445446DFCE291C9F17AB

What is asymmetric cryptography?

The problem with symmetric cryptography is how to distribute the secret key to the involved parties. In assymetric cryptography (also: public key cryptography), algorithms use two different keys: a private and a public one. A message encrypted with a private key can be decrypted with its public key (and in some cases vice versa). The owner of the key pair holds the private key, and may distribute the public key to anyone. Someone who wants to send a secret message uses the public key of the intended receiver to encrypt it. Only the receiver holds the private key and can decrypt it.

Compared to secret key encryption, public key encryption is slow.

A popular assymetric cryptographic algorithm is RSA, used in PGP.

What is a message authentication code (MAC)?

A MAC is a type of a message digest but that requires a key. It uses that key to encrypt the hash. Only the receiver, who has access to that key, can decrypt the hash and verify whether the message has not been tampered with.

This is to solve the problem that a man-in-the-middle, one that spies the communication line, intercepts a message with a conventional message digest and then sends out another message with another message digest. The receiver is unable to know whether the whole thing comes from the original sender. If the sender and receiver would use a MAC utilizing a (secret) key, there would be no way for the man-in-the-middle to intercept and send out a new message as he doesn’t know the key.

The problem with MACs is that secret keys need to be shared between both parties.

A MAC works with available hashing methods (MD5 or SHA).

Programmatically generating a public and private key

Programmatically:

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
import java.io.*;
 
public class Main
{
   public static void main(String []args) throws Exception {
      KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
      kpg.initialize(1024);
      KeyPair kp = kpg.genKeyPair();
 
      byte[] publicKey = kp.getPublic().getEncoded();
      byte[] privateKey = kp.getPrivate().getEncoded();
 
      FileOutputStream fos = new FileOutputStream("public.key");
      fos.write(publicKey);
      fos.close();
      fos = new FileOutputStream("private.key");
      fos.write(privateKey);
      fos.close();
   }
}

using keytool:

keytool -genkey -alias mykey -keysize 1024 -keyalg RSA

What is a keystore?

A keystore is a database (usually a file) that can contain trusted certificates and combinations of private keys with their corresponding certficiates.

- trusted certificates: these are certificates from the entities you trust, for example a certificate from Thawte. Trusted certificates are used to validate other certificates. For example, suppose you have a certificate A signed by Thawte and you want to check it for trustworthiness. Certificate A contains: a public key, some identification information about the certificate (name, etc.), a digital signature (calculated by the one that is vouching for the certificate, in this case Thawte), and some identification information about the voucher. Now you can extract the digital signature from A and decrypt it with the public key from the Thawte (stored in the keystore as a trusted certificate) to check the validity the public key of A.

- private keys/certificates: each is a public key certificate with their corresponding private keys.

To create a keystore containing a self-signed certificate:

C:>c:jdk1.3binkeytool -genkey -alias mykey -keyalg RSA
Enter keystore password:  esuspass
What is your first and last name?
  [Unknown]:  Joris Van den Bogaert
What is the name of your organizational unit?
  [Unknown]:  ESUS Team
What is the name of your organization?
  [Unknown]:  Esus, Inc
What is the name of your City or Locality?
  [Unknown]:  Meerbeek
What is the name of your State or Province?
  [Unknown]:
What is the two-letter country code for this unit?
  [Unknown]:  BE
Is <CN=Joris Van den Bogaert, OU=ESUS Team, O="Esus, Inc", L=Meerbeek, ST=Unknow
n, C=BE> correct?
  [no]:  yes

Enter key password for <mykey>
        (RETURN if same as keystore password):
 
C:> c:jdk1.3binkeytool -list
Enter keystore password:  esuspass

Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry:

mykey, Mon Aug 06 13:29:28 CEST 2001, keyEntry,
Certificate fingerprint (MD5): 0E:8F:ED:F3:E3:07:25:9C:1D:15:65:43:7C:4F:86:32

The keystore containing the trusted certificates is located at JRE_HOME/lib/security/cacerts. You
can list its contents:

C:> c:jdk1.3binkeytool -list -keystore c:jdk1.3jrelibsecuritycacerts
Enter keystore password:

*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

Keystore type: jks
Keystore provider: SUN

Your keystore contains 10 entries:

thawtepersonalfreemailca, Fri Feb 12 21:12:16 CET 1999, trustedCertEntry,
Certificate fingerprint (MD5): 1E:74:C3:86:3C:0C:35:C5:3E:C2:7F:EF:3C:AA:3C:D9
thawtepersonalbasicca, Fri Feb 12 21:11:01 CET 1999, trustedCertEntry,
Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41
verisignclass3ca, Mon Jun 29 19:05:51 CEST 1998, trustedCertEntry,
Certificate fingerprint (MD5): 78:2A:02:DF:DB:2E:14:D5:A7:5F:0A:DF:B6:8E:9C:5D
thawtepersonalpremiumca, Fri Feb 12 21:13:21 CET 1999, trustedCertEntry,
Certificate fingerprint (MD5): 3A:B2:DE:22:9A:20:93:49:F9:ED:C8:D2:8A:E7:68:0D
thawteserverca, Fri Feb 12 21:14:33 CET 1999, trustedCertEntry,
Certificate fingerprint (MD5): C5:70:C4:A2:ED:53:78:0C:C8:10:53:81:64:CB:D0:1D
verisignclass4ca, Mon Jun 29 19:06:57 CEST 1998, trustedCertEntry,
Certificate fingerprint (MD5): 1B:D1:AD:17:8B:7F:22:13:24:F5:26:E2:5D:4E:B9:10
verisignserverca, Mon Jun 29 19:07:34 CEST 1998, trustedCertEntry,
Certificate fingerprint (MD5): 74:7B:82:03:43:F0:00:9E:6B:B3:EC:47:BF:85:A5:93
verisignclass1ca, Mon Jun 29 19:06:17 CEST 1998, trustedCertEntry,
Certificate fingerprint (MD5): 51:86:E8:1F:BC:B1:C3:71:B5:18:10:DB:5F:DC:F6:20
thawtepremiumserverca, Fri Feb 12 21:15:26 CET 1999, trustedCertEntry,
Certificate fingerprint (MD5): 06:9F:69:79:16:66:90:02:1B:8C:8C:A2:C3:07:6F:3A
verisignclass2ca, Mon Jun 29 19:06:39 CEST 1998, trustedCertEntry,
Certificate fingerprint (MD5): EC:40:7D:2B:76:52:67:05:2C:EA:F2:3A:4F:65:F0:D8

Generating a MAC that uses MD5 in Java

The following example generates a random key of 128 bits (16 bytes) necessary for HmacMD5 and computes a hash using this key. The key would have to be shared between sender and receiver.

Main.java:

import javax.crypto.spec.*;
import javax.crypto.Mac;
import java.security.*;
import javax.crypto.*;
import sun.misc.*;
 
public class Main
{
   public static void main(String []args) throws Exception {
      String message = "the sun is green and the grass shines";
 
      byte[] b = generateMAC(message);
      System.out.println("HMAC-MD5 for message '" + message + "':");
      System.out.println("t" + new BASE64Encoder().encode(generateMAC(message)));
   }
 
   public static byte[] generateMAC(String message) throws Exception {
      // generate key
      SecureRandom sr = new SecureRandom();
      byte[] b = new byte[20];
      sr.nextBytes(b);
      SecretKey key = new SecretKeySpec(b, "HmacMD5");
 
      // generate message digest based on key
      Mac mac = Mac.getInstance("HmacMD5");
      mac.init(key);
 
      return mac.doFinal(message.getBytes());
   }
}

outputs:

HMAC-MD5 for message 'the sun is green and the grass shines':
        JX25ruAB1qM0w39rTQnPGA==

Encrypting/decrypting a message using an assymetric encryption method (eg. RSA)

The following code demonstrates using a pair of RSA public/private key pairs to secure a message between a producer and a consumer. It also generates and validates a signature along the way since that is another common task.
AsymetricTest.java:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
import java.security.*;
import javax.crypto.*;
 
public class AsymetricTest {
 
    // these algorithms need to work together!
    public static String keyAlgorithm = "RSA" ;
    public static String cipherAlgorithm = "RSA/OAEP" ;
    public static String signatureAlgorithm = "SHA1WithRSAEncryption" ;
 
    static public void main(String[] args) {
	String testData = "Hugh, and only Hugh, can prevent florist friars." ;
 
	try {
	    // make sure the BC provider is registered.
	    Security.addProvider(new BouncyCastleProvider());
 
	    /***
	     * Generate two pairs of keys, one for the producer
	     * and one for the consumer.
	     ***/
	    KeyPairGenerator gen = KeyPairGenerator.getInstance(keyAlgorithm, "BC");
	    gen.initialize(1024, new SecureRandom());
 
	    System.out.println("Generating keys . . .") ;
	    KeyPair producerPair = gen.generateKeyPair();
	    KeyPair consumerPair = gen.generateKeyPair();
	    System.out.println("Generated keys, proceeding") ;
 
	    /***
	     * first on the producer side: encrypt and sign the
	     * original data.  The producer knows the consumer public key.
	     ***/
 
	    // encrypt the testData using the public key
	    byte[] encryptedData = encrypt(testData.getBytes(), consumerPair.getPublic()) ;
 	    
	    System.out.println("Encrypted byte count: " + encryptedData.length) ;
 
	    // generate a digital signature
	    byte[] dataSignature = generateSignature(testData, producerPair.getPrivate()) ;
 
	    System.out.println("Signature created, bytes: " + dataSignature.length) ;
 
	    /***
	     * uncomment one of these lines to befoul either the
	     * encrypted data or the signature "in transit" if you want
	     * to see a failure in the next steps.
	     ***/
	    //encryptedData[8] = 0 ;
	    //dataSignature[8] = 0 ;
 	    
	    /***
	     * and now on the consumer side: decrypt the original data,
	     * then use that result to validate the signature.  The
	     * consumer knows the producer's public key.
	     ***/
 
	    // decrypt the message using the private key
	    byte[] receivedData = decrypt(encryptedData, consumerPair.getPrivate()) ;
	    System.out.println("Data decoded, byte count: " + receivedData.length) ;
	    System.out.println("[" + new String(receivedData) + "]") ;
 
	    // and validate the signature
	    if ( ! validateSignature(receivedData, dataSignature, producerPair.getPublic()) ) {
		throw new SignatureException("Signature validation failed") ;
		}
 
	    System.out.println("Signature OK.") ;
	    }
	catch ( Exception ex ) {
	    ex.printStackTrace() ;
	    }
 	    
	System.exit(0);
	}

    public static byte[] encrypt(byte[] toEncrypt, PublicKey key)
				    throws GeneralSecurityException {
	Cipher cipher = Cipher.getInstance(cipherAlgorithm) ;
	cipher.init(Cipher.ENCRYPT_MODE, key) ;
 
	byte[] result = cipher.doFinal(toEncrypt) ;
	return result ;
    }

    public static byte[] decrypt(byte[] toDecrypt, PrivateKey key)
				    throws GeneralSecurityException {
	Cipher deCipher = Cipher.getInstance(cipherAlgorithm) ;
	deCipher.init(Cipher.DECRYPT_MODE, key) ;
 
	deCipher.update(toDecrypt) ;
 
	byte[] result = deCipher.doFinal() ;
	return result ;
    }

    public static byte[] generateSignature(String toSign, PrivateKey key)
				    throws GeneralSecurityException {
	Signature genSig = Signature.getInstance(signatureAlgorithm) ;
	genSig.initSign(key) ;
 
	genSig.update(toSign.getBytes()) ;
 
	byte[] result = genSig.sign() ;
	return result ;
    }

    public static boolean validateSignature(byte[] dataToValidate, byte[] sigToValidate, PublicKey key)
				    throws GeneralSecurityException {
	Signature valSig = Signature.getInstance(signatureAlgorithm) ;
	valSig.initVerify(key) ;
 
	valSig.update(dataToValidate) ;
 
	return valSig.verify(sigToValidate) ;
	}
    }

(tested with the BouncyCastle JCE provider, http://www.bouncycastle.org)

Getting a certificate from a Java keystore

I assumed here that you created the alias in the default keystore described in the question What is a keystore?.

Programmatically:

Main.java:

import java.security.cert.Certificate;
import java.security.*;
import java.io.*;
 
public class Main {
   public static void main(String []args) {
      try {
         KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
     
         InputStream in = new FileInputStream(System.getProperty("user.home") + "\" + 
                                              ".keystore");
 
         keyStore.load(in, "esuspass".toCharArray());
     
         Certificate cert = keyStore.getCertificate("mykey");
 
         System.out.println(cert);
      }  
      catch (KeyStoreException e) { 
         System.out.println(e);
      } 
      catch (java.security.cert.CertificateException e) {
         System.out.println(e);
      } 
      catch (NoSuchAlgorithmException e) {
         System.out.println(e);
      } 
      catch (java.io.IOException e) {
         System.out.println(e);
      } 
   }
}

outputs:

C:> java Main
[
[
  Version: V1
  Subject: CN=Joris Van den Bogaert, OU=ESUS Team, O="Esus, Inc", L=Meerbeek, ST
=Unknown, C=BE
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  RSA Public Key
            modulus: 10001
    public exponent: d395abbc7bd76b47c60a5e6e30cb7b74d8878706fe757d063daf737d8cd
3bf70447eaefd7ebaaab4d267898d8cd0680983a69b2e78c1d14ec27bfcff04da068e2dded11e323
4ecb900955295f96036ed0ddb919c5036bdb422415af60d81b793dbb40709f3fdd01609c470a52c5
e9ddc6879649122df5591d6f95efdbdf95889

  Validity: [From: Mon Aug 06 13:29:25 CEST 2001,
               To: Sun Nov 04 12:29:25 CET 2001]
  Issuer: CN=Joris Van den Bogaert, OU=ESUS Team, O="Esus, Inc", L=Meerbeek, ST=
Unknown, C=BE
  SerialNumber: [    3b6e7f95 ]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 94 19 99 85 71 95 6B C6   20 A0 42 C9 0E D1 4C D0  ....q.k. .B...L.
0010: 7A D6 30 38 4A C7 9E 65   72 F0 63 85 3D 46 74 48  z.08J..er.c.=FtH
0020: 7D 1D 70 A4 0A C9 A2 FC   CB 01 04 FA C5 31 39 1A  ..p..........19.
0030: 9C DC EA 07 BD 2C AD 7C   B0 D3 8E 00 16 90 E4 0E  .....,..........
0040: DB 73 3A AC 15 9F 6D 3F   7E 61 E6 E1 10 E5 A7 15  .s:...m?.a......
0050: 1C F5 B2 88 60 4C 55 3D   6B 38 22 B8 12 D6 B3 AF  ....`LU=k8".....
0060: 3A 81 61 C1 8C B3 CC 33   18 20 CA C8 B7 18 15 88  :.a....3. ......
0070: 67 6A C4 F7 D4 95 7E 80   7F DC F6 C6 79 36 86 C2  gj..........y6..

]

Using keytool:

C:> c:jdk1.3binkeytool -export -alias mykey -file mykey.cer
Enter keystore password:  esuspass
Certificate stored in file <mykey.cer>