-
Notifications
You must be signed in to change notification settings - Fork 4
/
jwe.go
90 lines (74 loc) · 2.44 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
package jwe
import (
"encoding/base64"
"encoding/json"
"strings"
)
// NewJWE creates a new JWE token.
// The plaintext will be encrypted with the method using a Content Encryption Key (cek).
// The cek will be encrypted with the alg using the key.
func NewJWE(alg KeyAlgorithm, key interface{}, method EncryptionType, plaintext []byte) (*jwe, error) {
jwe := &jwe{}
jwe.protected.Enc = method
chipher, err := getCipher(method)
if err != nil {
return nil, err
}
// Generate a random Content Encryption Key (CEK).
cek, err := generateKey(chipher.keySize)
if err != nil {
return nil, err
}
// Encrypt the CEK with the recipient's public key to produce the JWE Encrypted Key.
jwe.protected.Alg = alg
encrypter, err := createEncrypter(key)
if err != nil {
return nil, err
}
jwe.recipientKey, err = encrypter.Encrypt(cek, alg)
if err != nil {
return nil, err
}
// Serialize Authenticated Data
rawProtected, err := json.Marshal(jwe.protected)
if err != nil {
return nil, err
}
rawProtectedBase64 := base64.RawURLEncoding.EncodeToString(rawProtected)
// Perform authenticated encryption on the plaintext
jwe.iv, jwe.ciphertext, jwe.tag, err = chipher.encrypt(cek, []byte(rawProtectedBase64), plaintext)
if err != nil {
return nil, err
}
return jwe, nil
}
// jwe internal structure represents JWE in unmarshalling format.
type jwe struct {
// protected fields: alg - algorithm to encrypt a key and enc - algorithm to encrypt text.
protected struct {
Alg KeyAlgorithm `json:"alg,omitempty"`
Enc EncryptionType `json:"enc,omitempty"`
}
// recipientKey field is the key encrypted.
recipientKey []byte
// iv field is initialization vector.
iv []byte
// ciphertext filed is text encrypted by the enc with the key.
ciphertext []byte
// tag field is authentication tag.
tag []byte
}
// CompactSerialize serialize JWE to compact form.
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1
func (jwe *jwe) CompactSerialize() (string, error) {
rawProtected, err := json.Marshal(jwe.protected)
if err != nil {
return "", err
}
protected := base64.RawURLEncoding.EncodeToString(rawProtected)
encryptedKey := base64.RawURLEncoding.EncodeToString(jwe.recipientKey)
iv := base64.RawURLEncoding.EncodeToString(jwe.iv)
ciphertext := base64.RawURLEncoding.EncodeToString(jwe.ciphertext)
tag := base64.RawURLEncoding.EncodeToString(jwe.tag)
return strings.Join([]string{protected, encryptedKey, iv, ciphertext, tag}, "."), nil
}