forked from hashicorp/go-kms-wrapping
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hmac_sha256.go
98 lines (91 loc) · 2.97 KB
/
hmac_sha256.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
package crypto
import (
"context"
"crypto/ed25519"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
wrapping "github.com/hxfs/go-kms-wrapping/v2"
"github.com/mr-tron/base58"
"golang.org/x/crypto/blake2b"
)
// HmacSha256WithPrk will HmacSha256 using the provided prk. See HmacSha256 for
// options supported.
func HmacSha256WithPrk(ctx context.Context, data, prk []byte, opt ...wrapping.Option) (string, error) {
opt = append(opt, WithPrk(prk))
return HmacSha256(ctx, data, nil, opt...)
}
// HmacSha256 the provided data. Supports WithSalt, WithInfo, WithPrefix,
// WithEd25519 and WithPrk options. WithEd25519 is a "legacy" way to complete
// this operation and should not be used in new operations unless backward
// compatibility is needed. The WithPrefix option will prepend the prefix to the
// hmac-sha256 value.
func HmacSha256(ctx context.Context, data []byte, cipher wrapping.Wrapper, opt ...wrapping.Option) (string, error) {
const op = "crypto.HmacSha256"
opts, err := getOpts(opt...)
if err != nil {
return "", fmt.Errorf("%s: unable to get options: %w", op, err)
}
if data == nil {
return "", fmt.Errorf("%s: missing data: %w", op, wrapping.ErrInvalidParameter)
}
if cipher == nil && opts.withPrk == nil {
return "", fmt.Errorf("%s: you must specify either a wrapper or prk: %w", op, wrapping.ErrInvalidParameter)
}
if cipher != nil && opts.withPrk != nil {
return "", fmt.Errorf("%s: you cannot specify both a wrapper or prk: %w", op, wrapping.ErrInvalidParameter)
}
if opts.withEd25519 && opts.withPrk != nil {
return "", fmt.Errorf("%s: you cannot specify both ed25519 and a prk: %w", op, wrapping.ErrInvalidParameter)
}
var key [32]byte
switch {
case opts.withPrk != nil:
key = blake2b.Sum256(opts.withPrk)
case opts.withEd25519:
reader, err := NewDerivedReader(ctx, cipher, 32, opt...)
if err != nil {
return "", fmt.Errorf("%s: %w", op, err)
}
edKey, _, err := ed25519.GenerateKey(reader)
if err != nil {
return "", fmt.Errorf("%s: unable to generate derived key: %w", op, wrapping.ErrInvalidParameter)
}
n := copy(key[:], edKey)
if n != 32 {
return "", fmt.Errorf("%s: expected to copy 32 bytes and got: %d", op, n)
}
default:
reader, err := NewDerivedReader(ctx, cipher, 32, opt...)
if err != nil {
return "", fmt.Errorf("%s: %w", op, err)
}
readerKey := make([]byte, 32)
n, err := io.ReadFull(reader, readerKey)
if err != nil {
return "", fmt.Errorf("%s: %w", op, err)
}
if n != 32 {
return "", fmt.Errorf("%s: expected to read 32 bytes and got: %d", op, n)
}
key = blake2b.Sum256(readerKey)
}
mac := hmac.New(sha256.New, key[:])
_, _ = mac.Write(data)
hmac := mac.Sum(nil)
var hmacString string
switch {
case opts.withBase64Encoding:
hmacString = base64.RawURLEncoding.EncodeToString(hmac)
case opts.withBase58Encoding:
hmacString = base58.Encode(hmac)
default:
hmacString = string(hmac)
}
if opts.withPrefix != "" {
return opts.withPrefix + hmacString, nil
}
return hmacString, nil
}