Proposal Details
crypto/rsa.SignPSS() and similar packages take a crypto.Hash, which is hard-coded to only support known-to-Go hash algorithms.
This is a total show-stopper for me, because I need to be able to support new, not-yet-existing hash algorithms.
I propose a new implementation for src/crypto/crypto.go:
// ...
type customImplementation struct {
name string
// int is used rather than uint8 of digestSizes in order to support future
// hash functions with large digests.
digestSize int
f func() hash.Hash
}
var customImplementations = make(map[Hash]customImplementation)
func (h Hash) String() string {
switch h {
// ...
default:
if implementation, exists := customImplementations[h]; exists {
return implementation.name
}
return "unknown hash value " + strconv.Itoa(int(h))
}
}
// ...
// Defines the limit of 1st-party hash functions.
const boundaryFirstParty Hash = 101
// ...
// 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 for hash functions known to Go authors. It does require
// that the hash function in question be linked into the program for 3rd-party
// hash functions.
func (h Hash) Size() int {
if h < 1 || h == maxHash {
panic("crypto: Size of unknown hash function")
}
if h < maxHash {
return int(digestSizes[h])
}
if implementation, exists := customImplementations[h]; exists {
return implementation.digestSize
}
panic("crypto: Size of unknown hash function")
}
// ...
// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h < 1 || h == maxHash {
panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}
if h < maxHash {
f := hashes[h]
if f != nil {
return f()
}
}
if implementation, exists := customImplementations[h]; exists {
return implementation.f()
}
panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}
// Available reports whether the given hash function is linked into the binary.
func (h Hash) Available() bool {
if h < maxHash && hashes[h] != nil {
return true
}
if _, exists := customImplementations[h]; exists {
return true
}
return false
}
// ...
// RegisterCustomHash registers a function that returns a new instance of the given
// 3rd-party hash function. This is intended to be called from the init function in
// packages that implement hash functions. Registering hash functions outside of an
// init function can cause thread-unsafe behaviors.
func RegisterCustomHash(h Hash, name string, digestSize int, f func() hash.Hash) error {
if h <= boundaryFirstParty {
return errors.New("crypto: RegisterCustomHash within 1st-party region")
}
if len(name) == 0 {
return errors.New("crypto: RegisterCustomHash of hash function without a name")
}
if digestSize < 1 {
return errors.New("crypto: RegisterCustomHash of hash function with empty digests")
}
if f == nil {
return errors.New("crypto: RegisterCustomHash of hash function without an allocator")
}
if _, exists := customImplementations[h]; exists {
return errors.New("crypto: RegisterCustomHash of an existing hash function")
}
customImplementations[h] = customImplementation{
name: name,
digestSize: digestSize,
f: f,
}
return nil
}
// ...
(note that I would submit a pull request, but I am currently on a very shoddy hotspot internet connection that prevents me from performing the necessary tasks to do so.)
There is of course an issue with this proposal: 3rd-party hash algorithms might use the same value for crypto.Hash, which would lead to errors.
Ideally we would change the type definition of crypto.Hash to something more sensible than a uint, but this would break packages that use the uint to identify hash algorithms.
Perhaps a checksum of the hash algorithm's name to produce a uint would be better?
Proposal Details
crypto/rsa.SignPSS()and similar packages take acrypto.Hash, which is hard-coded to only support known-to-Go hash algorithms.This is a total show-stopper for me, because I need to be able to support new, not-yet-existing hash algorithms.
I propose a new implementation for
src/crypto/crypto.go:(note that I would submit a pull request, but I am currently on a very shoddy hotspot internet connection that prevents me from performing the necessary tasks to do so.)
There is of course an issue with this proposal: 3rd-party hash algorithms might use the same value for
crypto.Hash, which would lead to errors.Ideally we would change the type definition of
crypto.Hashto something more sensible than auint, but this would break packages that use theuintto identify hash algorithms.Perhaps a checksum of the hash algorithm's name to produce a
uintwould be better?