Skip to content

Commit 2ef00e2

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/internal/fips/hkdf: new package
Tests imported from x/crypto, but the actual implementation was simpler to implement ex-novo with a #61477-like API. Updates #61477 For #69536 Change-Id: I5a9e8a71d8abd5b2aa6b74e73bf7f631ed0115cd Reviewed-on: https://go-review.googlesource.com/c/go/+/621275 Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Daniel McCarney <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent f916d93 commit 2ef00e2

File tree

5 files changed

+448
-0
lines changed

5 files changed

+448
-0
lines changed

src/crypto/internal/fips/cast_external_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
// Import packages that define CASTs to test them.
1515
_ "crypto/internal/fips/drbg"
16+
_ "crypto/internal/fips/hkdf"
1617
_ "crypto/internal/fips/hmac"
1718
_ "crypto/internal/fips/sha256"
1819
_ "crypto/internal/fips/sha3"

src/crypto/internal/fips/hkdf/cast.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package hkdf
6+
7+
import (
8+
"bytes"
9+
"crypto/internal/fips"
10+
"crypto/internal/fips/sha256"
11+
"errors"
12+
)
13+
14+
func init() {
15+
fips.CAST("HKDF-SHA2-256", func() error {
16+
input := []byte{
17+
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
18+
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
19+
}
20+
want := []byte{
21+
0xb6, 0x53, 0x00, 0x5b, 0x51, 0x6d, 0x2b, 0xc9,
22+
0x4a, 0xe4, 0xf9, 0x51, 0x73, 0x1f, 0x71, 0x21,
23+
0xa6, 0xc1, 0xde, 0x42, 0x4f, 0x2c, 0x99, 0x60,
24+
0x64, 0xdb, 0x66, 0x3e, 0xec, 0xa6, 0x37, 0xff,
25+
}
26+
got := Key(sha256.New, input, input, input, len(want))
27+
if !bytes.Equal(got, want) {
28+
return errors.New("unexpected result")
29+
}
30+
return nil
31+
})
32+
}

src/crypto/internal/fips/hkdf/hkdf.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package hkdf
6+
7+
import (
8+
"crypto/internal/fips"
9+
"crypto/internal/fips/hmac"
10+
)
11+
12+
func Extract[H fips.Hash](h func() H, secret, salt []byte) []byte {
13+
if len(secret) < 112/8 {
14+
fips.RecordNonApproved()
15+
}
16+
if salt == nil {
17+
salt = make([]byte, h().Size())
18+
}
19+
extractor := hmac.New(h, salt)
20+
extractor.Write(secret)
21+
return extractor.Sum(nil)
22+
}
23+
24+
func Expand[H fips.Hash](h func() H, pseudorandomKey, info []byte, keyLen int) []byte {
25+
out := make([]byte, 0, keyLen)
26+
expander := hmac.New(h, pseudorandomKey)
27+
var counter uint8
28+
var buf []byte
29+
30+
for len(out) < keyLen {
31+
counter++
32+
if counter == 0 {
33+
panic("hkdf: counter overflow")
34+
}
35+
if counter > 1 {
36+
expander.Reset()
37+
}
38+
expander.Write(buf)
39+
expander.Write(info)
40+
expander.Write([]byte{counter})
41+
buf = expander.Sum(buf[:0])
42+
remain := keyLen - len(out)
43+
remain = min(remain, len(buf))
44+
out = append(out, buf[:remain]...)
45+
}
46+
47+
return out
48+
}
49+
50+
func Key[H fips.Hash](h func() H, secret, salt, info []byte, keyLen int) []byte {
51+
prk := Extract(h, secret, salt)
52+
return Expand(h, prk, info, keyLen)
53+
}

0 commit comments

Comments
 (0)