Initial version of other 3rd-party s3 bash script.
[clinton/scripts.git] / s3-hmac
diff --git a/s3-hmac b/s3-hmac
new file mode 100755 (executable)
index 0000000..0cac6bf
--- /dev/null
+++ b/s3-hmac
@@ -0,0 +1,84 @@
+#!/bin/bash
+# Implement HMAC functionality on top of the OpenSSL digest functions.
+# licensed under the terms of the GNU GPL v2
+# Copyright 2007 Victor Lowther <victor.lowther@gmail.com>
+
+die() {
+  echo $*
+  exit 1
+}
+
+check_deps() {
+  local res=0
+  while [ $# -ne 0 ]; do 
+    which "${1}" >& /dev/null || { res=1; echo "${1} not found."; }
+    shift
+  done
+  (( res == 0 )) || die "aborting."
+}
+
+# write a byte (passed as hex) to stdout
+write_byte() {
+  # $1 = byte to write
+  printf "\\x$(printf "%x" ${1})"
+}
+
+# make an hmac pad out of a key.
+# this is not the most secure way of doing it, but it is 
+# the most expedient.
+make_hmac_pad() {
+  # using key in file $1 and byte in $2, create the appropriate hmac pad
+  # Pad keys out to $3 bytes
+  # if key is longer than $3, use hash $4 to hash the key first.
+  local x y a size remainder oifs
+  [[ -f ${1} ]] || die "${1} does not exist when making hmac pads."
+  (( remainder = ${3} ))
+  # in case someone else was messing with IFS.
+  for x in $(od -v -t u1 < "${1}"|cut -b 9-);
+  do
+    write_byte $((${x} ^ ${2}))
+    (( remainder -= 1 ))
+  done
+  for ((y=0; remainder - y ;y++)); do
+    write_byte $((0 ^ ${2}))
+  done
+}
+
+# utility functions for making hmac pads
+hmac_ipad() {
+  make_hmac_pad "${1}" 0x36 ${2} "${3}"
+}
+
+hmac_opad() {
+  make_hmac_pad "${1}" 0x5c ${2} "${3}"
+}
+
+# hmac something
+do_hmac() {
+  # $1 = algo to use.  Must be one that openssl knows about
+  # $2 = keyfile to use
+  # $3 = file to hash.  uses stdin if none is given.
+  # accepts input on stdin, leaves it on stdout.
+  # Output is binary, if you want something else pipe it accordingly.
+  local blocklen keysize x
+  case "${1}" in 
+    sha) blocklen=64 ;;
+    sha1) blocklen=64 ;;
+    md5) blocklen=64 ;;
+    md4) blocklen=64 ;;
+    sha256) blocklen=64 ;;
+    sha512) blocklen=128 ;;
+    *) die "Unknown hash ${1} passed to hmac!" ;;
+  esac
+  keysize="$(wc -c "${2}")"
+  (( ${keysize%%[!0-9 ]*} > blocklen )) && \
+    die "Prehashing large-size keys not implemented yet. Sorry."
+  cat <(hmac_ipad ${2} ${blocklen} "${1}") "${3:--}" | openssl dgst "-${1}" -binary | \
+  cat <(hmac_opad ${2} ${blocklen} "${1}") - | openssl dgst "-${1}" -binary 
+}
+
+[[ ${1} ]] || die "Must pass the name of the hash function to use to ${0}".
+
+[[ -f ${2} ]] || die "Must pass file containing the secret to $0"
+check_deps od openssl
+do_hmac "${@}"