forked from lestrrat-go/jwx
/
jwe.go
285 lines (253 loc) · 8.6 KB
/
jwe.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// Package jwe implements JWE as described in https://tools.ietf.org/html/rfc7516
package jwe
import (
"bytes"
"crypto/ecdsa"
"crypto/rsa"
"encoding/json"
"github.com/lestrrat-go/jwx/buffer"
"github.com/lestrrat-go/jwx/internal/debug"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
"github.com/pkg/errors"
)
// Encrypt takes the plaintext payload and encrypts it in JWE compact format.
func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{}, contentalg jwa.ContentEncryptionAlgorithm, compressalg jwa.CompressionAlgorithm) ([]byte, error) {
contentcrypt, err := NewAesCrypt(contentalg)
if err != nil {
return nil, errors.Wrap(err, `failed to create AES encrypter`)
}
var keyenc KeyEncrypter
var keysize int
switch keyalg {
case jwa.RSA1_5:
pubkey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, errors.New("invalid key: *rsa.PublicKey required")
}
keyenc, err = NewRSAPKCSKeyEncrypt(keyalg, pubkey)
if err != nil {
return nil, errors.Wrap(err, "failed to create RSA PKCS encrypter")
}
keysize = contentcrypt.KeySize() / 2
case jwa.RSA_OAEP, jwa.RSA_OAEP_256:
pubkey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, errors.New("invalid key: *rsa.PublicKey required")
}
keyenc, err = NewRSAOAEPKeyEncrypt(keyalg, pubkey)
if err != nil {
return nil, errors.Wrap(err, "failed to create RSA OAEP encrypter")
}
keysize = contentcrypt.KeySize() / 2
case jwa.A128KW, jwa.A192KW, jwa.A256KW:
sharedkey, ok := key.([]byte)
if !ok {
return nil, errors.New("invalid key: []byte required")
}
keyenc, err = NewKeyWrapEncrypt(keyalg, sharedkey)
if err != nil {
return nil, errors.Wrap(err, "failed to create key wrap encrypter")
}
keysize = contentcrypt.KeySize()
switch aesKeySize := keysize / 2; aesKeySize {
case 16, 24, 32:
default:
return nil, errors.Errorf("unsupported keysize %d (from content encryption algorithm %s). consider using content encryption that uses 32, 48, or 64 byte keys", keysize, contentalg)
}
case jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW:
pubkey, ok := key.(*ecdsa.PublicKey)
if !ok {
return nil, errors.New("invalid key: *ecdsa.PublicKey required")
}
keyenc, err = NewEcdhesKeyWrapEncrypt(keyalg, pubkey)
if err != nil {
return nil, errors.Wrap(err, "failed to create ECDHS key wrap encrypter")
}
keysize = contentcrypt.KeySize() / 2
case jwa.ECDH_ES:
fallthrough
case jwa.A128GCMKW, jwa.A192GCMKW, jwa.A256GCMKW:
fallthrough
case jwa.PBES2_HS256_A128KW, jwa.PBES2_HS384_A192KW, jwa.PBES2_HS512_A256KW:
fallthrough
default:
if debug.Enabled {
debug.Printf("Encrypt: unknown key encryption algorithm: %s", keyalg)
}
return nil, errors.Wrap(ErrUnsupportedAlgorithm, "failed to create encrypter")
}
if debug.Enabled {
debug.Printf("Encrypt: keysize = %d", keysize)
}
enc := NewMultiEncrypt(contentcrypt, NewRandomKeyGenerate(keysize), keyenc)
msg, err := enc.Encrypt(payload)
if err != nil {
if debug.Enabled {
debug.Printf("Encrypt: failed to encrypt: %s", err)
}
return nil, errors.Wrap(err, "failed to encrypt payload")
}
return CompactSerialize{}.Serialize(msg)
}
// Decrypt takes the key encryption algorithm and the corresponding
// key to decrypt the JWE message, and returns the decrypted payload.
// The JWE message can be either compact or full JSON format.
func Decrypt(buf []byte, alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]byte, error) {
msg, err := Parse(buf)
if err != nil {
return nil, errors.Wrap(err, "failed to parse buffer for Decrypt")
}
return msg.Decrypt(alg, key)
}
// Parse parses the JWE message into a Message object. The JWE message
// can be either compact or full JSON format.
func Parse(buf []byte) (*Message, error) {
buf = bytes.TrimSpace(buf)
if len(buf) == 0 {
return nil, errors.New("empty buffer")
}
if buf[0] == '{' {
return parseJSON(buf)
}
return parseCompact(buf)
}
// ParseString is the same as Parse, but takes a string.
func ParseString(s string) (*Message, error) {
return Parse([]byte(s))
}
func parseJSON(buf []byte) (*Message, error) {
m := struct {
*Message
*Recipient
}{}
if err := json.Unmarshal(buf, &m); err != nil {
return nil, errors.Wrap(err, "failed to parse JSON")
}
// if the "signature" field exist, treat it as a flattened
if m.Recipient != nil {
if len(m.Message.Recipients) != 0 {
return nil, errors.New("invalid message: mixed flattened/full json serialization")
}
m.Message.Recipients = []Recipient{*m.Recipient}
}
return m.Message, nil
}
func parseCompact(buf []byte) (*Message, error) {
if debug.Enabled {
debug.Printf("Parse(Compact): buf = '%s'", buf)
}
parts := bytes.Split(buf, []byte{'.'})
if len(parts) != 5 {
return nil, ErrInvalidCompactPartsCount
}
hdrbuf := buffer.Buffer{}
if err := hdrbuf.Base64Decode(parts[0]); err != nil {
return nil, errors.Wrap(err, `failed to parse first part of compact form`)
}
if debug.Enabled {
debug.Printf("hdrbuf = %s", hdrbuf)
}
hdr := NewHeader()
if err := json.Unmarshal(hdrbuf, hdr); err != nil {
return nil, errors.Wrap(err, "failed to parse header JSON")
}
// We need the protected header to contain the content encryption
// algorithm. XXX probably other headers need to go there too
protected := NewEncodedHeader()
protected.ContentEncryption = hdr.ContentEncryption
hdr.ContentEncryption = ""
enckeybuf := buffer.Buffer{}
if err := enckeybuf.Base64Decode(parts[1]); err != nil {
return nil, errors.Wrap(err, "failed to base64 decode encryption key")
}
ivbuf := buffer.Buffer{}
if err := ivbuf.Base64Decode(parts[2]); err != nil {
return nil, errors.Wrap(err, "failed to base64 decode iv")
}
ctbuf := buffer.Buffer{}
if err := ctbuf.Base64Decode(parts[3]); err != nil {
return nil, errors.Wrap(err, "failed to base64 decode content")
}
tagbuf := buffer.Buffer{}
if err := tagbuf.Base64Decode(parts[4]); err != nil {
return nil, errors.Wrap(err, "failed to base64 decode tag")
}
m := NewMessage()
m.AuthenticatedData.SetBytes(hdrbuf.Bytes())
m.ProtectedHeader = protected
m.Tag = tagbuf
m.CipherText = ctbuf
m.InitializationVector = ivbuf
m.Recipients = []Recipient{
{
Header: hdr,
EncryptedKey: enckeybuf,
},
}
return m, nil
}
// BuildKeyDecrypter creates a new KeyDecrypter instance from the given
// parameters. It is used by the Message.Decrypt method to create
// key decrypter(s) from the given message. `keysize` is only used by
// some decrypters. Pass the value from ContentCipher.KeySize().
func BuildKeyDecrypter(alg jwa.KeyEncryptionAlgorithm, h *Header, key interface{}, keysize int) (KeyDecrypter, error) {
switch alg {
case jwa.RSA1_5:
privkey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("*rsa.PrivateKey is required as the key to build this key decrypter")
}
return NewRSAPKCS15KeyDecrypt(alg, privkey, keysize/2), nil
case jwa.RSA_OAEP, jwa.RSA_OAEP_256:
privkey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("*rsa.PrivateKey is required as the key to build this key decrypter")
}
return NewRSAOAEPKeyDecrypt(alg, privkey)
case jwa.A128KW, jwa.A192KW, jwa.A256KW:
sharedkey, ok := key.([]byte)
if !ok {
return nil, errors.New("[]byte is required as the key to build this key decrypter")
}
return NewKeyWrapEncrypt(alg, sharedkey)
case jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW:
epkif, err := h.Get("epk")
if err != nil {
return nil, errors.Wrap(err, "failed to get 'epk' field")
}
if epkif == nil {
return nil, errors.New("'epk' header is required as the key to build this key decrypter")
}
epk, ok := epkif.(*jwk.ECDSAPublicKey)
if !ok {
return nil, errors.New("'epk' header is required as the key to build this key decrypter")
}
pubkey, err := epk.Materialize()
if err != nil {
return nil, errors.Wrap(err, "failed to get public key")
}
privkey, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, errors.New("*ecdsa.PrivateKey is required as the key to build this key decrypter")
}
apuif, err := h.Get("apu")
if err != nil {
return nil, errors.New("'apu' key is required for this key decrypter")
}
apu, ok := apuif.(buffer.Buffer)
if !ok {
return nil, errors.New("'apu' key is required for this key decrypter")
}
apvif, err := h.Get("apv")
if err != nil {
return nil, errors.New("'apv' key is required for this key decrypter")
}
apv, ok := apvif.(buffer.Buffer)
if !ok {
return nil, errors.New("'apv' key is required for this key decrypter")
}
return NewEcdhesKeyWrapDecrypt(alg, pubkey.(*ecdsa.PublicKey), apu.Bytes(), apv.Bytes(), privkey), nil
}
return nil, NewErrUnsupportedAlgorithm(string(alg), "key decryption")
}