...
1 package hpke
2
3 import (
4 "crypto"
5 "crypto/aes"
6 "crypto/cipher"
7 "crypto/elliptic"
8 _ "crypto/sha256"
9 _ "crypto/sha512"
10 "fmt"
11 "hash"
12 "io"
13
14 "github.com/cloudflare/circl/dh/x25519"
15 "github.com/cloudflare/circl/dh/x448"
16 "github.com/cloudflare/circl/ecc/p384"
17 "github.com/cloudflare/circl/kem"
18 "github.com/cloudflare/circl/kem/kyber/kyber768"
19 "golang.org/x/crypto/chacha20poly1305"
20 "golang.org/x/crypto/hkdf"
21 )
22
23 type KEM uint16
24
25
26 const (
27
28 KEM_P256_HKDF_SHA256 KEM = 0x10
29
30 KEM_P384_HKDF_SHA384 KEM = 0x11
31
32 KEM_P521_HKDF_SHA512 KEM = 0x12
33
34
35 KEM_X25519_HKDF_SHA256 KEM = 0x20
36
37
38 KEM_X448_HKDF_SHA512 KEM = 0x21
39
40
41 KEM_X25519_KYBER768_DRAFT00 KEM = 0x30
42 )
43
44
45 func (k KEM) IsValid() bool {
46 switch k {
47 case KEM_P256_HKDF_SHA256,
48 KEM_P384_HKDF_SHA384,
49 KEM_P521_HKDF_SHA512,
50 KEM_X25519_HKDF_SHA256,
51 KEM_X448_HKDF_SHA512,
52 KEM_X25519_KYBER768_DRAFT00:
53 return true
54 default:
55 return false
56 }
57 }
58
59
60
61 func (k KEM) Scheme() kem.AuthScheme {
62 switch k {
63 case KEM_P256_HKDF_SHA256:
64 return dhkemp256hkdfsha256
65 case KEM_P384_HKDF_SHA384:
66 return dhkemp384hkdfsha384
67 case KEM_P521_HKDF_SHA512:
68 return dhkemp521hkdfsha512
69 case KEM_X25519_HKDF_SHA256:
70 return dhkemx25519hkdfsha256
71 case KEM_X448_HKDF_SHA512:
72 return dhkemx448hkdfsha512
73 case KEM_X25519_KYBER768_DRAFT00:
74 return hybridkemX25519Kyber768
75 default:
76 panic(ErrInvalidKEM)
77 }
78 }
79
80 type KDF uint16
81
82
83 const (
84
85 KDF_HKDF_SHA256 KDF = 0x01
86
87 KDF_HKDF_SHA384 KDF = 0x02
88
89 KDF_HKDF_SHA512 KDF = 0x03
90 )
91
92 func (k KDF) IsValid() bool {
93 switch k {
94 case KDF_HKDF_SHA256,
95 KDF_HKDF_SHA384,
96 KDF_HKDF_SHA512:
97 return true
98 default:
99 return false
100 }
101 }
102
103
104
105 func (k KDF) ExtractSize() int {
106 switch k {
107 case KDF_HKDF_SHA256:
108 return crypto.SHA256.Size()
109 case KDF_HKDF_SHA384:
110 return crypto.SHA384.Size()
111 case KDF_HKDF_SHA512:
112 return crypto.SHA512.Size()
113 default:
114 panic(ErrInvalidKDF)
115 }
116 }
117
118
119
120 func (k KDF) Extract(secret, salt []byte) (pseudorandomKey []byte) {
121 return hkdf.Extract(k.hash(), secret, salt)
122 }
123
124
125
126
127
128 func (k KDF) Expand(pseudorandomKey, info []byte, outputLen uint) []byte {
129 extractSize := k.ExtractSize()
130 if len(pseudorandomKey) < extractSize {
131 panic(fmt.Errorf("pseudorandom key must be %v bytes", extractSize))
132 }
133 maxLength := uint(255 * extractSize)
134 if outputLen > maxLength {
135 panic(fmt.Errorf("output length must be less than %v bytes", maxLength))
136 }
137 output := make([]byte, outputLen)
138 rd := hkdf.Expand(k.hash(), pseudorandomKey[:extractSize], info)
139 _, err := io.ReadFull(rd, output)
140 if err != nil {
141 panic(err)
142 }
143 return output
144 }
145
146 func (k KDF) hash() func() hash.Hash {
147 switch k {
148 case KDF_HKDF_SHA256:
149 return crypto.SHA256.New
150 case KDF_HKDF_SHA384:
151 return crypto.SHA384.New
152 case KDF_HKDF_SHA512:
153 return crypto.SHA512.New
154 default:
155 panic(ErrInvalidKDF)
156 }
157 }
158
159 type AEAD uint16
160
161
162 const (
163
164 AEAD_AES128GCM AEAD = 0x01
165
166 AEAD_AES256GCM AEAD = 0x02
167
168 AEAD_ChaCha20Poly1305 AEAD = 0x03
169 )
170
171
172
173 func (a AEAD) New(key []byte) (cipher.AEAD, error) {
174 switch a {
175 case AEAD_AES128GCM, AEAD_AES256GCM:
176 block, err := aes.NewCipher(key)
177 if err != nil {
178 return nil, err
179 }
180 return cipher.NewGCM(block)
181 case AEAD_ChaCha20Poly1305:
182 return chacha20poly1305.New(key)
183 default:
184 panic(ErrInvalidAEAD)
185 }
186 }
187
188 func (a AEAD) IsValid() bool {
189 switch a {
190 case AEAD_AES128GCM,
191 AEAD_AES256GCM,
192 AEAD_ChaCha20Poly1305:
193 return true
194 default:
195 return false
196 }
197 }
198
199
200 func (a AEAD) KeySize() uint {
201 switch a {
202 case AEAD_AES128GCM:
203 return 16
204 case AEAD_AES256GCM:
205 return 32
206 case AEAD_ChaCha20Poly1305:
207 return chacha20poly1305.KeySize
208 default:
209 panic(ErrInvalidAEAD)
210 }
211 }
212
213
214 func (a AEAD) NonceSize() uint {
215 switch a {
216 case AEAD_AES128GCM,
217 AEAD_AES256GCM,
218 AEAD_ChaCha20Poly1305:
219 return 12
220 default:
221 panic(ErrInvalidAEAD)
222 }
223 }
224
225
226
227 func (a AEAD) CipherLen(mLen uint) uint {
228 switch a {
229 case AEAD_AES128GCM, AEAD_AES256GCM, AEAD_ChaCha20Poly1305:
230 return mLen + 16
231 default:
232 panic(ErrInvalidAEAD)
233 }
234 }
235
236 var (
237 dhkemp256hkdfsha256, dhkemp384hkdfsha384, dhkemp521hkdfsha512 shortKEM
238 dhkemx25519hkdfsha256, dhkemx448hkdfsha512 xKEM
239 hybridkemX25519Kyber768 hybridKEM
240 )
241
242 func init() {
243 dhkemp256hkdfsha256.Curve = elliptic.P256()
244 dhkemp256hkdfsha256.dhKemBase.id = KEM_P256_HKDF_SHA256
245 dhkemp256hkdfsha256.dhKemBase.name = "HPKE_KEM_P256_HKDF_SHA256"
246 dhkemp256hkdfsha256.dhKemBase.Hash = crypto.SHA256
247 dhkemp256hkdfsha256.dhKemBase.dhKEM = dhkemp256hkdfsha256
248
249 dhkemp384hkdfsha384.Curve = p384.P384()
250 dhkemp384hkdfsha384.dhKemBase.id = KEM_P384_HKDF_SHA384
251 dhkemp384hkdfsha384.dhKemBase.name = "HPKE_KEM_P384_HKDF_SHA384"
252 dhkemp384hkdfsha384.dhKemBase.Hash = crypto.SHA384
253 dhkemp384hkdfsha384.dhKemBase.dhKEM = dhkemp384hkdfsha384
254
255 dhkemp521hkdfsha512.Curve = elliptic.P521()
256 dhkemp521hkdfsha512.dhKemBase.id = KEM_P521_HKDF_SHA512
257 dhkemp521hkdfsha512.dhKemBase.name = "HPKE_KEM_P521_HKDF_SHA512"
258 dhkemp521hkdfsha512.dhKemBase.Hash = crypto.SHA512
259 dhkemp521hkdfsha512.dhKemBase.dhKEM = dhkemp521hkdfsha512
260
261 dhkemx25519hkdfsha256.size = x25519.Size
262 dhkemx25519hkdfsha256.dhKemBase.id = KEM_X25519_HKDF_SHA256
263 dhkemx25519hkdfsha256.dhKemBase.name = "HPKE_KEM_X25519_HKDF_SHA256"
264 dhkemx25519hkdfsha256.dhKemBase.Hash = crypto.SHA256
265 dhkemx25519hkdfsha256.dhKemBase.dhKEM = dhkemx25519hkdfsha256
266
267 dhkemx448hkdfsha512.size = x448.Size
268 dhkemx448hkdfsha512.dhKemBase.id = KEM_X448_HKDF_SHA512
269 dhkemx448hkdfsha512.dhKemBase.name = "HPKE_KEM_X448_HKDF_SHA512"
270 dhkemx448hkdfsha512.dhKemBase.Hash = crypto.SHA512
271 dhkemx448hkdfsha512.dhKemBase.dhKEM = dhkemx448hkdfsha512
272
273 hybridkemX25519Kyber768.kemBase.id = KEM_X25519_KYBER768_DRAFT00
274 hybridkemX25519Kyber768.kemBase.name = "HPKE_KEM_X25519_KYBER768_HKDF_SHA256"
275 hybridkemX25519Kyber768.kemBase.Hash = crypto.SHA256
276 hybridkemX25519Kyber768.kemA = dhkemx25519hkdfsha256
277 hybridkemX25519Kyber768.kemB = kyber768.Scheme()
278 }
279
View as plain text