mirror of
https://github.com/kataras/iris.git
synced 2026-01-05 19:27:05 +00:00
implement the Iris Crypto Library for Request Authentication and Verification. With Examples and Tests.
Relative to this one as well: https://github.com/kataras/iris/issues/1200 Former-commit-id: 3a29e7398b7fdeb9b48a118b742d419d5681d56b
This commit is contained in:
94
crypto/json.go
Normal file
94
crypto/json.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/kataras/iris/crypto/sign"
|
||||
)
|
||||
|
||||
// Ticket contains the original payload raw data
|
||||
// and the generated signature.
|
||||
//
|
||||
// Look `SignJSON` and `VerifyJSON` for more details.
|
||||
type Ticket struct {
|
||||
Payload json.RawMessage `json:"payload"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
// SignJSON signs the incoming JSON request payload based on
|
||||
// client's "privateKey" and the "r" (could be ctx.Request().Body).
|
||||
//
|
||||
// It generates the signature and returns a structure called `Ticket`.
|
||||
// The `Ticket` just contains the original client's payload raw data
|
||||
// and the generated signature.
|
||||
//
|
||||
// Returns non-nil error if any error occurred.
|
||||
//
|
||||
// Usage:
|
||||
// ticket, err := crypto.SignJSON(testPrivateKey, ctx.Request().Body)
|
||||
// b, err := json.Marshal(ticket)
|
||||
// ctx.Write(b)
|
||||
func SignJSON(privateKey *ecdsa.PrivateKey, r io.Reader) (Ticket, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil || len(data) == 0 {
|
||||
return Ticket{}, err
|
||||
}
|
||||
|
||||
sig, err := sign.Sign(privateKey, data)
|
||||
if err != nil {
|
||||
return Ticket{}, err
|
||||
}
|
||||
|
||||
ticket := Ticket{
|
||||
Payload: data,
|
||||
Signature: base64.StdEncoding.EncodeToString(sig),
|
||||
}
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
// VerifyJSON verifies the incoming JSON request,
|
||||
// by reading the "r" which should decodes to a `Ticket`.
|
||||
// The `Ticket` is verified against the given "publicKey", the `Ticket#Signature` and
|
||||
// `Ticket#Payload` data (original request's payload data which was signed by `SignPayload`).
|
||||
//
|
||||
// Returns true wether the verification succeed or not.
|
||||
// The "toPayloadPtr" should be a pointer to a value of the same payload structure the client signed on.
|
||||
// If and only if the verification succeed the payload value is filled from the `Ticket#Payload` raw data.
|
||||
//
|
||||
// Check for both output arguments in order to:
|
||||
// 1. verification (true/false and error) and
|
||||
// 2. ticket's original json payload parsed and "toPayloadPtr" is filled successfully (error).
|
||||
//
|
||||
// Usage:
|
||||
// var myPayload myJSONStruct
|
||||
// ok, err := crypto.VerifyJSON(publicKey, ctx.Request().Body, &myPayload)
|
||||
func VerifyJSON(publicKey *ecdsa.PublicKey, r io.Reader, toPayloadPtr interface{}) (bool, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ticket := new(Ticket)
|
||||
err = json.Unmarshal(data, ticket)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
sig, err := base64.StdEncoding.DecodeString(ticket.Signature)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ok, err := sign.Verify(publicKey, sig, ticket.Payload)
|
||||
if ok && toPayloadPtr != nil {
|
||||
// if and only if the verification succeed we
|
||||
// set the payload to the structured/map value of "toPayloadPtr".
|
||||
err = json.Unmarshal(ticket.Payload, toPayloadPtr)
|
||||
}
|
||||
|
||||
return ok, err
|
||||
}
|
||||
Reference in New Issue
Block a user