Skip to content

Instantly share code, notes, and snippets.

@techjanitor
Created April 18, 2015 03:43
Show Gist options
  • Save techjanitor/4a3f4321f5dba567a56a to your computer and use it in GitHub Desktop.
Save techjanitor/4a3f4321f5dba567a56a to your computer and use it in GitHub Desktop.
Example of web safe, hmac signed JSON messages
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