<commit_before>package jwt

//go:generate stringer -type Algorithm -output alg_string.go .

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rsa"
	"errors"
	"fmt"

	"github.com/knq/pemutil"
)

// Algorithm is the type for signing algorithms implemented in this package.
type Algorithm uint

// Signer is the shared interface for an Algorithm's encoding, decoding,
// signing, and verify to handle the crypto primitives and lower-level API
// calls.
type Signer interface {
	// Sign creates a signature for buf, returning it as a URL-safe base64
	// encoded byte slice.
	Sign(buf []byte) ([]byte, error)

	// Verify creates a signature for buf, comparing it against the URL-safe
	// base64 encoded sig. If the sig is invalid, then ErrInvalidSignature will
	// be returned.
	Verify(buf, sig []byte) ([]byte, error)

	// Encode encodes obj as a serialized JWT.
	Encode(obj interface{}) ([]byte, error)

	// Decode decodes a serialized JWT in buf into obj, and verifying the JWT
	// signature in the process.
	Decode(buf []byte, obj interface{}) error
}

// PEM is a wrapper that assists with loading PEM-encoded crypto primitives
// (ie, rsa.PrivateKey, ecdsa.PrivateKey, etc).
type PEM pemutil.PEM

const (
	// NONE provides a JWT signing method for NONE.
	//
	// NOTE: This is not implemented for security reasons.
	NONE Algorithm = iota

	// HS256 provides a JWT signing method for HMAC using SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS256

	// HS384 provides a JWT signing method for HMAC using SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS384

	// HS512 provides a JWT signing method for HMAC using SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS512

	// RS256 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS256

	// RS384 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS384

	// RS512 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS512

	// ES256 provides a JWT signing method for ECDSA using P-256 and SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES256

	// ES384 provides a JWT signing method for ECDSA using P-384 and SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES384

	// ES512 provides a JWT signing method for ECDSA using P-521 and SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES512

	// PS256 provides a JWT signing method for RSASSA-PSS using SHA-256 and
	// MGF1 mask generation function with SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS256

	// PS384 provides a JWT signing method for RSASSA-PSS using SHA-384 hash
	// algorithm and MGF1 mask generation function with SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS384

	// PS512 provides a JWT signing method for RSASSA-PSS using SHA-512 hash
	// algorithm and MGF1 mask generation function with SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS512
)

// algMap is a map of algorithm implementations to its Algorithm.
var algMap = map[Algorithm]struct {
	newFunc func(pemutil.Store, crypto.Hash) (Signer, error)
	hash    crypto.Hash
}{
	// none
	NONE: {func(pemutil.Store, crypto.Hash) (Signer, error) {
		return nil, errors.New("jwt algorithm none is not implemented")
	}, crypto.SHA256},

	// HS256 is HMAC + SHA-256
	HS256: {NewHMACSigner(HS256), crypto.SHA256},

	// HS384 is HMAC + SHA-384
	HS384: {NewHMACSigner(HS384), crypto.SHA384},

	// HS512 is HMAC + SHA-512
	HS512: {NewHMACSigner(HS512), crypto.SHA512},

	// RS256 is RSASSA-PKCS1-V1_5 + SHA-256
	RS256: {NewRSASigner(RS256, rsaMethodPKCS1v15), crypto.SHA256},

	// RS384 is RSASSA-PKCS1-V1_5 + SHA-384
	RS384: {NewRSASigner(RS384, rsaMethodPKCS1v15), crypto.SHA384},

	// RS512 is RSASSA-PKCS1-V1_5 + SHA-512
	RS512: {NewRSASigner(RS512, rsaMethodPKCS1v15), crypto.SHA512},

	// ES256 is ECDSA P-256 + SHA-256
	ES256: {NewEllipticSigner(ES256, elliptic.P256()), crypto.SHA256},

	// ES384 is ECDSA P-384 + SHA-384
	ES384: {NewEllipticSigner(ES384, elliptic.P384()), crypto.SHA384},

	// ES512 is ECDSA P-521 + SHA-512
	ES512: {NewEllipticSigner(ES512, elliptic.P521()), crypto.SHA512},

	// PS256 is RSASSA-PSS + SHA-256
	PS256: {NewRSASigner(PS256, rsaMethodPSS), crypto.SHA256},

	// PS384 is RSASSA-PSS + SHA-384
	PS384: {NewRSASigner(PS384, rsaMethodPSS), crypto.SHA384},

	// PS512 is RSASSA-PSS + SHA-512
	PS512: {NewRSASigner(PS512, rsaMethodPSS), crypto.SHA512},
}

// New creates a Signer using the supplied keyset.
//
// The keyset can be of type PEM, pemutil.PEM, pemutil.Store,
// *rsa.{PrivateKey,PublicKey}, *ecdsa.{PrivateKey,PublicKey}, or []byte.
//
// If a private key is not provided, tokens cannot be Encode'd.  Public keys
// will be automatically generated for RSA and ECC private keys if none were
// provided in the keyset.
func (alg Algorithm) New(keyset interface{}) (Signer, error) {
	var err error

	a := algMap[alg]

	// check hash
	if !a.hash.Available() {
		return nil, fmt.Errorf("%s.New: crypto hash unavailable", alg)
	}

	var store pemutil.Store

	// load the data
	switch p := keyset.(type) {
	case pemutil.Store:
		store = p<commit_msg>Converting algMap to slice<commit_after>package jwt

//go:generate stringer -type Algorithm -output alg_string.go .

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rsa"
	"errors"
	"fmt"

	"github.com/knq/pemutil"
)

// Algorithm is the type for signing algorithms implemented in this package.
type Algorithm uint

// Signer is the shared interface for an Algorithm's encoding, decoding,
// signing, and verify to handle the crypto primitives and lower-level API
// calls.
type Signer interface {
	// Sign creates a signature for buf, returning it as a URL-safe base64
	// encoded byte slice.
	Sign(buf []byte) ([]byte, error)

	// Verify creates a signature for buf, comparing it against the URL-safe
	// base64 encoded sig. If the sig is invalid, then ErrInvalidSignature will
	// be returned.
	Verify(buf, sig []byte) ([]byte, error)

	// Encode encodes obj as a serialized JWT.
	Encode(obj interface{}) ([]byte, error)

	// Decode decodes a serialized JWT in buf into obj, and verifying the JWT
	// signature in the process.
	Decode(buf []byte, obj interface{}) error
}

// PEM is a wrapper that assists with loading PEM-encoded crypto primitives
// (ie, rsa.PrivateKey, ecdsa.PrivateKey, etc).
type PEM pemutil.PEM

const (
	// NONE provides a JWT signing method for NONE.
	//
	// NOTE: This is not implemented for security reasons.
	NONE Algorithm = iota

	// HS256 provides a JWT signing method for HMAC using SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS256

	// HS384 provides a JWT signing method for HMAC using SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS384

	// HS512 provides a JWT signing method for HMAC using SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.2
	HS512

	// RS256 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS256

	// RS384 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS384

	// RS512 provides a JWT signing method for RSASSA-PKCS1-V1_5 using SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.3
	RS512

	// ES256 provides a JWT signing method for ECDSA using P-256 and SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES256

	// ES384 provides a JWT signing method for ECDSA using P-384 and SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES384

	// ES512 provides a JWT signing method for ECDSA using P-521 and SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.4
	ES512

	// PS256 provides a JWT signing method for RSASSA-PSS using SHA-256 and
	// MGF1 mask generation function with SHA-256.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS256

	// PS384 provides a JWT signing method for RSASSA-PSS using SHA-384 hash
	// algorithm and MGF1 mask generation function with SHA-384.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS384

	// PS512 provides a JWT signing method for RSASSA-PSS using SHA-512 hash
	// algorithm and MGF1 mask generation function with SHA-512.
	//
	// See http://tools.ietf.org/html/rfc7518#section-3.5
	PS512
)

// algSet is the set of Algorithm implementations.
var algSet = []struct {
	newFunc func(pemutil.Store, crypto.Hash) (Signer, error)
	hash    crypto.Hash
}{
	// none
	NONE: {func(pemutil.Store, crypto.Hash) (Signer, error) {
		return nil, errors.New("jwt algorithm none is not implemented")
	}, crypto.SHA256},

	// HS256 is HMAC + SHA-256
	HS256: {NewHMACSigner(HS256), crypto.SHA256},

	// HS384 is HMAC + SHA-384
	HS384: {NewHMACSigner(HS384), crypto.SHA384},

	// HS512 is HMAC + SHA-512
	HS512: {NewHMACSigner(HS512), crypto.SHA512},

	// RS256 is RSASSA-PKCS1-V1_5 + SHA-256
	RS256: {NewRSASigner(RS256, rsaMethodPKCS1v15), crypto.SHA256},

	// RS384 is RSASSA-PKCS1-V1_5 + SHA-384
	RS384: {NewRSASigner(RS384, rsaMethodPKCS1v15), crypto.SHA384},

	// RS512 is RSASSA-PKCS1-V1_5 + SHA-512
	RS512: {NewRSASigner(RS512, rsaMethodPKCS1v15), crypto.SHA512},

	// ES256 is ECDSA P-256 + SHA-256
	ES256: {NewEllipticSigner(ES256, elliptic.P256()), crypto.SHA256},

	// ES384 is ECDSA P-384 + SHA-384
	ES384: {NewEllipticSigner(ES384, elliptic.P384()), crypto.SHA384},

	// ES512 is ECDSA P-521 + SHA-512
	ES512: {NewEllipticSigner(ES512, elliptic.P521()), crypto.SHA512},

	// PS256 is RSASSA-PSS + SHA-256
	PS256: {NewRSASigner(PS256, rsaMethodPSS), crypto.SHA256},

	// PS384 is RSASSA-PSS + SHA-384
	PS384: {NewRSASigner(PS384, rsaMethodPSS), crypto.SHA384},

	// PS512 is RSASSA-PSS + SHA-512
	PS512: {NewRSASigner(PS512, rsaMethodPSS), crypto.SHA512},
}

// New creates a Signer using the supplied keyset.
//
// The keyset can be of type PEM, pemutil.PEM, pemutil.Store,
// *rsa.{PrivateKey,PublicKey}, *ecdsa.{PrivateKey,PublicKey}, or []byte.
//
// If a private key is not provided, tokens cannot be Encode'd.  Public keys
// will be automatically generated for RSA and ECC private keys if none were
// provided in the keyset.
func (alg Algorithm) New(keyset interface{}) (Signer, error) {
	var err error

	a := algSet[alg]

	// check hash
	if !a.hash.Available() {
		return nil, fmt.Errorf("%s.New: crypto hash unavailable", alg)
	}

	var store pemutil.Store

	// load the data
	switch p := keyset.(type) {
	case pemutil.Store:
		store = p
{'fraction_non_alphanumeric': 0.12588322796578655, 'fraction_numerical': 0.08051320193380439, 'mean_word_length': 3.3392496974586527, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6547676', 'n_tokens_mistral': 4603, 'n_tokens_neox': 3911, 'n_words': 1159}