From 5aed334e047f4f2d5edb421bdad4a7a426fb46bd Mon Sep 17 00:00:00 2001 From: Dave Grijalva Date: Sat, 5 Jul 2014 15:08:42 -0700 Subject: [PATCH] Added support for HS384 and HS512 signing methods Renamed type SigningMethodHS256 to SigningMethodHMAC Added contstants SigningMethodHS256, SigningMethodHS384, and SigningMethodHS512 to support each of these methods Added simple tests to support these new methods --- hmac.go | 65 ++++++++++++++++++++++++++++++++++ sha256_test.go => hmac_test.go | 43 ++++++++++++++-------- sha256.go | 41 --------------------- test/hmacTestKey | 1 + 4 files changed, 94 insertions(+), 56 deletions(-) create mode 100644 hmac.go rename sha256_test.go => hmac_test.go (56%) delete mode 100644 sha256.go create mode 100644 test/hmacTestKey diff --git a/hmac.go b/hmac.go new file mode 100644 index 0000000..b6c1b33 --- /dev/null +++ b/hmac.go @@ -0,0 +1,65 @@ +package jwt + +import ( + "bytes" + "crypto" + "crypto/hmac" + "errors" +) + +type SigningMethodHMAC struct { + Name string + Hash crypto.Hash +} + +var ( + SigningMethodHS256 *SigningMethodHMAC + SigningMethodHS384 *SigningMethodHMAC + SigningMethodHS512 *SigningMethodHMAC +) + +func init() { + // HS256 + SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256} + RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod { + return SigningMethodHS256 + }) + + // HS384 + SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384} + RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod { + return SigningMethodHS384 + }) + + // HS512 + SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512} + RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod { + return SigningMethodHS512 + }) +} + +func (m *SigningMethodHMAC) Alg() string { + return m.Name +} + +func (m *SigningMethodHMAC) Verify(signingString, signature string, key []byte) error { + // Key + var sig []byte + var err error + if sig, err = DecodeSegment(signature); err == nil { + hasher := hmac.New(m.Hash.New, key) + hasher.Write([]byte(signingString)) + + if !bytes.Equal(sig, hasher.Sum(nil)) { + err = errors.New("Signature is invalid") + } + } + return err +} + +func (m *SigningMethodHMAC) Sign(signingString string, key []byte) (string, error) { + hasher := hmac.New(m.Hash.New, key) + hasher.Write([]byte(signingString)) + + return EncodeSegment(hasher.Sum(nil)), nil +} diff --git a/sha256_test.go b/hmac_test.go similarity index 56% rename from sha256_test.go rename to hmac_test.go index 4dfbf84..64d319c 100644 --- a/sha256_test.go +++ b/hmac_test.go @@ -1,44 +1,57 @@ package jwt import ( + "io/ioutil" "strings" "testing" ) -var sha256TestData = []struct { +var hmacTestData = []struct { name string tokenString string + alg string claims map[string]interface{} valid bool }{ { "web sample", "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", + "HS256", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + true, + }, + { + "HS384", + "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.KWZEuOD5lbBxZ34g7F-SlVLAQ_r5KApWNWlZIIMyQVz5Zs58a7XdNzj5_0EcNoOy", + "HS384", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + true, + }, + { + "HS512", + "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.CN7YijRX6Aw1n2jyI2Id1w90ja-DEMYiWixhYCyHnrZ1VfJRaFQz1bEbjjA5Fn4CLYaUG432dEYmSbS4Saokmw", + "HS512", map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, true, }, { "web sample: invalid", "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXo", + "HS256", map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, false, }, } // Sample data from http://tools.ietf.org/html/draft-jones-json-web-signature-04#appendix-A.1 -var sha256TestKey = []byte{ - 3, 35, 53, 75, 43, 15, 165, 188, 131, 126, 6, 101, 119, 123, 166, - 143, 90, 179, 40, 230, 240, 84, 201, 40, 169, 15, 132, 178, 210, 80, - 46, 191, 211, 251, 90, 146, 210, 6, 71, 239, 150, 138, 180, 195, 119, - 98, 61, 34, 61, 46, 33, 114, 5, 46, 79, 8, 192, 205, 154, 245, 103, - 208, 128, 163} +var hmacTestKey, _ = ioutil.ReadFile("test/hmacTestKey") -func TestHS256Verify(t *testing.T) { - for _, data := range sha256TestData { +func TestHMACVerify(t *testing.T) { + for _, data := range hmacTestData { parts := strings.Split(data.tokenString, ".") - method := GetSigningMethod("HS256") - err := method.Verify(strings.Join(parts[0:2], "."), parts[2], sha256TestKey) + method := GetSigningMethod(data.alg) + err := method.Verify(strings.Join(parts[0:2], "."), parts[2], hmacTestKey) if data.valid && err != nil { t.Errorf("[%v] Error while verifying key: %v", data.name, err) } @@ -48,12 +61,12 @@ func TestHS256Verify(t *testing.T) { } } -func TestHS256Sign(t *testing.T) { - for _, data := range sha256TestData { +func TestHMACSign(t *testing.T) { + for _, data := range hmacTestData { if data.valid { parts := strings.Split(data.tokenString, ".") - method := GetSigningMethod("HS256") - sig, err := method.Sign(strings.Join(parts[0:2], "."), sha256TestKey) + method := GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), hmacTestKey) if err != nil { t.Errorf("[%v] Error signing token: %v", data.name, err) } diff --git a/sha256.go b/sha256.go deleted file mode 100644 index 4868b0b..0000000 --- a/sha256.go +++ /dev/null @@ -1,41 +0,0 @@ -package jwt - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "errors" -) - -type SigningMethodHS256 struct{} - -func init() { - RegisterSigningMethod("HS256", func() SigningMethod { - return new(SigningMethodHS256) - }) -} - -func (m *SigningMethodHS256) Alg() string { - return "HS256" -} - -func (m *SigningMethodHS256) Verify(signingString, signature string, key []byte) (err error) { - // Key - var sig []byte - if sig, err = DecodeSegment(signature); err == nil { - hasher := hmac.New(sha256.New, key) - hasher.Write([]byte(signingString)) - - if !bytes.Equal(sig, hasher.Sum(nil)) { - err = errors.New("Signature is invalid") - } - } - return -} - -func (m *SigningMethodHS256) Sign(signingString string, key []byte) (string, error) { - hasher := hmac.New(sha256.New, key) - hasher.Write([]byte(signingString)) - - return EncodeSegment(hasher.Sum(nil)), nil -} diff --git a/test/hmacTestKey b/test/hmacTestKey new file mode 100644 index 0000000..435b8dd --- /dev/null +++ b/test/hmacTestKey @@ -0,0 +1 @@ +#5K+~ew{Z(T(P.ZGwb="=.!r.O͚gЀ \ No newline at end of file