@@ -92,6 +92,20 @@ func SHA512(p []byte) (sum [64]byte) {
92
92
return
93
93
}
94
94
95
+ // cloneHash is an interface that defines a Clone method.
96
+ //
97
+ // hash.CloneHash will probably be added in Go 1.25, see https://golang.org/issue/69521,
98
+ // but we need it now.
99
+ type cloneHash interface {
100
+ hash.Hash
101
+ // Clone returns a separate Hash instance with the same state as h.
102
+ Clone () hash.Hash
103
+ }
104
+
105
+ var _ hash.Hash = (* evpHash )(nil )
106
+ var _ cloneHash = (* evpHash )(nil )
107
+
108
+ // evpHash implements generic hash methods.
95
109
type evpHash struct {
96
110
ctx unsafe.Pointer
97
111
// ctx2 is used in evpHash.sum to avoid changing
@@ -107,12 +121,7 @@ type evpHash struct {
107
121
}
108
122
109
123
func newEvpHash (init func (ctx unsafe.Pointer ) C.int , update func (ctx unsafe.Pointer , data []byte ) C.int , final func (ctx unsafe.Pointer , digest []byte ) C.int , ctxSize , blockSize , size int ) * evpHash {
110
- ctx := C .malloc (C .size_t (ctxSize ))
111
- ctx2 := C .malloc (C .size_t (ctxSize ))
112
- init (ctx )
113
124
h := & evpHash {
114
- ctx : ctx ,
115
- ctx2 : ctx2 ,
116
125
init : init ,
117
126
update : update ,
118
127
final : final ,
@@ -125,8 +134,24 @@ func newEvpHash(init func(ctx unsafe.Pointer) C.int, update func(ctx unsafe.Poin
125
134
}
126
135
127
136
func (h * evpHash ) finalize () {
128
- C .free (h .ctx )
129
- C .free (h .ctx2 )
137
+ if h .ctx != nil {
138
+ C .free (h .ctx )
139
+ }
140
+ if h .ctx2 != nil {
141
+ C .free (h .ctx2 )
142
+ }
143
+ }
144
+
145
+ func (h * evpHash ) initialize () {
146
+ if h .ctx == nil {
147
+ h .ctx = C .malloc (C .size_t (h .ctxSize ))
148
+ h .ctx2 = C .malloc (C .size_t (h .ctxSize ))
149
+ if h .init (h .ctx ) != 1 {
150
+ C .free (h .ctx )
151
+ C .free (h .ctx2 )
152
+ panic ("commoncrypto: initialization failed" )
153
+ }
154
+ }
130
155
}
131
156
132
157
func (h * evpHash ) Reset () {
@@ -137,6 +162,7 @@ func (h *evpHash) Reset() {
137
162
}
138
163
139
164
func (h * evpHash ) Write (p []byte ) (int , error ) {
165
+ h .initialize ()
140
166
if len (p ) > 0 {
141
167
// Use a local variable to prevent the compiler from misinterpreting the pointer
142
168
data := p
@@ -149,6 +175,7 @@ func (h *evpHash) Write(p []byte) (int, error) {
149
175
}
150
176
151
177
func (h * evpHash ) WriteString (s string ) (int , error ) {
178
+ h .initialize ()
152
179
if len (s ) > 0 {
153
180
data := []byte (s )
154
181
if h .update (h .ctx , data ) != 1 {
@@ -160,6 +187,7 @@ func (h *evpHash) WriteString(s string) (int, error) {
160
187
}
161
188
162
189
func (h * evpHash ) WriteByte (c byte ) error {
190
+ h .initialize ()
163
191
if h .update (h .ctx , []byte {c }) != 1 {
164
192
return errors .New ("commoncrypto: Update function failed" )
165
193
}
@@ -175,12 +203,35 @@ func (h *evpHash) BlockSize() int {
175
203
}
176
204
177
205
func (h * evpHash ) Sum (b []byte ) []byte {
206
+ h .initialize ()
178
207
digest := make ([]byte , h .size )
179
208
C .memcpy (h .ctx2 , h .ctx , C .size_t (h .ctxSize ))
180
209
h .final (h .ctx2 , digest )
181
210
return append (b , digest ... )
182
211
}
183
212
213
+ // Clone returns a new evpHash object that is a deep clone of itself.
214
+ // The duplicate object contains all state and data contained in the
215
+ // original object at the point of duplication.
216
+ func (h * evpHash ) Clone () hash.Hash {
217
+ h .initialize ()
218
+ cloned := & evpHash {
219
+ init : h .init ,
220
+ update : h .update ,
221
+ final : h .final ,
222
+ blockSize : h .blockSize ,
223
+ size : h .size ,
224
+ ctxSize : h .ctxSize ,
225
+ }
226
+ cloned .ctx = C .malloc (C .size_t (h .ctxSize ))
227
+ cloned .ctx2 = C .malloc (C .size_t (h .ctxSize ))
228
+ C .memcpy (cloned .ctx , h .ctx , C .size_t (h .ctxSize ))
229
+ C .memcpy (cloned .ctx2 , h .ctx2 , C .size_t (h .ctxSize ))
230
+ runtime .SetFinalizer (cloned , (* evpHash ).finalize )
231
+ runtime .KeepAlive (h )
232
+ return cloned
233
+ }
234
+
184
235
type md4Hash struct {
185
236
* evpHash
186
237
}
0 commit comments