Commit a5263c7c authored by Luit van Drongelen's avatar Luit van Drongelen Committed by Russ Cox

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
parent 18ee75ec
...@@ -18,23 +18,14 @@ import ( ...@@ -18,23 +18,14 @@ import (
// FIPS 198: // FIPS 198:
// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
// key is zero padded to 64 bytes // key is zero padded to the block size of the hash function
// ipad = 0x36 byte repeated to 64 bytes // ipad = 0x36 byte repeated for key length
// opad = 0x5c byte repeated to 64 bytes // opad = 0x5c byte repeated for key length
// hmac = H([key ^ opad] H([key ^ ipad] text)) // 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 { type hmac struct {
size int size int
blocksize int
key, tmp []byte key, tmp []byte
outer, inner hash.Hash outer, inner hash.Hash
} }
...@@ -43,7 +34,7 @@ func (h *hmac) tmpPad(xor byte) { ...@@ -43,7 +34,7 @@ func (h *hmac) tmpPad(xor byte) {
for i, k := range h.key { for i, k := range h.key {
h.tmp[i] = xor ^ k 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 h.tmp[i] = xor
} }
} }
...@@ -52,7 +43,7 @@ func (h *hmac) Sum(in []byte) []byte { ...@@ -52,7 +43,7 @@ func (h *hmac) Sum(in []byte) []byte {
origLen := len(in) origLen := len(in)
in = h.inner.Sum(in) in = h.inner.Sum(in)
h.tmpPad(0x5c) h.tmpPad(0x5c)
copy(h.tmp[padSize:], in[origLen:]) copy(h.tmp[h.blocksize:], in[origLen:])
h.outer.Reset() h.outer.Reset()
h.outer.Write(h.tmp) h.outer.Write(h.tmp)
return h.outer.Sum(in[:origLen]) return h.outer.Sum(in[:origLen])
...@@ -64,20 +55,23 @@ func (h *hmac) Write(p []byte) (n int, err error) { ...@@ -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) Size() int { return h.size }
func (h *hmac) BlockSize() int { return h.blocksize }
func (h *hmac) Reset() { func (h *hmac) Reset() {
h.inner.Reset() h.inner.Reset()
h.tmpPad(0x36) 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 { func New(h func() hash.Hash, key []byte) hash.Hash {
hm := new(hmac) hm := new(hmac)
hm.outer = h() hm.outer = h()
hm.inner = h() hm.inner = h()
hm.size = hm.inner.Size() hm.size = hm.inner.Size()
hm.tmp = make([]byte, padSize+hm.size) hm.blocksize = hm.inner.BlockSize()
if len(key) > padSize { hm.tmp = make([]byte, hm.blocksize+hm.size)
if len(key) > hm.blocksize {
// If key is too big, hash it. // If key is too big, hash it.
hm.outer.Write(key) hm.outer.Write(key)
key = hm.outer.Sum(nil) key = hm.outer.Sum(nil)
......
This diff is collapsed.
...@@ -17,6 +17,9 @@ func init() { ...@@ -17,6 +17,9 @@ func init() {
// The size of an MD4 checksum in bytes. // The size of an MD4 checksum in bytes.
const Size = 16 const Size = 16
// The blocksize of MD4 in bytes.
const BlockSize = 64
const ( const (
_Chunk = 64 _Chunk = 64
_Init0 = 0x67452301 _Init0 = 0x67452301
...@@ -51,6 +54,8 @@ func New() hash.Hash { ...@@ -51,6 +54,8 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.len += uint64(nn) d.len += uint64(nn)
......
...@@ -17,6 +17,9 @@ func init() { ...@@ -17,6 +17,9 @@ func init() {
// The size of an MD5 checksum in bytes. // The size of an MD5 checksum in bytes.
const Size = 16 const Size = 16
// The blocksize of MD5 in bytes.
const BlockSize = 64
const ( const (
_Chunk = 64 _Chunk = 64
_Init0 = 0x67452301 _Init0 = 0x67452301
...@@ -51,6 +54,8 @@ func New() hash.Hash { ...@@ -51,6 +54,8 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.len += uint64(nn) d.len += uint64(nn)
......
...@@ -53,3 +53,7 @@ func (cth *canonicalTextHash) Reset() { ...@@ -53,3 +53,7 @@ func (cth *canonicalTextHash) Reset() {
func (cth *canonicalTextHash) Size() int { func (cth *canonicalTextHash) Size() int {
return cth.h.Size() return cth.h.Size()
} }
func (cth *canonicalTextHash) BlockSize() int {
return cth.h.BlockSize()
}
...@@ -29,6 +29,10 @@ func (r recordingHash) Size() int { ...@@ -29,6 +29,10 @@ func (r recordingHash) Size() int {
panic("shouldn't be called") panic("shouldn't be called")
} }
func (r recordingHash) BlockSize() int {
panic("shouldn't be called")
}
func testCanonicalText(t *testing.T, input, expected string) { func testCanonicalText(t *testing.T, input, expected string) {
r := recordingHash{bytes.NewBuffer(nil)} r := recordingHash{bytes.NewBuffer(nil)}
c := NewCanonicalTextHash(r) c := NewCanonicalTextHash(r)
......
...@@ -55,6 +55,8 @@ func New() hash.Hash { ...@@ -55,6 +55,8 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.tc += uint64(nn) d.tc += uint64(nn)
......
...@@ -17,6 +17,9 @@ func init() { ...@@ -17,6 +17,9 @@ func init() {
// The size of a SHA1 checksum in bytes. // The size of a SHA1 checksum in bytes.
const Size = 20 const Size = 20
// The blocksize of SHA1 in bytes.
const BlockSize = 64
const ( const (
_Chunk = 64 _Chunk = 64
_Init0 = 0x67452301 _Init0 = 0x67452301
...@@ -53,6 +56,8 @@ func New() hash.Hash { ...@@ -53,6 +56,8 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.len += uint64(nn) d.len += uint64(nn)
......
...@@ -22,6 +22,9 @@ const Size = 32 ...@@ -22,6 +22,9 @@ const Size = 32
// The size of a SHA224 checksum in bytes. // The size of a SHA224 checksum in bytes.
const Size224 = 28 const Size224 = 28
// The blocksize of SHA256 and SHA224 in bytes.
const BlockSize = 64
const ( const (
_Chunk = 64 _Chunk = 64
_Init0 = 0x6A09E667 _Init0 = 0x6A09E667
...@@ -97,6 +100,8 @@ func (d *digest) Size() int { ...@@ -97,6 +100,8 @@ func (d *digest) Size() int {
return Size224 return Size224
} }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.len += uint64(nn) d.len += uint64(nn)
......
...@@ -22,6 +22,9 @@ const Size = 64 ...@@ -22,6 +22,9 @@ const Size = 64
// The size of a SHA384 checksum in bytes. // The size of a SHA384 checksum in bytes.
const Size384 = 48 const Size384 = 48
// The blocksize of SHA512 and SHA384 in bytes.
const BlockSize = 128
const ( const (
_Chunk = 128 _Chunk = 128
_Init0 = 0x6a09e667f3bcc908 _Init0 = 0x6a09e667f3bcc908
...@@ -97,6 +100,8 @@ func (d *digest) Size() int { ...@@ -97,6 +100,8 @@ func (d *digest) Size() int {
return Size384 return Size384
} }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p) nn = len(p)
d.len += uint64(nn) d.len += uint64(nn)
......
...@@ -328,6 +328,8 @@ func (t truncatingMAC) Size() int { ...@@ -328,6 +328,8 @@ func (t truncatingMAC) Size() int {
return t.length return t.length
} }
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
// maxVersionStringBytes is the maximum number of bytes that we'll accept as a // maxVersionStringBytes is the maximum number of bytes that we'll accept as a
// version string. In the event that the client is talking a different protocol // version string. In the event that the client is talking a different protocol
// we need to set a limit otherwise we will keep using more and more memory // we need to set a limit otherwise we will keep using more and more memory
......
...@@ -38,6 +38,8 @@ func New() hash.Hash32 { ...@@ -38,6 +38,8 @@ func New() hash.Hash32 {
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return 1 }
// Add p to the running checksum a, b. // Add p to the running checksum a, b.
func update(a, b uint32, p []byte) (aa, bb uint32) { func update(a, b uint32, p []byte) (aa, bb uint32) {
for _, pi := range p { for _, pi := range p {
......
...@@ -94,6 +94,8 @@ func NewIEEE() hash.Hash32 { return New(IEEETable) } ...@@ -94,6 +94,8 @@ func NewIEEE() hash.Hash32 { return New(IEEETable) }
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { d.crc = 0 } func (d *digest) Reset() { d.crc = 0 }
func update(crc uint32, tab *Table, p []byte) uint32 { func update(crc uint32, tab *Table, p []byte) uint32 {
......
...@@ -53,6 +53,8 @@ func New(tab *Table) hash.Hash64 { return &digest{0, tab} } ...@@ -53,6 +53,8 @@ func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
func (d *digest) Size() int { return Size } func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { d.crc = 0 } func (d *digest) Reset() { d.crc = 0 }
func update(crc uint64, tab *Table, p []byte) uint64 { func update(crc uint64, tab *Table, p []byte) uint64 {
......
...@@ -104,6 +104,11 @@ func (s *sum32a) Size() int { return 4 } ...@@ -104,6 +104,11 @@ func (s *sum32a) Size() int { return 4 }
func (s *sum64) Size() int { return 8 } func (s *sum64) Size() int { return 8 }
func (s *sum64a) Size() int { return 8 } func (s *sum64a) Size() int { return 8 }
func (s *sum32) BlockSize() int { return 1 }
func (s *sum32a) BlockSize() int { return 1 }
func (s *sum64) BlockSize() int { return 1 }
func (s *sum64a) BlockSize() int { return 1 }
func (s *sum32) Sum(in []byte) []byte { func (s *sum32) Sum(in []byte) []byte {
v := uint32(*s) v := uint32(*s)
in = append(in, byte(v>>24)) in = append(in, byte(v>>24))
......
...@@ -22,6 +22,12 @@ type Hash interface { ...@@ -22,6 +22,12 @@ type Hash interface {
// Size returns the number of bytes Sum will return. // Size returns the number of bytes Sum will return.
Size() int 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. // Hash32 is the common interface implemented by all 32-bit hash functions.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment