diff --git a/cng/sha.go b/cng/hash.go similarity index 56% rename from cng/sha.go rename to cng/hash.go index 78704dd..d894c07 100644 --- a/cng/sha.go +++ b/cng/hash.go @@ -18,120 +18,144 @@ import ( // SupportsHash returns true if a hash.Hash implementation is supported for h. func SupportsHash(h crypto.Hash) bool { switch h { - case crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512: + case crypto.MD4, crypto.MD5, crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512: return true case crypto.SHA3_256: - _, err := loadSha(bcrypt.SHA3_256_ALGORITHM, bcrypt.ALG_NONE_FLAG) + _, err := loadHash(bcrypt.SHA3_256_ALGORITHM, bcrypt.ALG_NONE_FLAG) return err == nil case crypto.SHA3_384: - _, err := loadSha(bcrypt.SHA3_384_ALGORITHM, bcrypt.ALG_NONE_FLAG) + _, err := loadHash(bcrypt.SHA3_384_ALGORITHM, bcrypt.ALG_NONE_FLAG) return err == nil case crypto.SHA3_512: - _, err := loadSha(bcrypt.SHA3_512_ALGORITHM, bcrypt.ALG_NONE_FLAG) + _, err := loadHash(bcrypt.SHA3_512_ALGORITHM, bcrypt.ALG_NONE_FLAG) return err == nil } return false } -func shaOneShot(id string, p, sum []byte) error { - h, err := loadSha(id, 0) +func hashOneShot(id string, p, sum []byte) error { + h, err := loadHash(id, 0) if err != nil { return err } return bcrypt.Hash(h.handle, nil, p, sum) } +func MD4(p []byte) (sum [16]byte) { + if err := hashOneShot(bcrypt.MD4_ALGORITHM, p, sum[:]); err != nil { + panic("bcrypt: MD4 failed") + } + return +} + +func MD5(p []byte) (sum [16]byte) { + if err := hashOneShot(bcrypt.MD5_ALGORITHM, p, sum[:]); err != nil { + panic("bcrypt: MD5 failed") + } + return +} + func SHA1(p []byte) (sum [20]byte) { - if err := shaOneShot(bcrypt.SHA1_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA1_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA1 failed") } return } func SHA256(p []byte) (sum [32]byte) { - if err := shaOneShot(bcrypt.SHA256_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA256_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA256 failed") } return } func SHA384(p []byte) (sum [48]byte) { - if err := shaOneShot(bcrypt.SHA384_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA384_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA384 failed") } return } func SHA512(p []byte) (sum [64]byte) { - if err := shaOneShot(bcrypt.SHA512_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA512_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA512 failed") } return } func SHA3_256(p []byte) (sum [32]byte) { - if err := shaOneShot(bcrypt.SHA3_256_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA3_256_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA3_256 failed") } return } func SHA3_384(p []byte) (sum [48]byte) { - if err := shaOneShot(bcrypt.SHA3_384_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA3_384_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA3_384 failed") } return } func SHA3_512(p []byte) (sum [64]byte) { - if err := shaOneShot(bcrypt.SHA3_512_ALGORITHM, p, sum[:]); err != nil { + if err := hashOneShot(bcrypt.SHA3_512_ALGORITHM, p, sum[:]); err != nil { panic("bcrypt: SHA3_512 failed") } return } +// NewMD4 returns a new MD4 hash. +func NewMD4() hash.Hash { + return newHashX(bcrypt.MD4_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) +} + +// NewMD5 returns a new MD5 hash. +func NewMD5() hash.Hash { + return newHashX(bcrypt.MD5_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) +} + // NewSHA1 returns a new SHA1 hash. func NewSHA1() hash.Hash { - return newSHAX(bcrypt.SHA1_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA1_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA256 returns a new SHA256 hash. func NewSHA256() hash.Hash { - return newSHAX(bcrypt.SHA256_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA256_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA384 returns a new SHA384 hash. func NewSHA384() hash.Hash { - return newSHAX(bcrypt.SHA384_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA384_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA512 returns a new SHA512 hash. func NewSHA512() hash.Hash { - return newSHAX(bcrypt.SHA512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA3_256 returns a new SHA256 hash. func NewSHA3_256() hash.Hash { - return newSHAX(bcrypt.SHA3_256_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA3_256_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA3_384 returns a new SHA384 hash. func NewSHA3_384() hash.Hash { - return newSHAX(bcrypt.SHA3_384_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA3_384_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } // NewSHA3_512 returns a new SHA512 hash. func NewSHA3_512() hash.Hash { - return newSHAX(bcrypt.SHA3_512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) + return newHashX(bcrypt.SHA3_512_ALGORITHM, bcrypt.ALG_NONE_FLAG, nil) } -type shaAlgorithm struct { +type hashAlgorithm struct { handle bcrypt.ALG_HANDLE size uint32 blockSize uint32 } -func loadSha(id string, flags bcrypt.AlgorithmProviderFlags) (shaAlgorithm, error) { +func loadHash(id string, flags bcrypt.AlgorithmProviderFlags) (hashAlgorithm, error) { v, err := loadOrStoreAlg(id, flags, "", func(h bcrypt.ALG_HANDLE) (interface{}, error) { size, err := getUint32(bcrypt.HANDLE(h), bcrypt.HASH_LENGTH) if err != nil { @@ -141,15 +165,15 @@ func loadSha(id string, flags bcrypt.AlgorithmProviderFlags) (shaAlgorithm, erro if err != nil { return nil, err } - return shaAlgorithm{h, size, blockSize}, nil + return hashAlgorithm{h, size, blockSize}, nil }) if err != nil { - return shaAlgorithm{}, err + return hashAlgorithm{}, err } - return v.(shaAlgorithm), nil + return v.(hashAlgorithm), nil } -type shaXHash struct { +type hashX struct { h bcrypt.ALG_HANDLE ctx bcrypt.HASH_HANDLE size int @@ -158,33 +182,33 @@ type shaXHash struct { key []byte } -func newSHAX(id string, flag bcrypt.AlgorithmProviderFlags, key []byte) *shaXHash { - h, err := loadSha(id, flag) +func newHashX(id string, flag bcrypt.AlgorithmProviderFlags, key []byte) *hashX { + h, err := loadHash(id, flag) if err != nil { panic(err) } - sha := new(shaXHash) - sha.h = h.handle - sha.size = int(h.size) - sha.blockSize = int(h.blockSize) - sha.buf = make([]byte, sha.size) + hx := new(hashX) + hx.h = h.handle + hx.size = int(h.size) + hx.blockSize = int(h.blockSize) + hx.buf = make([]byte, hx.size) if len(key) > 0 { - sha.key = make([]byte, len(key)) - copy(sha.key, key) + hx.key = make([]byte, len(key)) + copy(hx.key, key) } - sha.Reset() - runtime.SetFinalizer(sha, (*shaXHash).finalize) - return sha + hx.Reset() + runtime.SetFinalizer(hx, (*hashX).finalize) + return hx } -func (h *shaXHash) finalize() { +func (h *hashX) finalize() { if h.ctx != 0 { bcrypt.DestroyHash(h.ctx) } } -func (h *shaXHash) Clone() (hash.Hash, error) { - h2 := &shaXHash{ +func (h *hashX) Clone() (hash.Hash, error) { + h2 := &hashX{ h: h.h, size: h.size, blockSize: h.blockSize, @@ -196,12 +220,12 @@ func (h *shaXHash) Clone() (hash.Hash, error) { if err != nil { return nil, err } - runtime.SetFinalizer(h2, (*shaXHash).finalize) + runtime.SetFinalizer(h2, (*hashX).finalize) runtime.KeepAlive(h) return h2, nil } -func (h *shaXHash) Reset() { +func (h *hashX) Reset() { if h.ctx != 0 { bcrypt.DestroyHash(h.ctx) h.ctx = 0 @@ -213,7 +237,7 @@ func (h *shaXHash) Reset() { runtime.KeepAlive(h) } -func (h *shaXHash) Write(p []byte) (n int, err error) { +func (h *hashX) Write(p []byte) (n int, err error) { for n < len(p) && err == nil { nn := len32(p[n:]) err = bcrypt.HashData(h.ctx, p[n:n+nn], 0) @@ -227,7 +251,7 @@ func (h *shaXHash) Write(p []byte) (n int, err error) { return len(p), nil } -func (h *shaXHash) WriteString(s string) (int, error) { +func (h *hashX) WriteString(s string) (int, error) { // TODO: use unsafe.StringData once we drop support // for go1.19 and earlier. hdr := (*struct { @@ -237,7 +261,7 @@ func (h *shaXHash) WriteString(s string) (int, error) { return h.Write(unsafe.Slice(hdr.Data, len(s))) } -func (h *shaXHash) WriteByte(c byte) error { +func (h *hashX) WriteByte(c byte) error { if err := bcrypt.HashDataRaw(h.ctx, &c, 1, 0); err != nil { // hash.Hash interface mandates Write should never return an error. panic(err) @@ -246,20 +270,20 @@ func (h *shaXHash) WriteByte(c byte) error { return nil } -func (h *shaXHash) Size() int { +func (h *hashX) Size() int { return h.size } -func (h *shaXHash) BlockSize() int { +func (h *hashX) BlockSize() int { return h.blockSize } -func (h *shaXHash) Sum(in []byte) []byte { +func (h *hashX) Sum(in []byte) []byte { h.sum(h.buf) return append(in, h.buf...) } -func (h *shaXHash) sum(out []byte) { +func (h *hashX) sum(out []byte) { var ctx2 bcrypt.HASH_HANDLE err := bcrypt.DuplicateHash(h.ctx, &ctx2, nil, 0) if err != nil { diff --git a/cng/sha_test.go b/cng/hash_test.go similarity index 91% rename from cng/sha_test.go rename to cng/hash_test.go index c996347..182a90f 100644 --- a/cng/sha_test.go +++ b/cng/hash_test.go @@ -18,6 +18,10 @@ import ( func cryptoToHash(h crypto.Hash) func() hash.Hash { switch h { + case crypto.MD4: + return cng.NewMD4 + case crypto.MD5: + return cng.NewMD5 case crypto.SHA1: return cng.NewSHA1 case crypto.SHA256: @@ -36,9 +40,11 @@ func cryptoToHash(h crypto.Hash) func() hash.Hash { return nil } -func TestSha(t *testing.T) { +func TestHash(t *testing.T) { msg := []byte("testing") var tests = []crypto.Hash{ + crypto.MD4, + crypto.MD5, crypto.SHA1, crypto.SHA224, crypto.SHA256, @@ -106,12 +112,20 @@ func TestSha(t *testing.T) { } } -func TestSHA_OneShot(t *testing.T) { +func TestHash_OneShot(t *testing.T) { msg := []byte("testing") var tests = []struct { h crypto.Hash oneShot func([]byte) []byte }{ + {crypto.MD4, func(p []byte) []byte { + b := cng.MD4(p) + return b[:] + }}, + {crypto.MD5, func(p []byte) []byte { + b := cng.MD5(p) + return b[:] + }}, {crypto.SHA1, func(p []byte) []byte { b := cng.SHA1(p) return b[:] diff --git a/cng/hmac.go b/cng/hmac.go index 736472d..76a80ce 100644 --- a/cng/hmac.go +++ b/cng/hmac.go @@ -15,7 +15,7 @@ import ( // hashToID converts a hash.Hash implementation from this package // to a CNG hash ID func hashToID(h hash.Hash) string { - if _, ok := h.(*shaXHash); !ok { + if _, ok := h.(*hashX); !ok { return "" } var id string @@ -51,5 +51,5 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { ch.Write(key) key = ch.Sum(nil) } - return newSHAX(id, bcrypt.ALG_HANDLE_HMAC_FLAG, key) + return newHashX(id, bcrypt.ALG_HANDLE_HMAC_FLAG, key) } diff --git a/internal/bcrypt/bcrypt_windows.go b/internal/bcrypt/bcrypt_windows.go index 1a7f44a..69ce980 100644 --- a/internal/bcrypt/bcrypt_windows.go +++ b/internal/bcrypt/bcrypt_windows.go @@ -20,6 +20,7 @@ const ( SHA3_512_ALGORITHM = "SHA3-512" AES_ALGORITHM = "AES" RSA_ALGORITHM = "RSA" + MD4_ALGORITHM = "MD4" MD5_ALGORITHM = "MD5" ECDSA_ALGORITHM = "ECDSA" ECDH_ALGORITHM = "ECDH"