3

I have a code from creating base 64 hashes

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class ApiSecurityExample {
  public static void main(String[] args) {
    try {
     String secret = "secret";
     String message = "Message";

     Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
     SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
     sha256_HMAC.init(secret_key);

     String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
     System.out.println(hash);
    }
    catch (Exception e){
     System.out.println("Error");
    }
   }
}

there is secret_key in sha256_HMAC.init(secret_key);

when I read, it tells use Key key an Interface.

how to use it?

yozawiratama
  • 4,209
  • 12
  • 58
  • 106

1 Answers1

4

The example is doing it wrong, as strings should not be used to store keys.

A secret key should consist of bytes that are unpredictable to an adversary. The most logical method to generate those is to use a random number generator, but you can also generate them from key establishment (Diffie-Hellman), using a key derivation function upon another key, ratchets and many other ways.

A somewhat dangerous method is to generate them from a password. For that you normally use a Password Based Key Derivation Function or PBKDF. Java has direct support for PBKDF2 which can be used for this.


So you could create a HMAC key in the following way:

Mac mac = Mac.getInstance("HMACSHA256");

SecureRandom rng = new SecureRandom();
// key size can be anything but should default to the hash / MAC output size for HMAC
byte[] hmacKeyData = new byte[mac.getMacLength()];
rng.nextBytes(hmacKeyData);
SecretKey hmacKey = new SecretKeySpec(hmacKeyData, "HMACSHA256");
Arrays.fill(hmacKeyData, (byte) 0x00); 

However, the following code is shorter, probably more descriptive. It also allows hardware devices to be used later on to implement the Mac, although that might be a bit out of your territory.

KeyGenerator kg = KeyGenerator.getInstance("HMACSHA256");
SecretKey hmacKey = kg.generateKey();

Finally, if you still want to use a password, then use PKBDF2 and don't forget to store the salt:

// you don't want to use a string, as you cannot delete strings in Java
char[] password = {'p', 'a', 's', 's' };
SecureRandom rng = new SecureRandom();
byte[] salt = new byte[128 / Byte.SIZE];
rng.nextBytes(salt);
int iterations = 1_000_000;

Mac mac = Mac.getInstance("HMACSHA256");

PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, mac.getMacLength() * Byte.SIZE);
SecretKeyFactory pbkdf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hmacKeyData = pbkdf.generateSecret(spec).getEncoded();
SecretKey hmacKey = new SecretKeySpec(hmacKeyData, "HMACSHA256");

// clean up secret material
Arrays.fill(password, (char) 0x0000); 
spec.clearPassword();
Arrays.fill(hmacKeyData, (byte) 0x00); 

As an attacker may have forever to try passwords if he has a MAC to compare the result with, it would be a very good idea to choose a very complex password though; this is why password based encryption generally is not a good idea.


Key is a generic parent interface used for both SecretKey, PublicKey and PrivateKey. It is used in many classes that represent crypto algorithms as they may be used with any kind of key. For instance Cipher can be used for RSA but also for AES. So the implementation just checks at runtime if the correct key is given.

For Mac it might as well have been SecretKey as a Mac is really always a symmetrical algorithm (an asymmetric form of a Mac is called a Signature after all). Just a HMAC key would not be enough though, as there are also Mac algorithms based on block ciphers such as AES (thus requiring a SecretKey with algorithm "AES").

For convenience, SecretKeySpec also implements SecretKey; that way you don't need the SecretKeyFactory to create a SecretKey. The Java designers kind of forgot about hardware support that does require such as factory, but here we are.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263