跳到主要内容

签名及验证示例(Go)

package sign

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
)

// RsaPrivateKey is a holder of RSA private key
type RsaPrivateKey struct {
*rsa.PrivateKey
}

// Signer is an interface to define signature action(s)
type Signer interface {
Sign(data []byte) ([]byte, error)
}

//Sign is the signature method
func (r *RsaPrivateKey) Sign(data []byte) ([]byte, error) {
h := sha256.New()
h.Write(data)
d := h.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, r.PrivateKey, crypto.SHA256, d)
}

// LoadPrivateKey for load private key with file path
func LoadPrivateKey(path string) (Signer, error) {
fileBytes, e := ioutil.ReadFile(path)
if e != nil {
return nil, fmt.Errorf("could not load private key: %v", e)
}
return ParsePrivateKey(fileBytes)
}

func ParsePrivateKey(pemBytes []byte) (Signer, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}

var rawkey interface{}
switch block.Type {
case "RSA PRIVATE KEY":
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
return newSignerFromKey(rawkey)
}

func newSignerFromKey(k interface{}) (Signer, error) {
var sshKey Signer
switch t := k.(type) {
case *rsa.PrivateKey:
sshKey = &RsaPrivateKey{t}
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
package sign

import (
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)

//RsaPublicKey is a holder of RSA public key
type RsaPublicKey struct {
*rsa.PublicKey
}

//Verifier is an interface to define signature verification action(s)
type Verifier interface {
Verify(data []byte, sig []byte) error
}

//Verify is the verification method
func (r *RsaPublicKey) Verify(message []byte, sig []byte) error {
h := sha256.New()
h.Write(message)
d := h.Sum(nil)
return rsa.VerifyPKCS1v15(r.PublicKey, crypto.SHA256, d, sig)
}

//LoadTupuPublicKey for load embeded TUPU's public key
func LoadTupuPublicKey() (Verifier, error) {
return parsePublicKey([]byte(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDyZneSY2eGnhKrArxaT6zswVH9
/EKz+CLD+38kJigWj5UaRB6dDUK9BR6YIv0M9vVQZED2650tVhS3BeX04vEFhThn
NrJguVPidufFpEh3AgdYDzOQxi06AN+CGzOXPaigTurBxZDIbdU+zmtr6a8bIBBj
WQ4v2JR/BA6gVHV5TwIDAQAB
-----END PUBLIC KEY-----`))
}

func parsePublicKey(pemBytes []byte) (Verifier, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}

var rawkey interface{}
switch block.Type {
case "PUBLIC KEY":
rsa, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}

return newVerifierFromKey(rawkey)
}

func newVerifierFromKey(k interface{}) (Verifier, error) {
var sshKey Verifier
switch t := k.(type) {
case *rsa.PublicKey:
sshKey = &RsaPublicKey{t}
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
package sign

import (
"encoding/base64"
"encoding/json"
"log"
"os"
"testing"
)

var (
PrivateKey = "./my_private_key.pem"
PublicKey = ``
DATA = `{ "code": 0, "message": "success", "nonce": "0.01627771095362096", "timestamp": 1552391372490, "requestId": "tupu_request_id", "roomId": "your_room_id", "userId": "your_user_id", "forumId": "your_forum_id", "customInfo": {"hello": true, "other": "your customInfo"}, "5caee6b2a76925c55a09a6d2": { "label": "Politics", "review": false, "rate": 0.896484, "action": "block", "text": "毛泽东,你好", "violations": [{ "startTime": 12, "endTime": 15, "content": "毛泽东", "action": "block", "label": "Politics", "review": false, "rate": 0.896484, "speechUrl": "http:://123.mp3", "details": [{"keyword": "毛泽东", "hint": "毛泽东", "mainLabel": "Politics", "subLabel": "National_Leader"}] }] } }`
)

func Test_SignAndVerify_1(t *testing.T) {
signer, err := LoadPrivateKey(PrivateKey)
if err != nil {
t.Fatal(err)
}

verifier, err := LoadTupuPublicKey()
if err != nil {
t.Fatal(err)
}

data := DATA
sig, err := signer.Sign([]byte(data))
if err != nil {
log.Fatalf("error signing data: %v", err)
}
log.Println(base64.StdEncoding.EncodeToString(sig))

err = verifier.Verify([]byte(data), sig)
log.Println("test 1", err)

}

func Test_SignAndVerify_2(t *testing.T) {
signer, err := ParsePrivateKey([]byte(PublicKey))
if err != nil {
t.Fatal(err)
}

verifier, err := LoadTupuPublicKey()
if err != nil {
t.Fatal(err)
}

data := DATA
payload := make(map[string]interface{})
err = json.Unmarshal([]byte(data), &payload)
if err != nil {
log.Fatalf("error unmarshalling data: %v", err)
}

byt, err := json.Marshal(payload)
if err != nil {
log.Fatalf("error marshalling data: %v", err)
}
err = os.WriteFile("./marshalled.txt", byt, os.ModePerm)
if err != nil {
log.Printf("error writing marshalled json to file: %v", err)
}

sig, err := signer.Sign(byt)
if err != nil {
log.Fatalf("error signing data: %v", err)
}
log.Println(base64.StdEncoding.EncodeToString(sig))

err = verifier.Verify([]byte(data), sig)
log.Println("test 2", err)

}