]> Cypherpunks repositories - gostls13.git/commitdiff
crypto: add package.
authorAdam Langley <agl@golang.org>
Tue, 1 Feb 2011 16:02:48 +0000 (11:02 -0500)
committerAdam Langley <agl@golang.org>
Tue, 1 Feb 2011 16:02:48 +0000 (11:02 -0500)
The crypto package is added as a common place to store identifiers for
hash functions. At the moment, the rsa package has an enumeration of
hash functions and knowledge of their digest lengths. This is an
unfortunate coupling and other high level crypto packages tend to need
to duplicate this enumeration and knowledge (i.e. openpgp).

crypto pulls this code out into a common location.

It would also make sense to add similar support for ciphers to crypto,
but the problem there isn't as acute that isn't done in this change.

R=bradfitzgo, r, rsc
CC=golang-dev
https://golang.org/cl/4080046

16 files changed:
src/pkg/Makefile
src/pkg/crypto/Makefile [new file with mode: 0644]
src/pkg/crypto/crypto.go [new file with mode: 0644]
src/pkg/crypto/md4/md4.go
src/pkg/crypto/md5/md5.go
src/pkg/crypto/ocsp/ocsp.go
src/pkg/crypto/ripemd160/ripemd160.go
src/pkg/crypto/rsa/pkcs1v15.go
src/pkg/crypto/rsa/pkcs1v15_test.go
src/pkg/crypto/sha1/sha1.go
src/pkg/crypto/sha256/sha256.go
src/pkg/crypto/sha512/sha512.go
src/pkg/crypto/tls/handshake_client.go
src/pkg/crypto/tls/handshake_server.go
src/pkg/crypto/tls/key_agreement.go
src/pkg/crypto/x509/x509.go

index 619e8aa26125eb83c751e38b6dde71df0595445d..6ba6951afc360ac5d340db5e4f163b6c930b19f1 100644 (file)
@@ -28,6 +28,7 @@ DIRS=\
        container/list\
        container/ring\
        container/vector\
+       crypto\
        crypto/aes\
        crypto/block\
        crypto/blowfish\
@@ -154,6 +155,7 @@ DIRS+=\
 endif
 
 NOTEST=\
+       crypto\
        debug/proc\
        exp/draw/x11\
        go/ast\
diff --git a/src/pkg/crypto/Makefile b/src/pkg/crypto/Makefile
new file mode 100644 (file)
index 0000000..738a520
--- /dev/null
@@ -0,0 +1,11 @@
+# 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.
+
+include ../../Make.inc
+
+TARG=crypto
+GOFILES=\
+       crypto.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/crypto/crypto.go b/src/pkg/crypto/crypto.go
new file mode 100644 (file)
index 0000000..be6b34a
--- /dev/null
@@ -0,0 +1,73 @@
+// 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.
+
+// The crypto package collects common cryptographic constants.
+package crypto
+
+import (
+       "hash"
+)
+
+// Hash identifies a cryptographic hash function that is implemented in another
+// package.
+type Hash uint
+
+const (
+       MD4       Hash = 1 + iota // in package crypto/md4
+       MD5                       // in package crypto/md5
+       SHA1                      // in package crypto/sha1
+       SHA224                    // in package crypto/sha256
+       SHA256                    // in package crypto/sha256
+       SHA384                    // in package crypto/sha512
+       SHA512                    // in package crypto/sha512
+       MD5SHA1                   // no implementation; MD5+SHA1 used for TLS RSA
+       RIPEMD160                 // in package crypto/ripemd160
+       maxHash
+)
+
+var digestSizes = []uint8{
+       MD4:       16,
+       MD5:       16,
+       SHA1:      20,
+       SHA224:    28,
+       SHA256:    32,
+       SHA384:    48,
+       SHA512:    64,
+       MD5SHA1:   36,
+       RIPEMD160: 20,
+}
+
+// Size returns the length, in bytes, of a digest resulting from the given hash
+// function. It doesn't require that the hash function in question be linked
+// into the program.
+func (h Hash) Size() int {
+       if h > 0 && h < maxHash {
+               return int(digestSizes[h])
+       }
+       panic("crypto: Size of unknown hash function")
+}
+
+var hashes = make([]func() hash.Hash, maxHash)
+
+// New returns a new hash.Hash calculating the given hash function. If the
+// hash function is not linked into the binary, New returns nil.
+func (h Hash) New() hash.Hash {
+       if h > 0 && h < maxHash {
+               f := hashes[h]
+               if f != nil {
+                       return f()
+               }
+       }
+       return nil
+}
+
+// RegisterHash registers a function that returns a new instance of the given
+// hash function. This is intended to be called from the init function in
+// packages that implement hash functions.
+func RegisterHash(h Hash, f func() hash.Hash) {
+       if h >= maxHash {
+               panic("crypto: RegisterHash of unknown hash function")
+       }
+       hashes[h] = f
+}
index e13c986e68637ee372b2243524db2d02ede4192f..ee46544a920b32ee67864c9ed7508016769126ea 100644 (file)
@@ -6,10 +6,15 @@
 package md4
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.MD4, New)
+}
+
 // The size of an MD4 checksum in bytes.
 const Size = 16
 
index 54fddb63b93672468800606b07956294b1c89784..8f93fc4b354eecf94a467bad45352dfe47462969 100644 (file)
@@ -6,10 +6,15 @@
 package md5
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.MD5, New)
+}
+
 // The size of an MD5 checksum in bytes.
 const Size = 16
 
index f3fa3bc834c4bf114336a05e888191c0f07b4c15..f42d8088884c30f0127f4c71468611af7f5b9e18 100644 (file)
@@ -9,8 +9,9 @@ package ocsp
 
 import (
        "asn1"
+       "crypto"
        "crypto/rsa"
-       "crypto/sha1"
+       "crypto/sha1"
        "crypto/x509"
        "os"
        "time"
@@ -168,8 +169,8 @@ func ParseResponse(bytes []byte) (*Response, os.Error) {
                return nil, x509.UnsupportedAlgorithmError{}
        }
 
-       h := sha1.New()
-       hashType := rsa.HashSHA1
+       hashType := crypto.SHA1
+       h := hashType.New()
 
        pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
        h.Write(basicResp.TBSResponseData.Raw)
index 5614f1360ebd441289b819398f6a653e6ae417af..6e88521c3f6c58c7afee82d390e4c04a868bd90b 100644 (file)
@@ -10,10 +10,15 @@ package ripemd160
 // http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.RIPEMD160, New)
+}
+
 // The size of the checksum in bytes.
 const Size = 20
 
index e4fc7d14a6b722c5c7939874f993056cf525d4ea..2eaadee24c2e964d042e1d94109d5a4fc1ff3762 100644 (file)
@@ -6,6 +6,7 @@ package rsa
 
 import (
        "big"
+       "crypto"
        "crypto/subtle"
        "io"
        "os"
@@ -139,19 +140,6 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
        return
 }
 
-// Due to the design of PKCS#1 v1.5, we need to know the exact hash function in
-// use. A generic hash.Hash will not do.
-type PKCS1v15Hash int
-
-const (
-       HashMD5 PKCS1v15Hash = iota
-       HashSHA1
-       HashSHA256
-       HashSHA384
-       HashSHA512
-       HashMD5SHA1 // combined MD5 and SHA1 hash used for RSA signing in TLS.
-)
-
 // These are ASN1 DER structures:
 //   DigestInfo ::= SEQUENCE {
 //     digestAlgorithm AlgorithmIdentifier,
@@ -160,25 +148,20 @@ const (
 // For performance, we don't use the generic ASN1 encoder. Rather, we
 // precompute a prefix of the digest value that makes a valid ASN1 DER string
 // with the correct contents.
-var hashPrefixes = [][]byte{
-       // HashMD5
-       {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
-       // HashSHA1
-       {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
-       // HashSHA256
-       {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
-       // HashSHA384
-       {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
-       // HashSHA512
-       {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
-       // HashMD5SHA1
-       {}, // A special TLS case which doesn't use an ASN1 prefix.
+var hashPrefixes = map[crypto.Hash][]byte{
+       crypto.MD5:       []byte{0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+       crypto.SHA1:      []byte{0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+       crypto.SHA256:    []byte{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+       crypto.SHA384:    []byte{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+       crypto.SHA512:    {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+       crypto.MD5SHA1:   {}, // A special TLS case which doesn't use an ASN1 prefix.
+       crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
 }
 
 // SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
 // Note that hashed must be the result of hashing the input message using the
 // given hash function.
-func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed []byte) (s []byte, err os.Error) {
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err os.Error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
                return
@@ -211,7 +194,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed []
 // hashed is the result of hashing the input message using the given hash
 // function and sig is the signature. A valid signature is indicated by
 // returning a nil error.
-func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte) (err os.Error) {
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err os.Error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
                return
@@ -246,28 +229,14 @@ func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte
        return nil
 }
 
-func pkcs1v15HashInfo(hash PKCS1v15Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
-       switch hash {
-       case HashMD5:
-               hashLen = 16
-       case HashSHA1:
-               hashLen = 20
-       case HashSHA256:
-               hashLen = 32
-       case HashSHA384:
-               hashLen = 48
-       case HashSHA512:
-               hashLen = 64
-       case HashMD5SHA1:
-               hashLen = 36
-       default:
-               return 0, nil, os.ErrorString("unknown hash function")
-       }
-
+func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
+       hashLen = hash.Size()
        if inLen != hashLen {
                return 0, nil, os.ErrorString("input must be hashed message")
        }
-
-       prefix = hashPrefixes[int(hash)]
+       prefix, ok := hashPrefixes[hash]
+       if !ok {
+               return 0, nil, os.ErrorString("unsupported hash function")
+       }
        return
 }
index bf6306dc29b43351666f6fccdf6c6d0ac2480714..7b2ce08cb0bf5c96f43cfcad228e8a46bbc5fb3f 100644 (file)
@@ -7,6 +7,7 @@ package rsa
 import (
        "big"
        "bytes"
+       "crypto"
        "crypto/rand"
        "crypto/sha1"
        "encoding/base64"
@@ -165,7 +166,7 @@ func TestSignPKCS1v15(t *testing.T) {
                h.Write([]byte(test.in))
                digest := h.Sum()
 
-               s, err := SignPKCS1v15(nil, rsaPrivateKey, HashSHA1, digest)
+               s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest)
                if err != nil {
                        t.Errorf("#%d %s", i, err)
                }
@@ -185,7 +186,7 @@ func TestVerifyPKCS1v15(t *testing.T) {
 
                sig, _ := hex.DecodeString(test.out)
 
-               err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, HashSHA1, digest, sig)
+               err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA1, digest, sig)
                if err != nil {
                        t.Errorf("#%d %s", i, err)
                }
index 8716c3591074b4845388926d97ed74f8755597b7..e6aa096e2a6b9c07ae1f7e8687b4d18efa1b4a12 100644 (file)
@@ -6,10 +6,15 @@
 package sha1
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.SHA1, New)
+}
+
 // The size of a SHA1 checksum in bytes.
 const Size = 20
 
index 57a8ffa0d76c5afac4ebe5296287378f1af9e59f..69b356b4e5132297fad466df20b5bb159a1f06bb 100644 (file)
@@ -6,10 +6,16 @@
 package sha256
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.SHA224, New224)
+       crypto.RegisterHash(crypto.SHA256, New)
+}
+
 // The size of a SHA256 checksum in bytes.
 const Size = 32
 
index c3cda97d9681f469da8ad5a25fe7d38915c4605f..7e9f330e594a4c08c212d2d47ea28ebd09d9c802 100644 (file)
@@ -6,10 +6,16 @@
 package sha512
 
 import (
+       "crypto"
        "hash"
        "os"
 )
 
+func init() {
+       crypto.RegisterHash(crypto.SHA384, New384)
+       crypto.RegisterHash(crypto.SHA512, New)
+}
+
 // The size of a SHA512 checksum in bytes.
 const Size = 64
 
index 1ca33f59dd080cdfccc2c5351e922dd6523b3511..19d2bfa3ba74f2d5cf613875720a748d46619dfc 100644 (file)
@@ -5,6 +5,7 @@
 package tls
 
 import (
+       "crypto"
        "crypto/rsa"
        "crypto/subtle"
        "crypto/x509"
@@ -248,7 +249,7 @@ func (c *Conn) clientHandshake() os.Error {
                var digest [36]byte
                copy(digest[0:16], finishedHash.serverMD5.Sum())
                copy(digest[16:36], finishedHash.serverSHA1.Sum())
-               signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:])
+               signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:])
                if err != nil {
                        return c.sendAlert(alertInternalError)
                }
index 955811ada35d3b3aceb89d6133135b99bd0ef60a..af46ea51133dae2ae86e46988318f880c897ef93 100644 (file)
@@ -5,6 +5,7 @@
 package tls
 
 import (
+       "crypto"
        "crypto/rsa"
        "crypto/subtle"
        "crypto/x509"
@@ -213,7 +214,7 @@ Curves:
                digest := make([]byte, 36)
                copy(digest[0:16], finishedHash.serverMD5.Sum())
                copy(digest[16:36], finishedHash.serverSHA1.Sum())
-               err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature)
+               err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
                if err != nil {
                        c.sendAlert(alertBadCertificate)
                        return os.ErrorString("could not validate signature of connection nonces: " + err.String())
index 861c64f04bb36635074c9cce3f46e2ccc81797e5..8edbb11900c5f1dfa2b8f2db9b08c67d46cafc2e 100644 (file)
@@ -6,6 +6,7 @@ package tls
 
 import (
        "big"
+       "crypto"
        "crypto/elliptic"
        "crypto/md5"
        "crypto/rsa"
@@ -143,7 +144,7 @@ Curve:
        copy(serverECDHParams[4:], ecdhePublic)
 
        md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
-       sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, md5sha1)
+       sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
        if err != nil {
                return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
        }
@@ -216,7 +217,7 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
        sig = sig[2:]
 
        md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
-       return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), rsa.HashMD5SHA1, md5sha1, sig)
+       return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
 
 Error:
        return os.ErrorString("invalid ServerKeyExchange")
index 6199e8db9f539df86d7c0bc43aa05182e330fe1a..599263432b551c3617dddf83c603fe3930cf0f6a 100644 (file)
@@ -9,6 +9,7 @@ import (
        "asn1"
        "big"
        "container/vector"
+       "crypto"
        "crypto/rsa"
        "crypto/sha1"
        "hash"
@@ -374,12 +375,12 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
        // TODO(agl): don't ignore the path length constraint.
 
        var h hash.Hash
-       var hashType rsa.PKCS1v15Hash
+       var hashType crypto.Hash
 
        switch c.SignatureAlgorithm {
        case SHA1WithRSA:
                h = sha1.New()
-               hashType = rsa.HashSHA1
+               hashType = crypto.SHA1
        default:
                return UnsupportedAlgorithmError{}
        }
@@ -840,7 +841,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
        h.Write(tbsCertContents)
        digest := h.Sum()
 
-       signature, err := rsa.SignPKCS1v15(rand, priv, rsa.HashSHA1, digest)
+       signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
        if err != nil {
                return
        }