1
2
3
4
5 package hpke
6
7 import (
8 "crypto/hkdf"
9 "crypto/sha256"
10 "crypto/sha3"
11 "crypto/sha512"
12 "errors"
13 "fmt"
14 "hash"
15 "internal/byteorder"
16 )
17
18
19
20 type KDF interface {
21 ID() uint16
22 oneStage() bool
23 size() int
24 labeledDerive(suiteID, inputKey []byte, label string, context []byte, length uint16) ([]byte, error)
25 labeledExtract(suiteID, salt []byte, label string, inputKey []byte) ([]byte, error)
26 labeledExpand(suiteID, randomKey []byte, label string, info []byte, length uint16) ([]byte, error)
27 }
28
29
30
31
32
33 func NewKDF(id uint16) (KDF, error) {
34 switch id {
35 case 0x0001:
36 return HKDFSHA256(), nil
37 case 0x0002:
38 return HKDFSHA384(), nil
39 case 0x0003:
40 return HKDFSHA512(), nil
41 case 0x0010:
42 return SHAKE128(), nil
43 case 0x0011:
44 return SHAKE256(), nil
45 default:
46 return nil, fmt.Errorf("unsupported KDF %04x", id)
47 }
48 }
49
50
51 func HKDFSHA256() KDF { return hkdfSHA256 }
52
53
54 func HKDFSHA384() KDF { return hkdfSHA384 }
55
56
57 func HKDFSHA512() KDF { return hkdfSHA512 }
58
59 type hkdfKDF struct {
60 hash func() hash.Hash
61 id uint16
62 nH int
63 }
64
65 var hkdfSHA256 = &hkdfKDF{hash: sha256.New, id: 0x0001, nH: sha256.Size}
66 var hkdfSHA384 = &hkdfKDF{hash: sha512.New384, id: 0x0002, nH: sha512.Size384}
67 var hkdfSHA512 = &hkdfKDF{hash: sha512.New, id: 0x0003, nH: sha512.Size}
68
69 func (kdf *hkdfKDF) ID() uint16 {
70 return kdf.id
71 }
72
73 func (kdf *hkdfKDF) size() int {
74 return kdf.nH
75 }
76
77 func (kdf *hkdfKDF) oneStage() bool {
78 return false
79 }
80
81 func (kdf *hkdfKDF) labeledDerive(_, _ []byte, _ string, _ []byte, _ uint16) ([]byte, error) {
82 return nil, errors.New("hpke: internal error: labeledDerive called on two-stage KDF")
83 }
84
85 func (kdf *hkdfKDF) labeledExtract(suiteID []byte, salt []byte, label string, inputKey []byte) ([]byte, error) {
86 labeledIKM := make([]byte, 0, 7+len(suiteID)+len(label)+len(inputKey))
87 labeledIKM = append(labeledIKM, []byte("HPKE-v1")...)
88 labeledIKM = append(labeledIKM, suiteID...)
89 labeledIKM = append(labeledIKM, label...)
90 labeledIKM = append(labeledIKM, inputKey...)
91 return hkdf.Extract(kdf.hash, labeledIKM, salt)
92 }
93
94 func (kdf *hkdfKDF) labeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) ([]byte, error) {
95 labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info))
96 labeledInfo = byteorder.BEAppendUint16(labeledInfo, length)
97 labeledInfo = append(labeledInfo, []byte("HPKE-v1")...)
98 labeledInfo = append(labeledInfo, suiteID...)
99 labeledInfo = append(labeledInfo, label...)
100 labeledInfo = append(labeledInfo, info...)
101 return hkdf.Expand(kdf.hash, randomKey, string(labeledInfo), int(length))
102 }
103
104
105 func SHAKE128() KDF {
106 return shake128KDF
107 }
108
109
110 func SHAKE256() KDF {
111 return shake256KDF
112 }
113
114 type shakeKDF struct {
115 hash func() *sha3.SHAKE
116 id uint16
117 nH int
118 }
119
120 var shake128KDF = &shakeKDF{hash: sha3.NewSHAKE128, id: 0x0010, nH: 32}
121 var shake256KDF = &shakeKDF{hash: sha3.NewSHAKE256, id: 0x0011, nH: 64}
122
123 func (kdf *shakeKDF) ID() uint16 {
124 return kdf.id
125 }
126
127 func (kdf *shakeKDF) size() int {
128 return kdf.nH
129 }
130
131 func (kdf *shakeKDF) oneStage() bool {
132 return true
133 }
134
135 func (kdf *shakeKDF) labeledDerive(suiteID, inputKey []byte, label string, context []byte, length uint16) ([]byte, error) {
136 H := kdf.hash()
137 H.Write(inputKey)
138 H.Write([]byte("HPKE-v1"))
139 H.Write(suiteID)
140 H.Write([]byte{byte(len(label) >> 8), byte(len(label))})
141 H.Write([]byte(label))
142 H.Write([]byte{byte(length >> 8), byte(length)})
143 H.Write(context)
144 out := make([]byte, length)
145 H.Read(out)
146 return out, nil
147 }
148
149 func (kdf *shakeKDF) labeledExtract(_, _ []byte, _ string, _ []byte) ([]byte, error) {
150 return nil, errors.New("hpke: internal error: labeledExtract called on one-stage KDF")
151 }
152
153 func (kdf *shakeKDF) labeledExpand(_, _ []byte, _ string, _ []byte, _ uint16) ([]byte, error) {
154 return nil, errors.New("hpke: internal error: labeledExpand called on one-stage KDF")
155 }
156
View as plain text