-
Notifications
You must be signed in to change notification settings - Fork 29
/
pbse2_hmac_aeskw.go
142 lines (110 loc) · 4.01 KB
/
pbse2_hmac_aeskw.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
package jose
import (
"crypto/sha256"
"crypto/sha512"
"errors"
"fmt"
"hash"
"github.com/dvsekhvalnov/jose2go/arrays"
"github.com/dvsekhvalnov/jose2go/base64url"
"github.com/dvsekhvalnov/jose2go/kdf"
)
func init() {
RegisterJwa(NewPbse2HmacAesKWAlg(128, 1300000, 0))
RegisterJwa(NewPbse2HmacAesKWAlg(192, 950000, 0))
RegisterJwa(NewPbse2HmacAesKWAlg(256, 600000, 0))
}
// PBSE2 with HMAC key management algorithm implementation
type Pbse2HmacAesKW struct {
keySizeBits int
aesKW JwaAlgorithm
maxIterations int64
minIterations int64
}
func NewPbse2HmacAesKWAlg(keySize int, maxIters int64, minIters int64) JwaAlgorithm {
switch keySize {
case 128:
return &Pbse2HmacAesKW{keySizeBits: 128, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 128}}
case 192:
return &Pbse2HmacAesKW{keySizeBits: 192, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 192}}
default:
return &Pbse2HmacAesKW{keySizeBits: 256, maxIterations: maxIters, minIterations: minIters, aesKW: &AesKW{keySizeBits: 256}}
}
}
func (alg *Pbse2HmacAesKW) Name() string {
switch alg.keySizeBits {
case 128:
return PBES2_HS256_A128KW
case 192:
return PBES2_HS384_A192KW
default:
return PBES2_HS512_A256KW
}
}
func (alg *Pbse2HmacAesKW) WrapNewKey(cekSizeBits int, key interface{}, header map[string]interface{}) (cek []byte, encryptedCek []byte, err error) {
if passphrase, ok := key.(string); ok {
algId := []byte(header["alg"].(string))
iterationCount := 8192
var saltInput []byte
if saltInput, err = arrays.Random(12); err != nil {
return nil, nil, err
}
// use user provided iteration counts if any
if p2c, ok := header["p2c"].(int); ok {
iterationCount = p2c
}
if int64(iterationCount) > alg.maxIterations {
return nil, nil, errors.New(
fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be less than %v but got %v", alg.maxIterations, iterationCount))
}
if int64(iterationCount) < alg.minIterations {
return nil, nil, errors.New(
fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be higher than %v but got %v", alg.minIterations, iterationCount))
}
header["p2c"] = iterationCount
header["p2s"] = base64url.Encode(saltInput)
salt := arrays.Concat(algId, []byte{0}, saltInput)
kek := kdf.DerivePBKDF2([]byte(passphrase), salt, iterationCount, alg.keySizeBits, alg.prf)
return alg.aesKW.WrapNewKey(cekSizeBits, kek, header)
}
return nil, nil, errors.New("Pbse2HmacAesKW.WrapNewKey(): expected key to be 'string' array")
}
func (alg *Pbse2HmacAesKW) Unwrap(encryptedCek []byte, key interface{}, cekSizeBits int, header map[string]interface{}) (cek []byte, err error) {
if passphrase, ok := key.(string); ok {
var p2s string
var p2c float64
if p2c, ok = header["p2c"].(float64); !ok {
return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected 'p2c' param in JWT header, but was not found.")
}
if int64(p2c) > alg.maxIterations {
return nil, errors.New(
fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be less than %v but got %v", alg.maxIterations, p2c))
}
if int64(p2c) < alg.minIterations {
return nil, errors.New(
fmt.Sprintf("Pbse2HmacAesKW.Unwrap(): expected 'p2c' to be higher than %v but got %v", alg.minIterations, p2c))
}
if p2s, ok = header["p2s"].(string); !ok {
return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected 'p2s' param in JWT header, but was not found")
}
var saltInput []byte
algId := []byte(header["alg"].(string))
if saltInput, err = base64url.Decode(p2s); err != nil {
return nil, err
}
salt := arrays.Concat(algId, []byte{0}, saltInput)
kek := kdf.DerivePBKDF2([]byte(passphrase), salt, int(p2c), alg.keySizeBits, alg.prf)
return alg.aesKW.Unwrap(encryptedCek, kek, cekSizeBits, header)
}
return nil, errors.New("Pbse2HmacAesKW.Unwrap(): expected key to be 'string' array")
}
func (alg *Pbse2HmacAesKW) prf() hash.Hash {
switch alg.keySizeBits {
case 128:
return sha256.New()
case 192:
return sha512.New384()
default:
return sha512.New()
}
}