package jwt

import (
	"crypto"
	"crypto/hmac"
	"fmt"
	//imports the sha hash functions
	_ "crypto/sha256"
	//imports the sha hash functions
	_ "crypto/sha512"
)

var _ Algorithm = shaMAC{}

type _hmac struct {
	Secret []byte
	Hash   crypto.Hash
}

func (h _hmac) Sign(value []byte) (signature []byte, err error) {
	d := hmac.New(h.Hash.New, h.Secret)
	if _, err = d.Write(value); err != nil {
		err = Err{err, "in writing to decoder during signing"}
		return
	}

	signature = d.Sum(nil)

	return

}

func (h _hmac) Validate(body, signature []byte) (err error) {

	correctSig, err := h.Sign(body)
	if err != nil {
		return
	}

	//Prevents crafty timing attacks that sign their own stuff
	//used to use my own subtle.Equal or whatever since it
	//skipped the redundant length check in hmac.Equal, but no harm really.
	if !hmac.Equal(correctSig, signature) {
		err = ErrInvalidSignature
		return
	}

	return

}

type shaMAC struct{ _hmac }

func (s shaMAC) Size() int { return s.Hash.Size() }

func (s shaMAC) Name() string { return fmt.Sprintf("HS%d", s.Size()*8) }

//HS256 returns a SHA256 MAC Algorithm, a 256bit symmetric signing algorithm.
func HS256(secret []byte) Algorithm { return shaMAC{_hmac{secret, crypto.SHA256}} }

//HS384 returns a SHA384 MAC Algorithm, a 384bit symmetric signing algorithm.
func HS384(secret []byte) Algorithm { return shaMAC{_hmac{secret, crypto.SHA384}} }

//HS512 returns a SHA512 MAC Algorithm, a 512bit symmetric signing algorithm.
func HS512(secret []byte) Algorithm { return shaMAC{_hmac{secret, crypto.SHA512}} }
