This is something i never thought i’d need to know or care to find out: the maximum size of an HMAC SHA256
key is capped at 64bytes
.
Anything larger than that key is hashed back to 64 bytes; anything smaller is padded.
This is actually just documentation right here in the wiki page for HMAC and you can see it in language bindings like
if len(key) > blocksize {
// If key is too big, hash it.
hm.outer.Write(key)
key = hm.outer.Sum(nil)
}
or in dotnet
The secret key for HMACSHA256 encryption. The key can be any length. However, the recommended size is 64 bytes. If the key is more than 64 bytes long, it is hashed (using SHA-256) to derive a 64-byte key. If it is less than 64 bytes long, it is padded to 64 bytes.
sure, for academic reasons i’ll just use openssl
and a bit of inference.
Lets pick some sample text and generate a key of exactly 64bytes
and calculate its mac
echo -n "foo" > data.txt
# 64 bytes (hex)
# export RAW_KEY=`openssl rand -hex 32`
export RAW_KEY=e2c6c78e079ca23ac0d37fbbc0ae36a2d5c0f0c7186e70fbd6a964e60444a0de
openssl dgst -sha256 -mac hmac -macopt key:$RAW_KEY data.txt
HMAC-SHA256(data.txt)= 941b8178bd275e41f98a372679ef066220ff5e0ed470633390038f9ef49d1233
Now just hash that and recalculate the mac….you’ll see its different…thats totally reasonable: the secret key is different
HASHED_HEX_RAW_KEY=`echo -n $RAW_KEY | openssl dgst -sha256 | awk '{print $2}'`
openssl dgst -sha256 -mac hmac -macopt hexkey:$HASHED_HEX_RAW_KEY data.txt
HMAC-SHA256(data.txt)= 388d4c0d8d87da9aa332f0dd2f25d40239df692d150855db65d5b4e77f4c5d6a
ok, what does that prove? nothing but see what happens when try 65bytes
Create a key of 65bytes
(well…66
) and calculate mac
# 65 bytes
# export RAW_KEY=`openssl rand -hex 33`
export RAW_KEY=892982ea016645e04b0436ce49221e4e16e7ff250ce1c93210bf9d5c504da845ae
openssl dgst -sha256 -mac hmac -macopt key:$RAW_KEY data.txt
HMAC-SHA256(data.txt)= 3fd1fc902c63fd3017d113b9e0c9d7918439a30bc9409d8605caad7b2b3a9c7f
Now hash the key and look at the calculated mac
HASHED_HEX_RAW_KEY=`echo -n $RAW_KEY | openssl dgst -sha256 | awk '{print $2}'`
openssl dgst -sha256 -mac hmac -macopt hexkey:$HASHED_HEX_RAW_KEY data.txt
HMAC-SHA256(data.txt)= 3fd1fc902c63fd3017d113b9e0c9d7918439a30bc9409d8605caad7b2b3a9c7f
Wow!..they’re the same…openssl
must be using the hashed key internally for keysize>64bytes
this isn’t precisely Q.E.D but its sufficient for me…(yes, thats the first time i got to use that since boarding school math class)
Now…why do you even care to know this…
Well, i found out that Google Cloud KMS
now support HMAC key import.
What i wanted to do is to import an AWS Secret Access Key into Cloud KMS.
Once imported, i could securely use GCP KMS to access AWS Resources.
How? well, its a trick i used to to make AWS HMAC signing work with Trusted Platform Modules
and PKCS-11
devices.
Essentially, you’re saving the aws secret into hardware and making the hardware help create the AWS signed request. IMO, it think thats neat if i have to say so!!
For more info see
Coming back to the limits, it took me a long to notice that the HMAC key import limit for Google KMS is…32bytes
. period.
Symmetric keys for signing (MAC keys) must have length equal to the output length of the cryptographic hash function being used (e.g. HMAC-SHA256 keys must have a length of 32 bytes), and must not be encoded. If your key is hex-encoded or base-64 encoded, you must decode it before attempting to import it.
and my AWS key was…44bytes
which is still pefectly valid.
44 bytes (AWS4HMrL6cNwJCNQzRX8R33mto/jiKM/6AO123456789)
meaning…i’m stuck now due to a support in GCP KMS :(.
My usecase is academic (i just wanted to see this work for security reasons)…if you (as a reader, maybe customer) need this, please contact your google support teams!
ref:
Just a sample in go for hmac-sha256
to compare with the openssl commands above
main.go
package main
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
"io"
)
func main() {
h := hmac.New(sha256.New, []byte("892982ea016645e04b0436ce49221e4e16e7ff250ce1c93210bf9d5c504da845ae"))
io.WriteString(h, "foo")
fmt.Printf("%x", h.Sum(nil))
}
This site supports webmentions. Send me a mention via this form.