2025-01-28 00:44:02 +09:00
|
|
|
package hodu
|
|
|
|
|
|
|
|
import "crypto"
|
2025-01-31 04:06:03 +09:00
|
|
|
//import "crypto/hmac"
|
2025-01-28 00:44:02 +09:00
|
|
|
import "crypto/rand"
|
|
|
|
import "crypto/rsa"
|
|
|
|
import "encoding/base64"
|
|
|
|
import "encoding/json"
|
|
|
|
import "fmt"
|
|
|
|
import "hash"
|
|
|
|
import "strings"
|
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
/*
|
2025-01-28 00:44:02 +09:00
|
|
|
func Sign(data []byte, privkey *rsa.PrivateKey) ([]byte, error) {
|
|
|
|
var h hash.Hash
|
|
|
|
|
|
|
|
h = crypto.SHA512.New()
|
|
|
|
h.Write(data)
|
|
|
|
|
2025-01-28 23:50:28 +09:00
|
|
|
//fmt.Printf("%+v\n", h.Sum(nil))
|
2025-01-28 00:44:02 +09:00
|
|
|
return rsa.SignPKCS1v15(rand.Reader, privkey, crypto.SHA512, h.Sum(nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
func Verify(data []byte, pubkey *rsa.PublicKey, sig []byte) error {
|
|
|
|
var h hash.Hash
|
|
|
|
|
|
|
|
h = crypto.SHA512.New()
|
|
|
|
h.Write(data)
|
|
|
|
|
|
|
|
return rsa.VerifyPKCS1v15(pubkey, crypto.SHA512, h.Sum(nil), sig)
|
|
|
|
}
|
|
|
|
|
|
|
|
func SignHS512(data []byte, key string) ([]byte, error) {
|
|
|
|
var h hash.Hash
|
|
|
|
|
|
|
|
h = hmac.New(crypto.SHA512.New, []byte(key))
|
|
|
|
h.Write(data)
|
|
|
|
|
|
|
|
return h.Sum(nil), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func VerifyHS512(data []byte, key string, sig []byte) error {
|
|
|
|
var h hash.Hash
|
|
|
|
|
|
|
|
h = crypto.SHA512.New()
|
|
|
|
h.Write(data)
|
|
|
|
|
|
|
|
if !hmac.Equal(h.Sum(nil), sig) { return fmt.Errorf("invalid signature") }
|
|
|
|
return nil
|
|
|
|
}
|
2025-01-31 04:06:03 +09:00
|
|
|
*/
|
2025-01-28 00:44:02 +09:00
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
type JWT[T any] struct {
|
|
|
|
key *rsa.PrivateKey
|
|
|
|
claims *T
|
2025-01-28 00:44:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
type JWTHeader struct {
|
|
|
|
Algo string `json:"alg"`
|
|
|
|
Type string `json:"typ"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type JWTClaimMap map[string]interface{}
|
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
func NewJWT[T any](key *rsa.PrivateKey, claims *T) *JWT[T] {
|
|
|
|
return &JWT[T]{key: key, claims: claims}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j *JWT[T]) SignRS512() (string, error) {
|
2025-01-28 00:44:02 +09:00
|
|
|
var h JWTHeader
|
|
|
|
var hb []byte
|
|
|
|
var cb []byte
|
|
|
|
var ss string
|
|
|
|
var sb []byte
|
2025-01-31 04:06:03 +09:00
|
|
|
var hs hash.Hash
|
2025-01-28 00:44:02 +09:00
|
|
|
var err error
|
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
h.Algo = "RS512"
|
2025-01-28 00:44:02 +09:00
|
|
|
h.Type = "JWT"
|
|
|
|
|
|
|
|
hb, err = json.Marshal(h)
|
|
|
|
if err != nil { return "", err }
|
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
cb, err = json.Marshal(j.claims)
|
2025-01-28 00:44:02 +09:00
|
|
|
if err != nil { return "", err }
|
|
|
|
|
|
|
|
ss = base64.RawURLEncoding.EncodeToString(hb) + "." + base64.RawURLEncoding.EncodeToString(cb)
|
2025-01-31 04:06:03 +09:00
|
|
|
|
|
|
|
hs = crypto.SHA512.New()
|
|
|
|
hs.Write([]byte(ss))
|
|
|
|
|
|
|
|
sb, err = rsa.SignPKCS1v15(rand.Reader, j.key, crypto.SHA512, hs.Sum(nil))
|
2025-01-28 00:44:02 +09:00
|
|
|
if err != nil { return "", err }
|
|
|
|
|
2025-01-28 23:50:28 +09:00
|
|
|
//fmt.Printf ("%+v %+v %s\n", string(hb), string(cb), (ss + "." + base64.RawURLEncoding.EncodeToString(sb)))
|
2025-01-28 00:44:02 +09:00
|
|
|
return ss + "." + base64.RawURLEncoding.EncodeToString(sb), nil
|
|
|
|
}
|
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
func (j *JWT[T]) VerifyRS512(tok string) error {
|
2025-01-28 00:44:02 +09:00
|
|
|
var segs []string
|
|
|
|
var hb []byte
|
|
|
|
var cb []byte
|
2025-01-31 04:06:03 +09:00
|
|
|
var ss []byte
|
2025-01-28 00:44:02 +09:00
|
|
|
var jh JWTHeader
|
2025-01-31 04:06:03 +09:00
|
|
|
var hs hash.Hash
|
2025-01-28 00:44:02 +09:00
|
|
|
var err error
|
|
|
|
|
|
|
|
segs = strings.Split(tok, ".")
|
|
|
|
if len(segs) != 3 { return fmt.Errorf("invalid token") }
|
|
|
|
|
|
|
|
hb, err = base64.RawURLEncoding.DecodeString(segs[0])
|
|
|
|
if err != nil { return fmt.Errorf("invalid header - %s", err.Error()) }
|
|
|
|
err = json.Unmarshal(hb, &jh)
|
|
|
|
if err != nil { return fmt.Errorf("invalid header - %s", err.Error()) }
|
2025-01-31 04:06:03 +09:00
|
|
|
|
|
|
|
if jh.Algo != "RS512" || jh.Type != "JWT" { return fmt.Errorf("invalid header content %+v", jh) }
|
2025-01-28 00:44:02 +09:00
|
|
|
|
|
|
|
cb, err = base64.RawURLEncoding.DecodeString(segs[1])
|
|
|
|
if err != nil { return fmt.Errorf("invalid claims - %s", err.Error()) }
|
2025-01-31 04:06:03 +09:00
|
|
|
err = json.Unmarshal(cb, j.claims)
|
|
|
|
if err != nil { return fmt.Errorf("invalid claims - %s", err.Error()) }
|
2025-01-28 00:44:02 +09:00
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
ss, err = base64.RawURLEncoding.DecodeString(segs[2])
|
|
|
|
if err != nil { return fmt.Errorf("invalid signature - %s", err.Error()) }
|
2025-01-28 00:44:02 +09:00
|
|
|
|
2025-01-31 04:06:03 +09:00
|
|
|
hs = crypto.SHA512.New()
|
|
|
|
hs.Write([]byte(segs[0]))
|
|
|
|
hs.Write([]byte("."))
|
|
|
|
hs.Write([]byte(segs[1]))
|
|
|
|
err = rsa.VerifyPKCS1v15(&j.key.PublicKey, crypto.SHA512, hs.Sum(nil), ss)
|
|
|
|
if err != nil { return fmt.Errorf("unverifiable signature - %s", err.Error()) }
|
2025-01-28 00:44:02 +09:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|