-
Notifications
You must be signed in to change notification settings - Fork 0
/
sign.go
103 lines (85 loc) · 1.99 KB
/
sign.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package gopot
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"strconv"
"unsafe"
jsoniter "github.com/json-iterator/go"
)
var json jsoniter.API
func init() {
// Initialize the jsoniter configuration with the custom ascii escape encoder
jsoniter.RegisterTypeEncoderFunc("string", asciiEncode, asciiIsEmpty)
config := jsoniter.Config{
SortMapKeys: true,
ValidateJsonRawMessage: true,
}
// Freeze the jsoniter API
json = config.Froze()
}
func asciiEncode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
str := *(*string)(ptr)
stream.WriteRaw(strconv.QuoteToASCII(str))
}
func asciiIsEmpty(ptr unsafe.Pointer) bool {
if *(*string)(ptr) == "" {
return true
}
return false
}
// calculateHash returns a calculated hash from the provided data
func calculateHash(d interface{}) (hash [32]byte, err error) {
jdata, err := Marshal(d)
if err != nil {
return
}
hash = sha256.Sum256(jdata)
return
}
// CreateSignature creates a pot signature with the given secret
func CreateSignature(d interface{}, key *rsa.PrivateKey) (string, error) {
if key == nil {
return "", ErrNoSecret
}
hash, err := calculateHash(d)
if err != nil {
return "", err
}
signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash[:])
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), err
}
// Marshal marshals json with the POT separators added.
func Marshal(d interface{}) ([]byte, error) {
jdata, err := json.Marshal(d)
jdata = JSONAddSpaces(jdata)
return jdata, err
}
// JSONAddSpaces ands spaces after the value declarations in json
func JSONAddSpaces(src []byte) []byte {
var res []byte
isEscaped := false
isValue := false
for _, b := range src {
res = append(res, b)
if !isEscaped && b == '"' {
isValue = !isValue
}
if b == ':' && !isValue {
res = append(res, ' ')
}
if b == '\\' && !isEscaped {
isEscaped = true
continue
}
if isEscaped {
isEscaped = false
}
}
return res
}