Hash based Message Authentication Code hashing in Spring MVC

Hash based Message Authentication Code(HMAC) is used in scenarios where you need to validate the validity and authenticity of a message. Recently I was implementing some security aspects for our REST service, and I noticed that Spring Security currently supports SHA hashing for password, but no HMAC SHA hashing.

Now firstly, this is really for informational sakes, and I’m in no position to advise which way is better, but instead, I’m providing what I think I’d rather have implemented, and its purely a personal preference – for me anyway.

So, now back to the point. Firstly, below is a sample of a security configuration(in xml) using one of the many Spring Security provided implementations of the PasswordEncoder interface – namely the ShaPasswordEncoder.

.....
<authentication-manager>
   <authentication-provider>
      <password-encoder hash="sha"/>
      <user-service>
         <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" authorities="ROLE_USER, ROLE_ADMIN" />
         <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>
.....

Now in this simple contrived sample config, we’re telling Spring Security to use their implementation of the ShaPasswordEncoder. Upon inspection of this implementation, you’re also able to specify the field responsible for holding the salt value if you so choose to provide one. In the REST service I have, I have defintely opted to provide a salt in which to further secure the hash.

In this ShaPasswordEncoder implementation provided by Spring, it performs a hash on the raw concatenated string in the format of “password{salt}” . This surprised me somewhat, because I had actually expected Spring to provide an implementation of HMacSHA when providing a salt, not just an implementation of SHA! And believe me theres a difference! So the purist in me came out, and I couldn’t let this rest (see what I did there? rest….REST?.. ok I know, perhaps a little lame, but I digress.)

The main difference between the two implementations, is that the way Spring have done it, they have just effectively hashed a string. With HMac, the salt actively plays a role in the encryption of the raw string. Some might argue that they arrive at the same end result, which is a hashed string based on the salt. I’d tend to agree, but the purist in me wanted to do it properly, so I wrote my own implementation of what the HMacSha should have been. Below is a simple snippet of what the code looks like when just using a normal SHA hash, and when using a HMacSHA. In these samples below I’ve only shown the code which actually does the hashing so you can see what the difference is. Also bear in mind, that my custom rolled hashing class extends the PasswordEncoder class so that I can include it in the security config xml.

SHA Implementation

public String encodePassword(String rawPass, Object salt) {
 String saltedPass = mergePasswordAndSalt(rawPass, salt, false);

MessageDigest messageDigest = getMessageDigest();

byte[] digest = messageDigest.digest(Utf8.encode(saltedPass));

// "stretch" the encoded value if configured to do so
 for (int i = 1; i < iterations; i++) {
 digest = messageDigest.digest(digest);
 }

if (getEncodeHashAsBase64()) {
 return Utf8.decode(Base64.encode(digest));
 } else {
 return new String(Hex.encode(digest));
 }
 }

protected final MessageDigest getMessageDigest() throws IllegalArgumentException {
 try {
 return MessageDigest.getInstance(algorithm);
 } catch (NoSuchAlgorithmException e) {
 throw new IllegalArgumentException("No such algorithm [" + algorithm + "]");
 }
 }

protected String mergePasswordAndSalt(String password, Object salt, boolean strict) {
 if (password == null) {
 password = "";
 }

if (strict && (salt != null)) {
 if ((salt.toString().lastIndexOf("{") != -1) || (salt.toString().lastIndexOf("}") != -1)) {
 throw new IllegalArgumentException("Cannot use { or } in salt.toString()");
 }
 }

if ((salt == null) || "".equals(salt)) {
 return password;
 } else {
 return password + "{" + salt.toString() + "}";
 }
 }

HMac Implementation

protected final Mac getMac() throws IllegalArgumentException {
 try {
 return Mac.getInstance(algorithm);
 } catch (NoSuchAlgorithmException e) {
 throw new IllegalArgumentException("No such algorithm [" + algorithm + "]");
 }
 }
 public String encodePassword(String rawDataToBeEncrypted, Object salt) {
 byte[] hmacData = null;
 if(rawDataToBeEncrypted != null){
 try {
 SecretKeySpec secretKey = new SecretKeySpec(rawDataToBeEncrypted.getBytes(ENCODING_FOR_ENCRYPTION), this.algorithm);
 Mac mac = getMac();
 mac.init(secretKey);
 hmacData = mac.doFinal(salt.toString().getBytes(ENCODING_FOR_ENCRYPTION));

if (isEncodeHashAsBas64()) {
 return new String(Base64.encode(hmacData), ENCODING_FOR_ENCRYPTION);
 } else {
 return new String(hmacData, ENCODING_FOR_ENCRYPTION);
 }

}
 catch(InvalidKeyException ike){
 throw new RuntimeException("Invalid Key while encrypting.", ike);
 }
 catch (UnsupportedEncodingException e) {
 throw new RuntimeException("Unsupported Encoding while encrypting.",e);
 }
 }
 return "";

}

I am using this version of the hashing algorithm for my sample REST service which I have up on Github. You can check out the java file itself here, but I’ll give a more detailed run down of the sample project in my next blog post, which is about supporting stateless authentication in a Spring REST application, and how I went about rolling my own security filter/mechanism to support this. Watch this space!

Advertisements