-
Notifications
You must be signed in to change notification settings - Fork 11
/
signaling.go
102 lines (80 loc) · 2.35 KB
/
signaling.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
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
// SPDX-License-Identifier: Apache-2.0
package signaling
import (
"errors"
"fmt"
"golang.org/x/crypto/nacl/box"
"google.golang.org/protobuf/proto"
"cunicu.li/cunicu/pkg/crypto"
)
var (
errKeyPairMismatch = errors.New("key pair mismatch")
errInvalidNonceLength = errors.New("invalid nonce length")
errFailedToDecrypt = errors.New("failed to open")
)
func (e *Envelope) PublicKeyPair() (crypto.PublicKeyPair, error) {
sender, err := crypto.ParseKeyBytes(e.Sender)
if err != nil {
return crypto.PublicKeyPair{}, fmt.Errorf("invalid key: %w", err)
}
recipient, err := crypto.ParseKeyBytes(e.Recipient)
if err != nil {
return crypto.PublicKeyPair{}, fmt.Errorf("invalid key: %w", err)
}
return crypto.PublicKeyPair{
Ours: recipient,
Theirs: sender,
}, nil
}
func (e *Envelope) Decrypt(kp *crypto.KeyPair) (*Message, error) {
ekp, err := e.PublicKeyPair()
if err != nil {
return nil, fmt.Errorf("failed to get keys from envelope: %w", err)
}
if ekp != kp.Public() {
return nil, errKeyPairMismatch
}
msg := &Message{}
return msg, e.Contents.Unmarshal(msg, kp)
}
func (e *Message) Encrypt(kp *crypto.KeyPair) (*Envelope, error) {
envp := &Envelope{
Sender: kp.Ours.PublicKey().Bytes(),
Recipient: kp.Theirs.Bytes(),
Contents: &EncryptedMessage{},
}
return envp, envp.Contents.Marshal(e, kp)
}
func (e *Envelope) DeepCopyInto(out *Envelope) {
p, ok := proto.Clone(e).(*Envelope)
if !ok {
panic("type assertion failed")
}
*out = *p //nolint:govet
}
func (s *EncryptedMessage) Marshal(msg proto.Message, kp *crypto.KeyPair) error {
body, err := proto.Marshal(msg)
if err != nil {
return fmt.Errorf("failed to marshal: %w", err)
}
s.Nonce, err = crypto.GetNonce(24)
if err != nil {
return fmt.Errorf("failed to create nonce: %w", err)
}
s.Body = box.Seal([]byte{}, body, (*[24]byte)(s.Nonce), (*[32]byte)(&kp.Theirs), (*[32]byte)(&kp.Ours))
if err != nil {
return fmt.Errorf("failed to seal: %w", err)
}
return nil
}
func (s *EncryptedMessage) Unmarshal(msg proto.Message, kp *crypto.KeyPair) error {
if len(s.Nonce) != 24 {
return errInvalidNonceLength
}
body, ok := box.Open([]byte{}, s.Body, (*[24]byte)(s.Nonce), (*[32]byte)(&kp.Theirs), (*[32]byte)(&kp.Ours))
if !ok {
return errFailedToDecrypt
}
return proto.Unmarshal(body, msg)
}