Created
April 18, 2015 03:43
-
-
Save techjanitor/4a3f4321f5dba567a56a to your computer and use it in GitHub Desktop.
Example of web safe, hmac signed JSON messages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/hmac" | |
"crypto/sha256" | |
"encoding/base64" | |
"encoding/json" | |
"fmt" | |
"time" | |
) | |
var secret = "really top secret" | |
// Register contains information for initial account creation | |
type Register struct { | |
Issued int64 `json:"i"` | |
User string `json:"u"` | |
Email string `json:"e"` | |
} | |
// Encode marshals the data to JSON | |
func (r *Register) Encode() (message []byte, err error) { | |
message, err = json.Marshal(r) | |
if err != nil { | |
return | |
} | |
return | |
} | |
// Decode unmarshals the data to JSON | |
func (r *Register) Decode(message []byte) (err error) { | |
// Unmarshal JSON into struct | |
err = json.Unmarshal(message, r) | |
if err != nil { | |
return | |
} | |
return | |
} | |
func main() { | |
// Data | |
register := Register{ | |
Issued: time.Now().Unix(), | |
User: "user", | |
Email: "user@bullshit.com", | |
} | |
var err error | |
// | |
// Encode | |
// | |
// Initialize SignedMessage struct | |
message := SignedMessage{} | |
// Encode payload data to JSON | |
message.Payload, err = register.Encode() | |
if err != nil { | |
return | |
} | |
// Create HMAC signature | |
message.Sign() | |
// Marshal message to JSON and encode in url-safe base64 | |
signedmessage, err := message.Encode() | |
if err != nil { | |
return | |
} | |
fmt.Println(signedmessage) | |
// | |
// Decode | |
// | |
// Initialize SignedMessage struct | |
decodedmessage := SignedMessage{} | |
// Decode message from url-safe base64 and unmarshal JSON | |
err = decodedmessage.Decode(signedmessage) | |
if err != nil { | |
return | |
} | |
// Verify signatures | |
check := decodedmessage.Verify() | |
decodedregister := Register{} | |
// Decode info to register struct | |
decodedregister.Decode(decodedmessage.Payload) | |
fmt.Println("Data:", decodedregister) | |
fmt.Println("Verify:", check) | |
} | |
// SignedMessage contains a payload and a signature | |
type SignedMessage struct { | |
Payload []byte `json:"p"` | |
Signature []byte `json:"s"` | |
} | |
// Encode marshals the data to JSON and url-safe base64 encodes it | |
func (sm *SignedMessage) Encode() (message string, err error) { | |
msg, err := json.Marshal(sm) | |
if err != nil { | |
return | |
} | |
message = base64.URLEncoding.EncodeToString(msg) | |
return | |
} | |
// Decode will unencode the url-safe base64 message and unmarshal to JSON | |
func (sm *SignedMessage) Decode(message string) (err error) { | |
// Decode message | |
msg, err := base64.URLEncoding.DecodeString(message) | |
if err != nil { | |
return | |
} | |
// Unmarshal JSON into struct | |
err = json.Unmarshal(msg, sm) | |
if err != nil { | |
return | |
} | |
return | |
} | |
// Sign creates a HMAC signature for the message | |
func (sm *SignedMessage) Sign() { | |
mac := hmac.New(sha256.New, []byte(secret)) | |
mac.Write(sm.Payload) | |
sm.Signature = []byte(base64.StdEncoding.EncodeToString(mac.Sum(nil))) | |
} | |
// CheckSignature takes the base64 encoded message and signature | |
func (sm *SignedMessage) Verify() bool { | |
mac := hmac.New(sha256.New, []byte(secret)) | |
mac.Write(sm.Payload) | |
expected := []byte(base64.StdEncoding.EncodeToString(mac.Sum(nil))) | |
return hmac.Equal(sm.Signature, expected) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment