mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 09:42:26 -05:00 
			
		
		
		
	[feature] Try HTTP signature validation with and without query params for incoming requests (#2591)
* [feature] Verify signatures both with + without query params * Bump to tagged version
This commit is contained in:
		
					parent
					
						
							
								c675d47a8c
							
						
					
				
			
			
				commit
				
					
						b614d33c40
					
				
			
		
					 18 changed files with 1799 additions and 22 deletions
				
			
		
							
								
								
									
										532
									
								
								vendor/github.com/superseriousbusiness/httpsig/algorithms.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								vendor/github.com/superseriousbusiness/httpsig/algorithms.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,532 @@ | |||
| package httpsig | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/hmac" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/sha256" | ||||
| 	"crypto/sha512" | ||||
| 	"crypto/subtle" // Use should trigger great care | ||||
| 	"encoding/asn1" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"golang.org/x/crypto/blake2b" | ||||
| 	"golang.org/x/crypto/blake2s" | ||||
| 	"golang.org/x/crypto/ed25519" | ||||
| 	"golang.org/x/crypto/ripemd160" | ||||
| 	"golang.org/x/crypto/sha3" | ||||
| 	"golang.org/x/crypto/ssh" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	hmacPrefix        = "hmac" | ||||
| 	rsaPrefix         = "rsa" | ||||
| 	sshPrefix         = "ssh" | ||||
| 	ecdsaPrefix       = "ecdsa" | ||||
| 	ed25519Prefix     = "ed25519" | ||||
| 	md4String         = "md4" | ||||
| 	md5String         = "md5" | ||||
| 	sha1String        = "sha1" | ||||
| 	sha224String      = "sha224" | ||||
| 	sha256String      = "sha256" | ||||
| 	sha384String      = "sha384" | ||||
| 	sha512String      = "sha512" | ||||
| 	md5sha1String     = "md5sha1" | ||||
| 	ripemd160String   = "ripemd160" | ||||
| 	sha3_224String    = "sha3-224" | ||||
| 	sha3_256String    = "sha3-256" | ||||
| 	sha3_384String    = "sha3-384" | ||||
| 	sha3_512String    = "sha3-512" | ||||
| 	sha512_224String  = "sha512-224" | ||||
| 	sha512_256String  = "sha512-256" | ||||
| 	blake2s_256String = "blake2s-256" | ||||
| 	blake2b_256String = "blake2b-256" | ||||
| 	blake2b_384String = "blake2b-384" | ||||
| 	blake2b_512String = "blake2b-512" | ||||
| ) | ||||
| 
 | ||||
| var blake2Algorithms = map[crypto.Hash]bool{ | ||||
| 	crypto.BLAKE2s_256: true, | ||||
| 	crypto.BLAKE2b_256: true, | ||||
| 	crypto.BLAKE2b_384: true, | ||||
| 	crypto.BLAKE2b_512: true, | ||||
| } | ||||
| 
 | ||||
| var hashToDef = map[crypto.Hash]struct { | ||||
| 	name string | ||||
| 	new  func(key []byte) (hash.Hash, error) // Only MACers will accept a key | ||||
| }{ | ||||
| 	// Which standard names these? | ||||
| 	// The spec lists the following as a canonical reference, which is dead: | ||||
| 	// http://www.iana.org/assignments/signature-algorithms | ||||
| 	// | ||||
| 	// Note that the forbidden hashes have an invalid 'new' function. | ||||
| 	crypto.MD4: {md4String, func(key []byte) (hash.Hash, error) { return nil, nil }}, | ||||
| 	crypto.MD5: {md5String, func(key []byte) (hash.Hash, error) { return nil, nil }}, | ||||
| 	// Temporarily enable SHA1 because of issue https://github.com/golang/go/issues/37278 | ||||
| 	crypto.SHA1:        {sha1String, func(key []byte) (hash.Hash, error) { return sha1.New(), nil }}, | ||||
| 	crypto.SHA224:      {sha224String, func(key []byte) (hash.Hash, error) { return sha256.New224(), nil }}, | ||||
| 	crypto.SHA256:      {sha256String, func(key []byte) (hash.Hash, error) { return sha256.New(), nil }}, | ||||
| 	crypto.SHA384:      {sha384String, func(key []byte) (hash.Hash, error) { return sha512.New384(), nil }}, | ||||
| 	crypto.SHA512:      {sha512String, func(key []byte) (hash.Hash, error) { return sha512.New(), nil }}, | ||||
| 	crypto.MD5SHA1:     {md5sha1String, func(key []byte) (hash.Hash, error) { return nil, nil }}, | ||||
| 	crypto.RIPEMD160:   {ripemd160String, func(key []byte) (hash.Hash, error) { return ripemd160.New(), nil }}, | ||||
| 	crypto.SHA3_224:    {sha3_224String, func(key []byte) (hash.Hash, error) { return sha3.New224(), nil }}, | ||||
| 	crypto.SHA3_256:    {sha3_256String, func(key []byte) (hash.Hash, error) { return sha3.New256(), nil }}, | ||||
| 	crypto.SHA3_384:    {sha3_384String, func(key []byte) (hash.Hash, error) { return sha3.New384(), nil }}, | ||||
| 	crypto.SHA3_512:    {sha3_512String, func(key []byte) (hash.Hash, error) { return sha3.New512(), nil }}, | ||||
| 	crypto.SHA512_224:  {sha512_224String, func(key []byte) (hash.Hash, error) { return sha512.New512_224(), nil }}, | ||||
| 	crypto.SHA512_256:  {sha512_256String, func(key []byte) (hash.Hash, error) { return sha512.New512_256(), nil }}, | ||||
| 	crypto.BLAKE2s_256: {blake2s_256String, func(key []byte) (hash.Hash, error) { return blake2s.New256(key) }}, | ||||
| 	crypto.BLAKE2b_256: {blake2b_256String, func(key []byte) (hash.Hash, error) { return blake2b.New256(key) }}, | ||||
| 	crypto.BLAKE2b_384: {blake2b_384String, func(key []byte) (hash.Hash, error) { return blake2b.New384(key) }}, | ||||
| 	crypto.BLAKE2b_512: {blake2b_512String, func(key []byte) (hash.Hash, error) { return blake2b.New512(key) }}, | ||||
| } | ||||
| 
 | ||||
| var stringToHash map[string]crypto.Hash | ||||
| 
 | ||||
| const ( | ||||
| 	defaultAlgorithm        = RSA_SHA256 | ||||
| 	defaultAlgorithmHashing = sha256String | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	stringToHash = make(map[string]crypto.Hash, len(hashToDef)) | ||||
| 	for k, v := range hashToDef { | ||||
| 		stringToHash[v.name] = k | ||||
| 	} | ||||
| 	// This should guarantee that at runtime the defaultAlgorithm will not | ||||
| 	// result in errors when fetching a macer or signer (see algorithms.go) | ||||
| 	if ok, err := isAvailable(string(defaultAlgorithmHashing)); err != nil { | ||||
| 		panic(err) | ||||
| 	} else if !ok { | ||||
| 		panic(fmt.Sprintf("the default httpsig algorithm is unavailable: %q", defaultAlgorithm)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func isForbiddenHash(h crypto.Hash) bool { | ||||
| 	switch h { | ||||
| 	// Not actually cryptographically secure | ||||
| 	case crypto.MD4: | ||||
| 		fallthrough | ||||
| 	case crypto.MD5: | ||||
| 		fallthrough | ||||
| 	case crypto.MD5SHA1: // shorthand for crypto/tls, not actually implemented | ||||
| 		return true | ||||
| 	} | ||||
| 	// Still cryptographically secure | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // signer is an internally public type. | ||||
| type signer interface { | ||||
| 	Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) | ||||
| 	Verify(pub crypto.PublicKey, toHash, signature []byte) error | ||||
| 	String() string | ||||
| } | ||||
| 
 | ||||
| // macer is an internally public type. | ||||
| type macer interface { | ||||
| 	Sign(sig, key []byte) ([]byte, error) | ||||
| 	Equal(sig, actualMAC, key []byte) (bool, error) | ||||
| 	String() string | ||||
| } | ||||
| 
 | ||||
| var _ macer = &hmacAlgorithm{} | ||||
| 
 | ||||
| type hmacAlgorithm struct { | ||||
| 	fn   func(key []byte) (hash.Hash, error) | ||||
| 	kind crypto.Hash | ||||
| } | ||||
| 
 | ||||
| func (h *hmacAlgorithm) Sign(sig, key []byte) ([]byte, error) { | ||||
| 	hs, err := h.fn(key) | ||||
| 	if err = setSig(hs, sig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return hs.Sum(nil), nil | ||||
| } | ||||
| 
 | ||||
| func (h *hmacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) { | ||||
| 	hs, err := h.fn(key) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	defer hs.Reset() | ||||
| 	err = setSig(hs, sig) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	expected := hs.Sum(nil) | ||||
| 	return hmac.Equal(actualMAC, expected), nil | ||||
| } | ||||
| 
 | ||||
| func (h *hmacAlgorithm) String() string { | ||||
| 	return fmt.Sprintf("%s-%s", hmacPrefix, hashToDef[h.kind].name) | ||||
| } | ||||
| 
 | ||||
| var _ signer = &rsaAlgorithm{} | ||||
| 
 | ||||
| type rsaAlgorithm struct { | ||||
| 	hash.Hash | ||||
| 	kind      crypto.Hash | ||||
| 	sshSigner ssh.Signer | ||||
| } | ||||
| 
 | ||||
| func (r *rsaAlgorithm) setSig(b []byte) error { | ||||
| 	n, err := r.Write(b) | ||||
| 	if err != nil { | ||||
| 		r.Reset() | ||||
| 		return err | ||||
| 	} else if n != len(b) { | ||||
| 		r.Reset() | ||||
| 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (r *rsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { | ||||
| 	if r.sshSigner != nil { | ||||
| 		sshsig, err := r.sshSigner.Sign(rand, sig) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		return sshsig.Blob, nil | ||||
| 	} | ||||
| 	defer r.Reset() | ||||
| 
 | ||||
| 	if err := r.setSig(sig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	rsaK, ok := p.(*rsa.PrivateKey) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("crypto.PrivateKey is not *rsa.PrivateKey") | ||||
| 	} | ||||
| 	return rsa.SignPKCS1v15(rand, rsaK, r.kind, r.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| func (r *rsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { | ||||
| 	defer r.Reset() | ||||
| 	rsaK, ok := pub.(*rsa.PublicKey) | ||||
| 	if !ok { | ||||
| 		return errors.New("crypto.PublicKey is not *rsa.PublicKey") | ||||
| 	} | ||||
| 	if err := r.setSig(toHash); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return rsa.VerifyPKCS1v15(rsaK, r.kind, r.Sum(nil), signature) | ||||
| } | ||||
| 
 | ||||
| func (r *rsaAlgorithm) String() string { | ||||
| 	return fmt.Sprintf("%s-%s", rsaPrefix, hashToDef[r.kind].name) | ||||
| } | ||||
| 
 | ||||
| var _ signer = &ed25519Algorithm{} | ||||
| 
 | ||||
| type ed25519Algorithm struct { | ||||
| 	sshSigner ssh.Signer | ||||
| } | ||||
| 
 | ||||
| func (r *ed25519Algorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { | ||||
| 	if r.sshSigner != nil { | ||||
| 		sshsig, err := r.sshSigner.Sign(rand, sig) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		return sshsig.Blob, nil | ||||
| 	} | ||||
| 	ed25519K, ok := p.(ed25519.PrivateKey) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("crypto.PrivateKey is not ed25519.PrivateKey") | ||||
| 	} | ||||
| 	return ed25519.Sign(ed25519K, sig), nil | ||||
| } | ||||
| 
 | ||||
| func (r *ed25519Algorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { | ||||
| 	ed25519K, ok := pub.(ed25519.PublicKey) | ||||
| 	if !ok { | ||||
| 		return errors.New("crypto.PublicKey is not ed25519.PublicKey") | ||||
| 	} | ||||
| 
 | ||||
| 	if ed25519.Verify(ed25519K, toHash, signature) { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return errors.New("ed25519 verify failed") | ||||
| } | ||||
| 
 | ||||
| func (r *ed25519Algorithm) String() string { | ||||
| 	return fmt.Sprintf("%s", ed25519Prefix) | ||||
| } | ||||
| 
 | ||||
| var _ signer = &ecdsaAlgorithm{} | ||||
| 
 | ||||
| type ecdsaAlgorithm struct { | ||||
| 	hash.Hash | ||||
| 	kind crypto.Hash | ||||
| } | ||||
| 
 | ||||
| func (r *ecdsaAlgorithm) setSig(b []byte) error { | ||||
| 	n, err := r.Write(b) | ||||
| 	if err != nil { | ||||
| 		r.Reset() | ||||
| 		return err | ||||
| 	} else if n != len(b) { | ||||
| 		r.Reset() | ||||
| 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type ECDSASignature struct { | ||||
| 	R, S *big.Int | ||||
| } | ||||
| 
 | ||||
| func (r *ecdsaAlgorithm) Sign(rand io.Reader, p crypto.PrivateKey, sig []byte) ([]byte, error) { | ||||
| 	defer r.Reset() | ||||
| 	if err := r.setSig(sig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ecdsaK, ok := p.(*ecdsa.PrivateKey) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("crypto.PrivateKey is not *ecdsa.PrivateKey") | ||||
| 	} | ||||
| 	R, S, err := ecdsa.Sign(rand, ecdsaK, r.Sum(nil)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	signature := ECDSASignature{R: R, S: S} | ||||
| 	bytes, err := asn1.Marshal(signature) | ||||
| 
 | ||||
| 	return bytes, err | ||||
| } | ||||
| 
 | ||||
| func (r *ecdsaAlgorithm) Verify(pub crypto.PublicKey, toHash, signature []byte) error { | ||||
| 	defer r.Reset() | ||||
| 	ecdsaK, ok := pub.(*ecdsa.PublicKey) | ||||
| 	if !ok { | ||||
| 		return errors.New("crypto.PublicKey is not *ecdsa.PublicKey") | ||||
| 	} | ||||
| 	if err := r.setSig(toHash); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	sig := new(ECDSASignature) | ||||
| 	_, err := asn1.Unmarshal(signature, sig) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if ecdsa.Verify(ecdsaK, r.Sum(nil), sig.R, sig.S) { | ||||
| 		return nil | ||||
| 	} else { | ||||
| 		return errors.New("Invalid signature") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *ecdsaAlgorithm) String() string { | ||||
| 	return fmt.Sprintf("%s-%s", ecdsaPrefix, hashToDef[r.kind].name) | ||||
| } | ||||
| 
 | ||||
| var _ macer = &blakeMacAlgorithm{} | ||||
| 
 | ||||
| type blakeMacAlgorithm struct { | ||||
| 	fn   func(key []byte) (hash.Hash, error) | ||||
| 	kind crypto.Hash | ||||
| } | ||||
| 
 | ||||
| func (r *blakeMacAlgorithm) Sign(sig, key []byte) ([]byte, error) { | ||||
| 	hs, err := r.fn(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err = setSig(hs, sig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return hs.Sum(nil), nil | ||||
| } | ||||
| 
 | ||||
| func (r *blakeMacAlgorithm) Equal(sig, actualMAC, key []byte) (bool, error) { | ||||
| 	hs, err := r.fn(key) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	defer hs.Reset() | ||||
| 	err = setSig(hs, sig) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	expected := hs.Sum(nil) | ||||
| 	return subtle.ConstantTimeCompare(actualMAC, expected) == 1, nil | ||||
| } | ||||
| 
 | ||||
| func (r *blakeMacAlgorithm) String() string { | ||||
| 	return fmt.Sprintf("%s", hashToDef[r.kind].name) | ||||
| } | ||||
| 
 | ||||
| func setSig(a hash.Hash, b []byte) error { | ||||
| 	n, err := a.Write(b) | ||||
| 	if err != nil { | ||||
| 		a.Reset() | ||||
| 		return err | ||||
| 	} else if n != len(b) { | ||||
| 		a.Reset() | ||||
| 		return fmt.Errorf("could only write %d of %d bytes of signature to hash", n, len(b)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // IsSupportedHttpSigAlgorithm returns true if the string is supported by this | ||||
| // library, is not a hash known to be weak, and is supported by the hardware. | ||||
| func IsSupportedHttpSigAlgorithm(algo string) bool { | ||||
| 	a, err := isAvailable(algo) | ||||
| 	return a && err == nil | ||||
| } | ||||
| 
 | ||||
| // isAvailable is an internally public function | ||||
| func isAvailable(algo string) (bool, error) { | ||||
| 	c, ok := stringToHash[algo] | ||||
| 	if !ok { | ||||
| 		return false, fmt.Errorf("no match for %q", algo) | ||||
| 	} | ||||
| 	if isForbiddenHash(c) { | ||||
| 		return false, fmt.Errorf("forbidden hash type in %q", algo) | ||||
| 	} | ||||
| 	return c.Available(), nil | ||||
| } | ||||
| 
 | ||||
| func newAlgorithmConstructor(algo string) (fn func(k []byte) (hash.Hash, error), c crypto.Hash, e error) { | ||||
| 	ok := false | ||||
| 	c, ok = stringToHash[algo] | ||||
| 	if !ok { | ||||
| 		e = fmt.Errorf("no match for %q", algo) | ||||
| 		return | ||||
| 	} | ||||
| 	if isForbiddenHash(c) { | ||||
| 		e = fmt.Errorf("forbidden hash type in %q", algo) | ||||
| 		return | ||||
| 	} | ||||
| 	algoDef, ok := hashToDef[c] | ||||
| 	if !ok { | ||||
| 		e = fmt.Errorf("have crypto.Hash %v but no definition", c) | ||||
| 		return | ||||
| 	} | ||||
| 	fn = func(key []byte) (hash.Hash, error) { | ||||
| 		h, err := algoDef.new(key) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return h, nil | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func newAlgorithm(algo string, key []byte) (hash.Hash, crypto.Hash, error) { | ||||
| 	fn, c, err := newAlgorithmConstructor(algo) | ||||
| 	if err != nil { | ||||
| 		return nil, c, err | ||||
| 	} | ||||
| 	h, err := fn(key) | ||||
| 	return h, c, err | ||||
| } | ||||
| 
 | ||||
| func signerFromSSHSigner(sshSigner ssh.Signer, s string) (signer, error) { | ||||
| 	switch { | ||||
| 	case strings.HasPrefix(s, rsaPrefix): | ||||
| 		return &rsaAlgorithm{ | ||||
| 			sshSigner: sshSigner, | ||||
| 		}, nil | ||||
| 	case strings.HasPrefix(s, ed25519Prefix): | ||||
| 		return &ed25519Algorithm{ | ||||
| 			sshSigner: sshSigner, | ||||
| 		}, nil | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("no signer matching %q", s) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // signerFromString is an internally public method constructor | ||||
| func signerFromString(s string) (signer, error) { | ||||
| 	s = strings.ToLower(s) | ||||
| 	isEcdsa := false | ||||
| 	isEd25519 := false | ||||
| 	var algo string = "" | ||||
| 	if strings.HasPrefix(s, ecdsaPrefix) { | ||||
| 		algo = strings.TrimPrefix(s, ecdsaPrefix+"-") | ||||
| 		isEcdsa = true | ||||
| 	} else if strings.HasPrefix(s, rsaPrefix) { | ||||
| 		algo = strings.TrimPrefix(s, rsaPrefix+"-") | ||||
| 	} else if strings.HasPrefix(s, ed25519Prefix) { | ||||
| 		isEd25519 = true | ||||
| 		algo = "sha512" | ||||
| 	} else { | ||||
| 		return nil, fmt.Errorf("no signer matching %q", s) | ||||
| 	} | ||||
| 	hash, cHash, err := newAlgorithm(algo, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if isEd25519 { | ||||
| 		return &ed25519Algorithm{}, nil | ||||
| 	} | ||||
| 	if isEcdsa { | ||||
| 		return &ecdsaAlgorithm{ | ||||
| 			Hash: hash, | ||||
| 			kind: cHash, | ||||
| 		}, nil | ||||
| 	} | ||||
| 	return &rsaAlgorithm{ | ||||
| 		Hash: hash, | ||||
| 		kind: cHash, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // macerFromString is an internally public method constructor | ||||
| func macerFromString(s string) (macer, error) { | ||||
| 	s = strings.ToLower(s) | ||||
| 	if strings.HasPrefix(s, hmacPrefix) { | ||||
| 		algo := strings.TrimPrefix(s, hmacPrefix+"-") | ||||
| 		hashFn, cHash, err := newAlgorithmConstructor(algo) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		// Ensure below does not panic | ||||
| 		_, err = hashFn(nil) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &hmacAlgorithm{ | ||||
| 			fn: func(key []byte) (hash.Hash, error) { | ||||
| 				return hmac.New(func() hash.Hash { | ||||
| 					h, e := hashFn(nil) | ||||
| 					if e != nil { | ||||
| 						panic(e) | ||||
| 					} | ||||
| 					return h | ||||
| 				}, key), nil | ||||
| 			}, | ||||
| 			kind: cHash, | ||||
| 		}, nil | ||||
| 	} else if bl, ok := stringToHash[s]; ok && blake2Algorithms[bl] { | ||||
| 		hashFn, cHash, err := newAlgorithmConstructor(s) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &blakeMacAlgorithm{ | ||||
| 			fn:   hashFn, | ||||
| 			kind: cHash, | ||||
| 		}, nil | ||||
| 	} else { | ||||
| 		return nil, fmt.Errorf("no MACer matching %q", s) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue