Hash-based Message Authentication Code (HMAC)


Hash-based MACs (HMACs) takes a long message as the input and produce a fixed-length output. In this scheme, the sender signs a message using the MAC and the receiver verifies it using the shared key. It hashes the key with the message using either of the two methods known as a secret prefix (key comes first and the message comes afterwards) or the secret suffix (key comes after the message).

High-level design of HMAC


Message Authentication Code (MAC) is a small part of information or a small algorithm, basically used to authenticate a message and to maintain integrity and authenticity assurances on the message. Hash-based Message Authentication Code is a message authentication code derived from a cryptographic hash function such as MD5 and SHA-1. The basic idea behind HMAC is to add a layer using a secret key in the existing message digest algorithms. Even if an attacker got the database of hashed passwords with the salts, they would still have a difficult time cracking them without the secret key. As algorithms such as MD5 and SHA-1 do not rely on the secret key, HMAC has been selected as mandatory-to-implement MAC for IP security. HMAC can work with any existing message digest algorithms (hash functions). It considers the message digest produced by the embedded hash function as a black box. It then uses the shared symmetric key to encrypt the message digest, thus, producing the final output, that is, MAC. HMAC is a calculation of a MAC through the use of a cryptographic hash function such as MD5 or SHA-1.

When we use SHA-1, then corresponding MAC would be known as HMAC-SHA1, or if SHA-2 is being used then we would say HMAC-SHA256. It is a good practice to store secret key in a separate location such as an environment variable rather than in the database with hashed passwords and salts.

Example

package main
 
import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"io"
)
 
var secretKey = "4234kxzjcjj3nxnxbcvsjfj"
 
// Generate a salt string with 16 bytes of crypto/rand data.
func generateSalt() string {
	randomBytes := make([]byte, 16)
	_, err := rand.Read(randomBytes)
	if err != nil {
		return ""
	}
	return base64.URLEncoding.EncodeToString(randomBytes)
}
 
func main() {
	message := "Today web engineering has modern apps adhere to what is known as a single-page app (SPA) model."
	salt := generateSalt()
	fmt.Println("Message: " + message)
	fmt.Println("\nSalt: " + salt)
 
	hash := hmac.New(sha256.New, []byte(secretKey))
	io.WriteString(hash, message+salt)
	fmt.Printf("\nHMAC-Sha256: %x", hash.Sum(nil))
 
	hash = hmac.New(sha512.New, []byte(secretKey))
	io.WriteString(hash, message+salt)
	fmt.Printf("\n\nHMAC-sha512: %x", hash.Sum(nil))
}

Output

Message: Today web engineering has modern apps adhere to what is known as a sing
le-page app (SPA) model.

Salt: iWk9q-tQgWQTnqDgdoxaXQ==

HMAC-Sha256: b158c5a1bbcdac3cf87fe761030828cb5811b0a6fdfa6366c7bdfddba6391728

HMAC-sha512: e350ca7f0349c2b16a410f224b1ad0c8fc9319708b1dd2be9e83a53b3d4b93d9dd1
f0637ea27641edcfac3d3196795d9889778bd4894ad332ba643d0735aa089