HMAC-SHA1 in bash

BashSha1Hmac

Bash Problem Overview


Is there a bash script to generate a HMAC-SHA1 hash?

I'm looking for something equivalent to the following PHP code:

hash_hmac("sha1", "value", "key");

Bash Solutions


Solution 1 - Bash

I realise this isn't exactly what you're asking for, but there's no point in reinventing the wheel and writing a bash version.

You can simply use the openssl command to generate the hash within your script.

[me@home] echo -n "value" | openssl dgst -sha1 -hmac "key"
57443a4c052350a44638835d64fd66822f813319

Or simply:

[me@home] echo -n "value" | openssl sha1 -hmac "key"
57443a4c052350a44638835d64fd66822f813319

Remember to use -n with echo or else a line break character is appended to the string and that changes your data and the hash.

That command comes from the OpenSSL package which should already be installed (or easily installed) in your choice of Linux/Unix, Cygwin and the likes.

Do note that older versions of openssl (such as that shipped with RHEL4) may not provide the -hmac option.


As an alternative solution, but mainly to prove that the results are the same, we can also call PHP's hmac_sha1() from the command line:

[me@home]$ echo '<?= hash_hmac("sha1", "value", "key") ?>' | php
57443a4c052350a44638835d64fd66822f813319

Solution 2 - Bash

Here is a bash function that works like hash_hmac from PHP:

#!/bin/bash

function hash_hmac {
  digest="$1"
  data="$2"
  key="$3"
  shift 3
  echo -n "$data" | openssl dgst "-$digest" -hmac "$key" "$@"
}

# hex output by default
hash_hmac "sha1" "value" "key"

# raw output by adding the "-binary" flag
hash_hmac "sha1" "value" "key" -binary | base64

# other algos also work
hash_hmac "md5"  "value" "key"

Solution 3 - Bash

Thanks for the hash_hmac function! But it was not enough for my application. In case anyone wondered, I had to re-hash stuff several times using a key that was the result of the previous hashing, and therefore is a binary input. (The Amazon AWS authentication signature is created like this.)

So what I needed was a way to supply the binary key in some way that would not break the algorithm. Then I found this: http://openssl.6102.n7.nabble.com/command-line-hmac-with-key-in-hex-td6754.html

Stephen Henson's reply requires the hash_hmac function to return the value in hex format. So it needs to echo the following:

$ echo -n "$data" | openssl dgst "-$digest" -hmac "$key" | sed -e 's/^.* //'

Then the next call would need to provide the key as an hexit:

$ echo -n "$data" | openssl dgst "-$digest" -mac HMAC -macopt "hexkey:$key" | sed -e 's/^.* //'

Hopefully this helps anyone, probably someone who is trying to create bash scripts to invalidate CloudFront entries on AWS (like me!) (I haven't tested it yet, but I think this is the thing that is the cause of why my bash script does not work, and my PHP one does...)

Solution 4 - Bash

Having node.js installed you can use HMAC-CLI tool:

npx hmac-cli generate 'value' -h sha1 -s key

returns:

57443a4c052350a44638835d64fd66822f813319

Solution 5 - Bash

To those who like to explore more JWT on the command line: cool jwt bash script

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarkView Question on Stackoverflow
Solution 1 - BashShawn ChinView Answer on Stackoverflow
Solution 2 - BashMartinView Answer on Stackoverflow
Solution 3 - BashWouter ThielenView Answer on Stackoverflow
Solution 4 - BashTeriteView Answer on Stackoverflow
Solution 5 - BasheigenfieldView Answer on Stackoverflow