-
Notifications
You must be signed in to change notification settings - Fork 1
/
fixed.go
175 lines (141 loc) · 3.82 KB
/
fixed.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2024 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html
package hash
import (
"crypto/hmac"
"crypto/sha256"
"crypto/sha512"
"errors"
"hash"
"io"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
)
const (
// block size in bytes.
blockSHA3256 = 1088 / 8
blockSHA3384 = 832 / 8
blockSHA3512 = 576 / 8
)
var errHmacKeySize = errors.New("hmac key length is larger than hash output size")
func newFixed(hid Hash, _ int) newHash {
var hashFunc func() hash.Hash
switch hid {
case SHA256:
hashFunc = sha256.New
case SHA384:
hashFunc = sha512.New384
case SHA512:
hashFunc = sha512.New
case SHA3_256:
hashFunc = sha3.New256
case SHA3_384:
hashFunc = sha3.New384
case SHA3_512:
hashFunc = sha3.New512
}
return func() Hasher {
return &Fixed{
id: hid,
hash: hashFunc(),
f: hashFunc,
}
}
}
// Fixed offers easy an easy-to-use API for common cryptographic hash operations of the SHA family.
type Fixed struct {
hash hash.Hash
f func() hash.Hash
id Hash
}
// Algorithm returns the Hash function identifier.
func (h *Fixed) Algorithm() Hash {
return h.id
}
// Hash hashes the concatenation of input and returns size bytes.
func (h *Fixed) Hash(input ...[]byte) []byte {
h.Reset()
for _, i := range input {
_, _ = h.Write(i)
}
return h.Sum(nil)
}
// Read returns the current hash.
// It does not change the underlying hash state.
func (h *Fixed) Read(_ int) []byte {
return h.Sum(nil)
}
// Write implements io.Writer.
func (h *Fixed) Write(input []byte) (int, error) {
return h.hash.Write(input)
}
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
func (h *Fixed) Sum(prefix []byte) []byte {
return h.hash.Sum(prefix)
}
// Reset resets the hash to its initial state.
func (h *Fixed) Reset() {
h.hash.Reset()
}
// SetOutputSize sets the output size for an ExtendableOutputFunction, and is a no-op for fixed hashing.
func (h *Fixed) SetOutputSize(_ int) {
// no-op
}
// Size returns the number of bytes Hash will return.
func (h *Fixed) Size() int {
return h.id.Size()
}
// BlockSize returns the hash's underlying block size.
func (h *Fixed) BlockSize() int {
return h.id.BlockSize()
}
// GetHashFunction returns the underlying Fixed Hasher.
func (h *Fixed) GetHashFunction() *Fixed {
return h
}
// GetXOF returns nil.
func (h *Fixed) GetXOF() *ExtendableHash {
return nil
}
// Hmac wraps the built-in hmac.
func (h *Fixed) Hmac(message, key []byte) []byte {
if len(key) > h.id.Size() {
panic(errHmacKeySize)
}
hm := hmac.New(h.f, key)
_, _ = hm.Write(message)
return hm.Sum(nil)
}
// HKDF is an "extract-then-expand" HMAC based Key derivation function,
// where info is the specific usage identifying information.
func (h *Fixed) HKDF(secret, salt, info []byte, length int) []byte {
if length == 0 {
length = h.id.Size()
}
kdf := hkdf.New(h.f, secret, salt, info)
dst := make([]byte, length)
_, _ = io.ReadFull(kdf, dst)
return dst
}
// HKDFExtract is an "extract" only HKDF, where the secret and salt are used to generate a pseudorandom key. This key
// can then be used in multiple HKDFExpand calls to derive individual different keys.
func (h *Fixed) HKDFExtract(secret, salt []byte) []byte {
return hkdf.Extract(h.f, secret, salt)
}
// HKDFExpand is an "expand" only HKDF, where the key should be an already random/hashed input,
// and info specific key usage identifying information.
func (h *Fixed) HKDFExpand(pseudorandomKey, info []byte, length int) []byte {
if length == 0 {
length = h.id.Size()
}
kdf := hkdf.Expand(h.f, pseudorandomKey, info)
dst := make([]byte, length)
_, _ = kdf.Read(dst)
return dst
}