Clojure SHA256 HMAC function not producing expected results
Asked Answered
G

1

5

I have the following Clojure code:

(ns myproject.hmac-sha256
    (:import (javax.crypto Mac)
             (javax.crypto.spec SecretKeySpec)))

(defn secretKeyInst [key mac]
    (SecretKeySpec. (.getBytes key) (.getAlgorithm mac)))

(defn toString [bytes]
    "Convert bytes to a String"
    (String. bytes "UTF-8"))

(defn sign [key string]
    "Returns the signature of a string with a given 
    key, using a SHA-256 HMAC."
    (let [mac (Mac/getInstance "HMACSHA256")
          secretKey (secretKeyInst key mac)]
          (-> (doto mac
                (.init secretKey)
                (.update (.getBytes "UTF-8")))
              .doFinal
              toString)))

When I use the sign function in the REPL, strange glyphs are output:

(sign "key" "The quick brown fox jumps over the lazy dog")
"*��`��n�S�F�|�؏�o�r���"

whereas I was expecting f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 as per https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256.29

This is doubtless a string encoding issue, but I don't really know much about encoding. Can anyone help?

Gowrie answered 15/3, 2013 at 23:36 Comment(0)
B
9

To put the output into a format that can be compared with the examples don't call the toString defined above, instead treat the result of .doFinal as a byte array and print it in hex. The example above is signing the string "UTF-8" instead of the input string:

 (defn sign [key string]
  "Returns the signature of a string with a given
    key, using a SHA-256 HMAC."
  (let [mac (Mac/getInstance "HMACSHA256")
        secretKey (secretKeyInst key mac)]
    (-> (doto mac
          (.init secretKey)
          (.update (.getBytes string)))
        .doFinal)))

myproject.hmac-sha256>  (apply str (map #(format "%x" %) (sign "key" "The quick brown fox jumps over the lazy dog")))
"f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"

you could then write the toString function as something like:

(defn toHexString [bytes]
  "Convert bytes to a String"
  (apply str (map #(format "%x" %) bytes)))
Bozo answered 16/3, 2013 at 0:14 Comment(1)
Check the actual bytes produced by .getBytes, and which padding is used.Beaulahbeaulieu

© 2022 - 2024 — McMap. All rights reserved.