Hashes, signatures and certificates

Message summaries

Digests are implemented using the java.security.MessageDigest class, which allows you to generate a data digest. The digest can be made secure using javax.crypto.Mac. The operation can also be performed with Streams thanks to java.security.DigestInputStream and java.security.DigestOutputStream.

Some typical digest algorithms: MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512.

MessageDigest messageDigest = MessageDigest.getInstance(algorithm); byte[] digest = messageDigest.digest(text.getBytes(StandardCharsets.UTF_8));

Secure digests

A Message Authentication Code (javax.crypto.Mac) is a digest encrypted with a shared private key. It can only be verified if you have this key. We can generate it like this:

Mac mac = Mac.getInstance(algorithm); mac.init(key); // the private key byte[] macBytes = mac.doFinal(text.getBytes(StandardCharsets.UTF_8));

An algorithm could be HmacSHA256 (HMAC: Hash-based MAC).

Key Derivation Functions

With a KDF, we can generate a key longer than a password, for example. Here we have an example using the PBKDF2WithHmacSHA256 algorithm.

SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec ks = new PBEKeySpec(password, salt, iterationCount, keyLength); SecretKey rawSecret = f.generateSecret(ks); // generic secret SecretKey aesSecret = new SecretKeySpec(s.getEncoded(), "AES"); // AES secret

The KeySpec parameters are:

  • password: a char[] with the password.
  • salt: A salt to randomize the hash.
  • iterationCount: number of iterations to generate the hash.
  • keyLength: length of the key to generate.

Digital signatures

A digital signature is equivalent to making a summary and encrypting it with a private key. The receiver could decipher it with the public, and compare it with a summary of the data (plan) received.

Algorithms are varied, for example SHA256withRSA indicates that hashing is done with SHA256 and encryption with RSA. Therefore, the keys used must be RSA. To sign an input (byte array):

Signature sign = Signature.getInstance(algorithm); sign.initSign(privateKey); sign.update(input); byte[] signature = sign.sign();

To verify it:

Signature sign = Signature.getInstance(algorithm); sign.initVerify(publicKey); sign.update(input); boolean correct = sign.verify(signature);

Certificates

The most common certificates (java.security.cert.Certificate) are of type X.509, and indicate a binding of an identity to a public key, guaranteed by another authorized entity. They include:

  • start and end date
  • version (currently 3)
  • serial number (unique per supplier)
  • the DN (distinguished name) of the issuing CA
  • the DN of the subject of the certificate

DNs (Distinguished Names) contain a series of fields (CN, OU, O, L, S, C) that identify both the issuer and the subject.

Usually, we find them inside warehouses. To manage them we can use the JRE keytool tool or programmatically with the java.security.KeyStore class and the getKey(alias) (private key) and getCertificate(alias) (certificate where there is the public key).

They are required on web portals with HTTPS security enabled.