From a5263c7caa61eb9eedfd6c15e3c1f989d5490ef9 Mon Sep 17 00:00:00 2001 From: Luit van Drongelen Date: Wed, 18 Jan 2012 10:36:28 -0500 Subject: [PATCH] crypto/hmac: Add HMAC-SHA224 and HMAC-SHA384/512 First was, apart from adding tests, a single line of code (to add the constructor function). Adding SHA512-based hashing to crypto/hmac required minor rework of the package because of a previously hardcoded block-size in it's implementation. Instead of using a hash.Hash generator function the constructor function now uses a crypto.Hash type, which was extended to expose information about block size. The only standard library package impacted by the change is crypto/tls, for which the fix is included in this patch. It might be useful to extend gofix to include this API change too. R=agl, r, rsc, r CC=golang-dev https://golang.org/cl/5550043 --- src/pkg/crypto/hmac/hmac.go | 32 +- src/pkg/crypto/hmac/hmac_test.go | 312 +++++++++++++++++- src/pkg/crypto/md4/md4.go | 5 + src/pkg/crypto/md5/md5.go | 5 + src/pkg/crypto/openpgp/canonical_text.go | 4 + src/pkg/crypto/openpgp/canonical_text_test.go | 4 + src/pkg/crypto/ripemd160/ripemd160.go | 2 + src/pkg/crypto/sha1/sha1.go | 5 + src/pkg/crypto/sha256/sha256.go | 5 + src/pkg/crypto/sha512/sha512.go | 5 + src/pkg/exp/ssh/transport.go | 2 + src/pkg/hash/adler32/adler32.go | 2 + src/pkg/hash/crc32/crc32.go | 2 + src/pkg/hash/crc64/crc64.go | 2 + src/pkg/hash/fnv/fnv.go | 5 + src/pkg/hash/hash.go | 6 + 16 files changed, 367 insertions(+), 31 deletions(-) diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go index 6e7dd8762c..6bdbbb4030 100644 --- a/src/pkg/crypto/hmac/hmac.go +++ b/src/pkg/crypto/hmac/hmac.go @@ -18,23 +18,14 @@ import ( // FIPS 198: // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf -// key is zero padded to 64 bytes -// ipad = 0x36 byte repeated to 64 bytes -// opad = 0x5c byte repeated to 64 bytes +// key is zero padded to the block size of the hash function +// ipad = 0x36 byte repeated for key length +// opad = 0x5c byte repeated for key length // hmac = H([key ^ opad] H([key ^ ipad] text)) -const ( - // NOTE(rsc): This constant is actually the - // underlying hash function's block size. - // HMAC is only conventionally used with - // MD5 and SHA1, and both use 64-byte blocks. - // The hash.Hash interface doesn't provide a - // way to find out the block size. - padSize = 64 -) - type hmac struct { size int + blocksize int key, tmp []byte outer, inner hash.Hash } @@ -43,7 +34,7 @@ func (h *hmac) tmpPad(xor byte) { for i, k := range h.key { h.tmp[i] = xor ^ k } - for i := len(h.key); i < padSize; i++ { + for i := len(h.key); i < h.blocksize; i++ { h.tmp[i] = xor } } @@ -52,7 +43,7 @@ func (h *hmac) Sum(in []byte) []byte { origLen := len(in) in = h.inner.Sum(in) h.tmpPad(0x5c) - copy(h.tmp[padSize:], in[origLen:]) + copy(h.tmp[h.blocksize:], in[origLen:]) h.outer.Reset() h.outer.Write(h.tmp) return h.outer.Sum(in[:origLen]) @@ -64,20 +55,23 @@ func (h *hmac) Write(p []byte) (n int, err error) { func (h *hmac) Size() int { return h.size } +func (h *hmac) BlockSize() int { return h.blocksize } + func (h *hmac) Reset() { h.inner.Reset() h.tmpPad(0x36) - h.inner.Write(h.tmp[0:padSize]) + h.inner.Write(h.tmp[0:h.blocksize]) } -// New returns a new HMAC hash using the given hash generator and key. +// New returns a new HMAC hash using the given crypto.Hash type and key. func New(h func() hash.Hash, key []byte) hash.Hash { hm := new(hmac) hm.outer = h() hm.inner = h() hm.size = hm.inner.Size() - hm.tmp = make([]byte, padSize+hm.size) - if len(key) > padSize { + hm.blocksize = hm.inner.BlockSize() + hm.tmp = make([]byte, hm.blocksize+hm.size) + if len(key) > hm.blocksize { // If key is too big, hash it. hm.outer.Write(key) key = hm.outer.Sum(nil) diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go index eac254b9d1..07957414c8 100644 --- a/src/pkg/crypto/hmac/hmac_test.go +++ b/src/pkg/crypto/hmac/hmac_test.go @@ -5,13 +5,17 @@ package hmac import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" "fmt" "hash" "testing" ) type hmacTest struct { - hash func([]byte) hash.Hash + hash func() hash.Hash key []byte in []byte out string @@ -21,7 +25,7 @@ var hmacTests = []hmacTest{ // Tests from US FIPS 198 // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf { - NewSHA1, + sha1.New, []byte{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -36,7 +40,7 @@ var hmacTests = []hmacTest{ "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a", }, { - NewSHA1, + sha1.New, []byte{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, @@ -46,7 +50,7 @@ var hmacTests = []hmacTest{ "0922d3405faa3d194f82a45830737d5cc6c75d24", }, { - NewSHA1, + sha1.New, []byte{ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, @@ -68,7 +72,7 @@ var hmacTests = []hmacTest{ // Test from Plan 9. { - NewMD5, + md5.New, []byte("Jefe"), []byte("what do ya want for nothing?"), "750c783e6ab0b503eaa86e310a5db738", @@ -76,7 +80,7 @@ var hmacTests = []hmacTest{ // Tests from RFC 4231 { - NewSHA256, + sha256.New, []byte{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, @@ -86,13 +90,13 @@ var hmacTests = []hmacTest{ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", }, { - NewSHA256, + sha256.New, []byte("Jefe"), []byte("what do ya want for nothing?"), "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -110,7 +114,7 @@ var hmacTests = []hmacTest{ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", }, { - NewSHA256, + sha256.New, []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, @@ -129,7 +133,7 @@ var hmacTests = []hmacTest{ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -153,7 +157,7 @@ var hmacTests = []hmacTest{ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -178,11 +182,295 @@ var hmacTests = []hmacTest{ "be hashed before being used by the HMAC algorithm."), "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", }, + + // Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html + // (truncated tag tests are left out) + { + sha1.New, + []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + []byte("Sample message for keylen=blocklen"), + "5fd596ee78d5553c8ff4e72d266dfd192366da29", + }, + { + sha1.New, + []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + }, + []byte("Sample message for keylen>24)) diff --git a/src/pkg/hash/hash.go b/src/pkg/hash/hash.go index 8598f4e1b8..aa895cf984 100644 --- a/src/pkg/hash/hash.go +++ b/src/pkg/hash/hash.go @@ -22,6 +22,12 @@ type Hash interface { // Size returns the number of bytes Sum will return. Size() int + + // BlockSize returns the hash's underlying block size. + // The Write method must be able to accept any amount + // of data, but it may operate more efficiently if all writes + // are a multiple of the block size. + BlockSize() int } // Hash32 is the common interface implemented by all 32-bit hash functions. -- 2.50.0