crypto/hmac: Deprecate hmac.NewMD5, hmac.NewSHA1 and hmac.NewSHA256

Remove NewMD5, NewSHA1 and NewSHA256 in favor of using New and
explicitly importing the used hash-function. This way when using, for
example, HMAC with RIPEMD there's no md5, sha1 and sha256 linked in
through the hmac package.

A gofix rule is included, and applied to the standard library (3 files
altered).

This change is the result of a discussion at
https://golang.org/cl/5550043/ to pull the discussion about
deprecating these functions out of that issue.

R=golang-dev, agl
CC=golang-dev, r, rsc
https://golang.org/cl/5556058
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index a00ec34..1aabd19 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -12,6 +12,7 @@
 	go1pkgrename.go\
 	googlecode.go\
 	hashsum.go\
+	hmacnew.go\
 	htmlerr.go\
 	httpfinalurl.go\
 	httpfs.go\
diff --git a/src/cmd/gofix/hmacnew.go b/src/cmd/gofix/hmacnew.go
new file mode 100644
index 0000000..c0c44ef
--- /dev/null
+++ b/src/cmd/gofix/hmacnew.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+	register(hmacNewFix)
+}
+
+var hmacNewFix = fix{
+	"hmacnew",
+	"2012-01-19",
+	hmacnew,
+	`Deprecate hmac.NewMD5, hmac.NewSHA1 and hmac.NewSHA256.
+
+This fix rewrites code using hmac.NewMD5, hmac.NewSHA1 and hmac.NewSHA256 to
+use hmac.New:
+
+	hmac.NewMD5(key) -> hmac.New(md5.New, key)
+	hmac.NewSHA1(key) -> hmac.New(sha1.New, key)
+	hmac.NewSHA256(key) -> hmac.New(sha256.New, key)
+
+`,
+}
+
+func hmacnew(f *ast.File) (fixed bool) {
+	if !imports(f, "crypto/hmac") {
+		return
+	}
+
+	walk(f, func(n interface{}) {
+		ce, ok := n.(*ast.CallExpr)
+		if !ok {
+			return
+		}
+
+		var pkg string
+		switch {
+		case isPkgDot(ce.Fun, "hmac", "NewMD5"):
+			pkg = "md5"
+		case isPkgDot(ce.Fun, "hmac", "NewSHA1"):
+			pkg = "sha1"
+		case isPkgDot(ce.Fun, "hmac", "NewSHA256"):
+			pkg = "sha256"
+		default:
+			return
+		}
+
+		addImport(f, "crypto/"+pkg)
+
+		ce.Fun = ast.NewIdent("hmac.New")
+		ce.Args = append([]ast.Expr{ast.NewIdent(pkg + ".New")}, ce.Args...)
+
+		fixed = true
+	})
+
+	return
+}
diff --git a/src/cmd/gofix/hmacnew_test.go b/src/cmd/gofix/hmacnew_test.go
new file mode 100644
index 0000000..5aeee85
--- /dev/null
+++ b/src/cmd/gofix/hmacnew_test.go
@@ -0,0 +1,107 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+	addTestCases(hmacNewTests, hmacnew)
+}
+
+var hmacNewTests = []testCase{
+	{
+		Name: "hmacnew.0",
+		In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewSHA1([]byte("some key"))
+`,
+		Out: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+	},
+	{
+		Name: "hmacnew.1",
+		In: `package main
+
+import "crypto/hmac"
+
+var key = make([]byte, 8)
+var f = hmac.NewSHA1(key)
+`,
+		Out: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+)
+
+var key = make([]byte, 8)
+var f = hmac.New(sha1.New, key)
+`,
+	},
+	{
+		Name: "hmacnew.2",
+		In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewMD5([]byte("some key"))
+`,
+		Out: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/md5"
+)
+
+var f = hmac.New(md5.New, []byte("some key"))
+`,
+	},
+	{
+		Name: "hmacnew.3",
+		In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewSHA256([]byte("some key"))
+`,
+		Out: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+)
+
+var f = hmac.New(sha256.New, []byte("some key"))
+`,
+	},
+	{
+		Name: "hmacnew.4",
+		In: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+		Out: `package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+	},
+}
diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go
index 6bdbbb4..a97ce09 100644
--- a/src/pkg/crypto/hmac/hmac.go
+++ b/src/pkg/crypto/hmac/hmac.go
@@ -9,9 +9,6 @@
 package hmac
 
 import (
-	"crypto/md5"
-	"crypto/sha1"
-	"crypto/sha256"
 	"hash"
 )
 
@@ -63,7 +60,7 @@
 	h.inner.Write(h.tmp[0:h.blocksize])
 }
 
-// New returns a new HMAC hash using the given crypto.Hash type and key.
+// New returns a new HMAC hash using the given hash.Hash type and key.
 func New(h func() hash.Hash, key []byte) hash.Hash {
 	hm := new(hmac)
 	hm.outer = h()
@@ -81,12 +78,3 @@
 	hm.Reset()
 	return hm
 }
-
-// NewMD5 returns a new HMAC-MD5 hash using the given key.
-func NewMD5(key []byte) hash.Hash { return New(md5.New, key) }
-
-// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
-func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) }
-
-// NewSHA256 returns a new HMAC-SHA256 hash using the given key.
-func NewSHA256(key []byte) hash.Hash { return New(sha256.New, key) }
diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go
index 914491d..00695e7 100644
--- a/src/pkg/crypto/tls/cipher_suites.go
+++ b/src/pkg/crypto/tls/cipher_suites.go
@@ -91,7 +91,7 @@
 		copy(mac.key, key)
 		return mac
 	}
-	return tls10MAC{hmac.NewSHA1(key)}
+	return tls10MAC{hmac.New(sha1.New, key)}
 }
 
 type macFunction interface {
diff --git a/src/pkg/exp/ssh/transport.go b/src/pkg/exp/ssh/transport.go
index 60a636f..e21bc4b 100644
--- a/src/pkg/exp/ssh/transport.go
+++ b/src/pkg/exp/ssh/transport.go
@@ -9,6 +9,7 @@
 	"crypto"
 	"crypto/cipher"
 	"crypto/hmac"
+	"crypto/sha1"
 	"crypto/subtle"
 	"errors"
 	"hash"
@@ -266,7 +267,7 @@
 	generateKeyMaterial(key, d.keyTag, K, H, sessionId, h)
 	generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h)
 
-	c.mac = truncatingMAC{12, hmac.NewSHA1(macKey)}
+	c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)}
 
 	cipher, err := cipherMode.createCipher(key, iv)
 	if err != nil {
diff --git a/src/pkg/net/smtp/auth.go b/src/pkg/net/smtp/auth.go
index 6f0cde0..d401e3c 100644
--- a/src/pkg/net/smtp/auth.go
+++ b/src/pkg/net/smtp/auth.go
@@ -6,6 +6,7 @@
 
 import (
 	"crypto/hmac"
+	"crypto/md5"
 	"errors"
 	"fmt"
 )
@@ -88,7 +89,7 @@
 
 func (a *cramMD5Auth) Next(fromServer []byte, more bool) ([]byte, error) {
 	if more {
-		d := hmac.NewMD5([]byte(a.secret))
+		d := hmac.New(md5.New, []byte(a.secret))
 		d.Write(fromServer)
 		s := make([]byte, 0, d.Size())
 		return []byte(fmt.Sprintf("%s %x", a.username, d.Sum(s))), nil