This repository has been archived by the owner on Dec 6, 2021. It is now read-only.
/
encrypt.go
105 lines (93 loc) · 2.97 KB
/
encrypt.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
package jwe
import (
"github.com/lestrrat/go-jwx/internal/debug"
"github.com/pkg/errors"
)
// NewMultiEncrypt creates a new Encrypt struct. The caller is responsible
// for instantiating valid inputs for ContentEncrypter, KeyGenerator,
// and KeyEncrypters.
func NewMultiEncrypt(cc ContentEncrypter, kg KeyGenerator, ke ...KeyEncrypter) *MultiEncrypt {
e := &MultiEncrypt{
ContentEncrypter: cc,
KeyGenerator: kg,
KeyEncrypters: ke,
}
return e
}
// Encrypt takes the plaintext and encrypts into a JWE message.
func (e MultiEncrypt) Encrypt(plaintext []byte) (*Message, error) {
bk, err := e.KeyGenerator.KeyGenerate()
if err != nil {
if debug.Enabled {
debug.Printf("Failed to generate key: %s", err)
}
return nil, errors.Wrap(err, "failed to generate key")
}
cek := bk.Bytes()
if debug.Enabled {
debug.Printf("Encrypt: generated cek len = %d", len(cek))
}
protected := NewEncodedHeader()
protected.Set("enc", e.ContentEncrypter.Algorithm())
// In JWE, multiple recipients may exist -- they receive an
// encrypted version of the CEK, using their key encryption
// algorithm of choice.
recipients := make([]Recipient, len(e.KeyEncrypters))
for i, enc := range e.KeyEncrypters {
r := NewRecipient()
r.Header.Set("alg", enc.Algorithm())
if v := enc.Kid(); v != "" {
r.Header.Set("kid", v)
}
enckey, err := enc.KeyEncrypt(cek)
if err != nil {
if debug.Enabled {
debug.Printf("Failed to encrypt key: %s", err)
}
return nil, errors.Wrap(err, `failed to encrypt key`)
}
r.EncryptedKey = enckey.Bytes()
if hp, ok := enckey.(HeaderPopulater); ok {
hp.HeaderPopulate(r.Header)
}
if debug.Enabled {
debug.Printf("Encrypt: encrypted_key = %x (%d)", enckey.Bytes(), len(enckey.Bytes()))
}
recipients[i] = *r
}
// If there's only one recipient, you want to include that in the
// protected header
if len(recipients) == 1 {
protected.Header, err = protected.Header.Merge(recipients[0].Header)
if err != nil {
return nil, errors.Wrap(err, "failed to merge protecte headers")
}
}
aad, err := protected.Base64Encode()
if err != nil {
return nil, errors.Wrap(err, "failed to base64 encode protected headers")
}
// ...on the other hand, there's only one content cipher.
iv, ciphertext, tag, err := e.ContentEncrypter.Encrypt(cek, plaintext, aad)
if err != nil {
if debug.Enabled {
debug.Printf("Failed to encrypt: %s", err)
}
return nil, errors.Wrap(err, "failed to encrypt payload")
}
if debug.Enabled {
debug.Printf("Encrypt.Encrypt: cek = %x (%d)", cek, len(cek))
debug.Printf("Encrypt.Encrypt: aad = %x", aad)
debug.Printf("Encrypt.Encrypt: ciphertext = %x", ciphertext)
debug.Printf("Encrypt.Encrypt: iv = %x", iv)
debug.Printf("Encrypt.Encrypt: tag = %x", tag)
}
msg := NewMessage()
msg.AuthenticatedData.Base64Decode(aad)
msg.CipherText = ciphertext
msg.InitializationVector = iv
msg.ProtectedHeader = protected
msg.Recipients = recipients
msg.Tag = tag
return msg, nil
}