Skip to content

Commit 950c5fd

Browse files
authored
Implement Clone for all hashers (#167)
* implement Clone for all hashers * document clone methods * add TestHash_Clone comment
1 parent c50e935 commit 950c5fd

File tree

3 files changed

+259
-29
lines changed

3 files changed

+259
-29
lines changed

hash.go

+149
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,34 @@ func (h *evpHash) sum(out []byte) {
230230
runtime.KeepAlive(h)
231231
}
232232

233+
// clone returns a new evpHash object that is a deep clone of itself.
234+
// The duplicate object contains all state and data contained in the
235+
// original object at the point of duplication.
236+
func (h *evpHash) clone() (*evpHash, error) {
237+
ctx := C.go_openssl_EVP_MD_CTX_new()
238+
if ctx == nil {
239+
return nil, newOpenSSLError("EVP_MD_CTX_new")
240+
}
241+
if C.go_openssl_EVP_MD_CTX_copy_ex(ctx, h.ctx) != 1 {
242+
C.go_openssl_EVP_MD_CTX_free(ctx)
243+
return nil, newOpenSSLError("EVP_MD_CTX_copy")
244+
}
245+
ctx2 := C.go_openssl_EVP_MD_CTX_new()
246+
if ctx2 == nil {
247+
C.go_openssl_EVP_MD_CTX_free(ctx)
248+
return nil, newOpenSSLError("EVP_MD_CTX_new")
249+
}
250+
cloned := &evpHash{
251+
ctx: ctx,
252+
ctx2: ctx2,
253+
size: h.size,
254+
blockSize: h.blockSize,
255+
marshallable: h.marshallable,
256+
}
257+
runtime.SetFinalizer(cloned, (*evpHash).finalize)
258+
return cloned, nil
259+
}
260+
233261
// hashState returns a pointer to the internal hash structure.
234262
//
235263
// The EVP_MD_CTX memory layout has changed in OpenSSL 3
@@ -280,6 +308,17 @@ func (h *md4Hash) Sum(in []byte) []byte {
280308
return append(in, h.out[:]...)
281309
}
282310

311+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
312+
// The duplicate object contains all state and data contained in the
313+
// original object at the point of duplication.
314+
func (h *md4Hash) Clone() (hash.Hash, error) {
315+
c, err := h.clone()
316+
if err != nil {
317+
return nil, err
318+
}
319+
return &md4Hash{evpHash: c}, nil
320+
}
321+
283322
// NewMD5 returns a new MD5 hash.
284323
func NewMD5() hash.Hash {
285324
h := md5Hash{evpHash: newEvpHash(crypto.MD5)}
@@ -308,6 +347,17 @@ func (h *md5Hash) Sum(in []byte) []byte {
308347
return append(in, h.out[:]...)
309348
}
310349

350+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
351+
// The duplicate object contains all state and data contained in the
352+
// original object at the point of duplication.
353+
func (h *md5Hash) Clone() (hash.Hash, error) {
354+
c, err := h.clone()
355+
if err != nil {
356+
return nil, err
357+
}
358+
return &md5Hash{evpHash: c}, nil
359+
}
360+
311361
const (
312362
md5Magic = "md5\x01"
313363
md5MarshaledSize = len(md5Magic) + 4*4 + 64 + 8
@@ -377,6 +427,17 @@ func (h *sha1Hash) Sum(in []byte) []byte {
377427
return append(in, h.out[:]...)
378428
}
379429

430+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
431+
// The duplicate object contains all state and data contained in the
432+
// original object at the point of duplication.
433+
func (h *sha1Hash) Clone() (hash.Hash, error) {
434+
c, err := h.clone()
435+
if err != nil {
436+
return nil, err
437+
}
438+
return &sha1Hash{evpHash: c}, nil
439+
}
440+
380441
// sha1State layout is taken from
381442
// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L34.
382443
type sha1State struct {
@@ -457,6 +518,17 @@ func (h *sha224Hash) Sum(in []byte) []byte {
457518
return append(in, h.out[:]...)
458519
}
459520

521+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
522+
// The duplicate object contains all state and data contained in the
523+
// original object at the point of duplication.
524+
func (h *sha224Hash) Clone() (hash.Hash, error) {
525+
c, err := h.clone()
526+
if err != nil {
527+
return nil, err
528+
}
529+
return &sha224Hash{evpHash: c}, nil
530+
}
531+
460532
// NewSHA256 returns a new SHA256 hash.
461533
func NewSHA256() hash.Hash {
462534
h := sha256Hash{evpHash: newEvpHash(crypto.SHA256)}
@@ -476,6 +548,17 @@ func (h *sha256Hash) Sum(in []byte) []byte {
476548
return append(in, h.out[:]...)
477549
}
478550

551+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
552+
// The duplicate object contains all state and data contained in the
553+
// original object at the point of duplication.
554+
func (h *sha256Hash) Clone() (hash.Hash, error) {
555+
c, err := h.clone()
556+
if err != nil {
557+
return nil, err
558+
}
559+
return &sha256Hash{evpHash: c}, nil
560+
}
561+
479562
const (
480563
magic224 = "sha\x02"
481564
magic256 = "sha\x03"
@@ -616,6 +699,17 @@ func (h *sha384Hash) Sum(in []byte) []byte {
616699
return append(in, h.out[:]...)
617700
}
618701

702+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
703+
// The duplicate object contains all state and data contained in the
704+
// original object at the point of duplication.
705+
func (h *sha384Hash) Clone() (hash.Hash, error) {
706+
c, err := h.clone()
707+
if err != nil {
708+
return nil, err
709+
}
710+
return &sha384Hash{evpHash: c}, nil
711+
}
712+
619713
// NewSHA512 returns a new SHA512 hash.
620714
func NewSHA512() hash.Hash {
621715
h := sha512Hash{evpHash: newEvpHash(crypto.SHA512)}
@@ -635,6 +729,17 @@ func (h *sha512Hash) Sum(in []byte) []byte {
635729
return append(in, h.out[:]...)
636730
}
637731

732+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
733+
// The duplicate object contains all state and data contained in the
734+
// original object at the point of duplication.
735+
func (h *sha512Hash) Clone() (hash.Hash, error) {
736+
c, err := h.clone()
737+
if err != nil {
738+
return nil, err
739+
}
740+
return &sha512Hash{evpHash: c}, nil
741+
}
742+
638743
// sha512State layout is taken from
639744
// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/sha.h#L95.
640745
type sha512State struct {
@@ -781,6 +886,17 @@ func (h *sha3_224Hash) Sum(in []byte) []byte {
781886
return append(in, h.out[:]...)
782887
}
783888

889+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
890+
// The duplicate object contains all state and data contained in the
891+
// original object at the point of duplication.
892+
func (h *sha3_224Hash) Clone() (hash.Hash, error) {
893+
c, err := h.clone()
894+
if err != nil {
895+
return nil, err
896+
}
897+
return &sha3_224Hash{evpHash: c}, nil
898+
}
899+
784900
// NewSHA3_256 returns a new SHA3-256 hash.
785901
func NewSHA3_256() hash.Hash {
786902
return &sha3_256Hash{
@@ -798,6 +914,17 @@ func (h *sha3_256Hash) Sum(in []byte) []byte {
798914
return append(in, h.out[:]...)
799915
}
800916

917+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
918+
// The duplicate object contains all state and data contained in the
919+
// original object at the point of duplication.
920+
func (h *sha3_256Hash) Clone() (hash.Hash, error) {
921+
c, err := h.clone()
922+
if err != nil {
923+
return nil, err
924+
}
925+
return &sha3_256Hash{evpHash: c}, nil
926+
}
927+
801928
// NewSHA3_384 returns a new SHA3-384 hash.
802929
func NewSHA3_384() hash.Hash {
803930
return &sha3_384Hash{
@@ -815,6 +942,17 @@ func (h *sha3_384Hash) Sum(in []byte) []byte {
815942
return append(in, h.out[:]...)
816943
}
817944

945+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
946+
// The duplicate object contains all state and data contained in the
947+
// original object at the point of duplication.
948+
func (h *sha3_384Hash) Clone() (hash.Hash, error) {
949+
c, err := h.clone()
950+
if err != nil {
951+
return nil, err
952+
}
953+
return &sha3_384Hash{evpHash: c}, nil
954+
}
955+
818956
// NewSHA3_512 returns a new SHA3-512 hash.
819957
func NewSHA3_512() hash.Hash {
820958
return &sha3_512Hash{
@@ -832,6 +970,17 @@ func (h *sha3_512Hash) Sum(in []byte) []byte {
832970
return append(in, h.out[:]...)
833971
}
834972

973+
// Clone returns a new [hash.Hash] object that is a deep clone of itself.
974+
// The duplicate object contains all state and data contained in the
975+
// original object at the point of duplication.
976+
func (h *sha3_512Hash) Clone() (hash.Hash, error) {
977+
c, err := h.clone()
978+
if err != nil {
979+
return nil, err
980+
}
981+
return &sha3_512Hash{evpHash: c}, nil
982+
}
983+
835984
// appendUint64 appends x into b as a big endian byte sequence.
836985
func appendUint64(b []byte, x uint64) []byte {
837986
return append(b,

0 commit comments

Comments
 (0)