This a BASH and OpenSSL HMAC script that accepts a hexadecimal key (OpenSSL’s -hmac command limits input to printable ASCII characters). Nigel Smith has a great post that describes how to get around this limitation for versions 1.0.0 or later, but I wanted an option that would work on my MacOS 10.9.4 with OpenSSL v0.9.8y. This script implements HMAC-SHA-1, HMAC-SHA-256, and HMAC-SHA-512 according to FIPS 198-1.
Downloads:
- hmac.sh (current) (sig) (sha1:29e255195358703533ad02ff4e48d611fd3c8487)
- hmac.v1.0.sh (sig) (sha1: 877c56a0087ca2be8ec238a73ca2c11b079bd438)
#!/bin/bash # hmac.sh v1.1 November 15, 2014 # Copyright (c) 2014 Kenji Yoshino https://www.tidgubi.com # This script is released under the Version 3 of the GNU General Public # License https://www.gnu.org/licenses/gpl-3.0.txt # # This script implements a BASH and OpenSSL HMAC algorithm according to # http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf # This script is designed to work with 0.9.8 versions of OpenSSL that do no # support the '-mac' and '-macopts' parameters. function usage { printf 'hmac.sh sha1|sha256|sha512 key [-f file]\n' exit 1 } # hex2shell $hex [-r] # Converts $hex to shellcode. If $hex is not byte aligned, left-pad the data # unless -r is passed, in which case right pad the data function hex2shell { hex=$1 rtn='' if [[ $(( ${#hex} % 2 )) -eq 1 ]]; then if [[ "$2" = '-r' ]]; then hex="${hex}0" else hex="0$hex" fi fi ndx=0 while [ $ndx -lt ${#hex} ]; do rtn="$rtn\x${hex:$ndx:2}" (( ndx += 2 )) done echo $rtn } # xorHex $str1 $str2 [-r] # xors $str1 with $str2. Returns hex unless -r is passed. If -r is passed, raw # binary is returned. function xorHex { if [[ ${#1} -lt ${#2} ]]; then len=${#1} else len=${#2} fi local rtn='' ndx=0 while [ $ndx -lt $len ]; do if [[ "$3" = '-r' && $(( $ndx % 2 )) -eq 0 ]]; then rtn="$rtn\x" fi first="0x${1:$ndx:1}" second="0x${2:$ndx:1}" rtn="$rtn$( printf '%x' $((first ^ second)) )" (( ndx++ )) done printf "$rtn" } # hmac sha1|sha256|sha512 key [-f file] # key is a key in hex. If a file is specified with -f this will hmac the file. function hmac { block_size=0 # in number of nibbles (hex string length) case $1 in sha1) block_size=128 #512 bits ;; sha256) block_size=128 #512 bits ;; sha512) block_size=256 #1024 bits ;; *) usage ;; esac local key=${2#0x} if [[ ${#key} -gt $block_size ]]; then key=$( printf "$( hex2shell $key )" | openssl dgst -$1 ) key=${key##* } fi #pad the key with zeros and truncate to the correct length key="${key}0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" key="${key:0:$block_size}" # determine if the hmac will process a file or stdin if [[ "$3" = '-f' ]]; then if [[ "$4" = '-' ]]; then text='-' elif [[ -r "$4" ]]; then text="$4" else usage fi else text='-' fi ipad='3636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636' opad='5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c' # perform the actual hmac operation per FIPS 198-1 mac="$( openssl dgst -$1 <(xorHex $key $ipad -r; cat $text) )" mac="${mac##* }" mac="$( printf $(hex2shell $mac) | cat <( xorHex $key $opad -r ) - | openssl dgst -$1 )" printf "${mac##* }\n" } hmac $@ exit 0