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.