forked from crow-misia/go-push-receiver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrypto.go
100 lines (85 loc) · 2.43 KB
/
crypto.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
/*
* Copyright (c) 2019 Zenichi Amano
*
* This file is part of go-push-receiver, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
package pushreceiver
import (
"crypto/elliptic"
"crypto/rand"
"encoding/base64"
pb "github.com/crow-misia/go-push-receiver/pb/mcs"
ece "github.com/crow-misia/http-ece"
"github.com/pkg/errors"
"math/big"
)
var cryptoCurve = elliptic.P256()
// appendCryptoInfo appends key for crypto to Credentials.
func (c *FCMCredentials) appendCryptoInfo() error {
privateKey, publicKey, err := generateKey(cryptoCurve)
if err != nil {
return errors.Wrap(err, "generate random key for FCM")
}
authSecret, err := generateSalt()
if err != nil {
return errors.Wrap(err, "generate random salt for FCM")
}
c.PrivateKey = privateKey
c.PublicKey = publicKey
c.AuthSecret = authSecret
return nil
}
func decryptData(data *pb.DataMessageStanza, privateKey []byte, authSecret []byte) (*MessageEvent, error) {
cryptoKeyData, err := findByKey(data.GetAppData(), "crypto-key")
if err != nil {
return nil, errors.Wrap(err, "dh is not provided")
}
cryptoKey, err := base64.URLEncoding.DecodeString(cryptoKeyData.GetValue()[3:])
if err != nil {
return nil, errors.Wrap(err, "decode decrypt data")
}
saltData, err := findByKey(data.GetAppData(), "encryption")
if err != nil {
return nil, errors.Wrap(err, "salt is not provided")
}
salt, err := base64.URLEncoding.DecodeString(saltData.GetValue()[5:])
if err != nil {
return nil, errors.Wrap(err, "decode salt")
}
bytes, err := ece.Decrypt(data.GetRawData(),
ece.WithEncoding(ece.AESGCM),
ece.WithPrivate(privateKey),
ece.WithDh(cryptoKey),
ece.WithSalt(salt),
ece.WithAuthSecret(authSecret),
)
if err != nil {
return nil, errors.Wrap(err, "decrypt HTTP-ECE data")
}
return newMessageEvent(data, bytes), nil
}
// generateKey generates for public key crypto.
func generateKey(curve elliptic.Curve) (private []byte, public []byte, err error) {
var x, y *big.Int
private, x, y, err = elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, nil, err
}
public = elliptic.Marshal(curve, x, y)
return
}
// generateSalt generates salt.
func generateSalt() ([]byte, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
return salt, err
}
func findByKey(data []*pb.AppData, key string) (*pb.AppData, error) {
for _, data := range data {
if *data.Key == key {
return data, nil
}
}
return nil, ErrNotFoundInAppData
}