forked from keybase/client
/
attachment_crypt.go
157 lines (128 loc) · 5.32 KB
/
attachment_crypt.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package chat
import (
"crypto/rand"
"errors"
"io"
"github.com/keybase/client/go/chat/signencrypt"
"github.com/keybase/client/go/libkb"
"github.com/keybase/go-crypto/ed25519"
)
type Encrypter interface {
// EncryptedLen returns the number of bytes that the ciphertext of
// size plaintext bytes will be.
EncryptedLen(size int) int
// Encrypt takes a plaintext reader and returns a ciphertext reader.
// It generates new keys every time it is called and uses a
// constant nonce.
Encrypt(plaintext io.Reader) (ciphertext io.Reader, err error)
// EncryptWithNonce takes a plaintext reader and returns a ciphertext reader.
// It generates new keys every time it is called and uses
// the provided nonce.
EncryptWithNonce(plaintext io.Reader, nonce signencrypt.Nonce) (ciphertext io.Reader, err error)
// EncryptResume takes a plaintext reader and a set of keys. It
// returns a ciphertext reader. It *does not* generate new keys
// but uses the parameter keys. These keys should *only* be used
// to encrypt the same plaintext as a previous attempt.
EncryptResume(r io.Reader, nonce signencrypt.Nonce, encKey signencrypt.SecretboxKey, signKey signencrypt.SignKey, verifyKey signencrypt.VerifyKey) (io.Reader, error)
// EncryptKey returns the ephemeral key that was used during the
// last invocation of Encrypt.
EncryptKey() []byte
// VerifyKey returns the public portion of the signing key used during
// the last invocation of Encrypt. It can be used for signature
// verification.
VerifyKey() []byte
}
type Decrypter interface {
// Decrypt takes a ciphertext reader, encryption and verify keys.
// It returns a plaintext reader. It uses the constant nonce.
Decrypt(ciphertext io.Reader, encKey, verifyKey []byte) (plaintext io.Reader)
// DecryptWithNonce takes a ciphertext reader, nonce, encryption and verify keys.
// It returns a plaintext reader.
DecryptWithNonce(ciphertext io.Reader, nonce signencrypt.Nonce, encKey, verifyKey []byte) (plaintext io.Reader)
}
// The ASCII bytes "kbchatattachment".
var nonceConst signencrypt.Nonce = &[16]byte{0x6b, 0x62, 0x63, 0x68, 0x61, 0x74, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74}
type SignEncrypter struct {
encKey signencrypt.SecretboxKey
signKey signencrypt.SignKey
verifyKey signencrypt.VerifyKey
}
func NewSignEncrypter() *SignEncrypter {
return &SignEncrypter{}
}
func (s *SignEncrypter) EncryptedLen(size int) int {
return signencrypt.GetSealedSize(size)
}
func (s *SignEncrypter) Encrypt(r io.Reader) (io.Reader, error) {
// It is *very* important that Encrypt calls makeKeys() to make
// new keys every time it runs. The keys it uses cannot be reused
// since we are using a constant nonce.
if err := s.makeKeys(); err != nil {
return nil, err
}
return signencrypt.NewEncodingReader(s.encKey, s.signKey, libkb.SignaturePrefixChatAttachment, nonceConst, r), nil
}
func (s *SignEncrypter) EncryptWithNonce(r io.Reader, nonce signencrypt.Nonce) (io.Reader, error) {
if err := s.makeKeys(); err != nil {
return nil, err
}
return signencrypt.NewEncodingReader(s.encKey, s.signKey, libkb.SignaturePrefixChatAttachment, nonce, r), nil
}
// EncryptResume is used to create a SignEncrypter to resume an interrupted attachment upload.
// It is *very* important that the keys passed in are not used to encrypt different plaintext
// than their original usage.
func (s *SignEncrypter) EncryptResume(r io.Reader, nonce signencrypt.Nonce, encKey signencrypt.SecretboxKey, signKey signencrypt.SignKey, verifyKey signencrypt.VerifyKey) (io.Reader, error) {
s.encKey = encKey
s.signKey = signKey
s.verifyKey = verifyKey
return signencrypt.NewEncodingReader(s.encKey, s.signKey, libkb.SignaturePrefixChatAttachment, nonce, r), nil
}
func (s *SignEncrypter) EncryptKey() []byte {
return []byte((*s.encKey)[:])
}
func (s *SignEncrypter) SignKey() []byte {
return []byte((*s.signKey)[:])
}
func (s *SignEncrypter) VerifyKey() []byte {
return []byte((*s.verifyKey)[:])
}
func (s *SignEncrypter) makeKeys() error {
var encKey [signencrypt.SecretboxKeySize]byte
n, err := rand.Read(encKey[:])
if err != nil {
return err
}
if n != signencrypt.SecretboxKeySize {
return errors.New("failed to rand.Read the correct number of bytes")
}
sign, err := libkb.GenerateNaclSigningKeyPair()
if err != nil {
return err
}
var signKey [ed25519.PrivateKeySize]byte
copy(signKey[:], (*sign.Private)[:])
var verifyKey [ed25519.PublicKeySize]byte
copy(verifyKey[:], sign.Public[:])
s.encKey = &encKey
s.signKey = &signKey
s.verifyKey = &verifyKey
return nil
}
type SignDecrypter struct{}
func NewSignDecrypter() *SignDecrypter {
return &SignDecrypter{}
}
func (s *SignDecrypter) Decrypt(r io.Reader, encKey, verifyKey []byte) io.Reader {
var xencKey [signencrypt.SecretboxKeySize]byte
copy(xencKey[:], encKey)
var xverifyKey [ed25519.PublicKeySize]byte
copy(xverifyKey[:], verifyKey)
return signencrypt.NewDecodingReader(&xencKey, &xverifyKey, libkb.SignaturePrefixChatAttachment, nonceConst, r)
}
func (s *SignDecrypter) DecryptWithNonce(r io.Reader, nonce signencrypt.Nonce, encKey, verifyKey []byte) (plaintext io.Reader) {
var xencKey [signencrypt.SecretboxKeySize]byte
copy(xencKey[:], encKey)
var xverifyKey [ed25519.PublicKeySize]byte
copy(xverifyKey[:], verifyKey)
return signencrypt.NewDecodingReader(&xencKey, &xverifyKey, libkb.SignaturePrefixChatAttachment, nonce, r)
}