github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/packages/multi_hasher.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 package packages 7 8 import ( 9 "crypto/md5" 10 "crypto/sha1" 11 "crypto/sha256" 12 "crypto/sha512" 13 "encoding" 14 "errors" 15 "hash" 16 "io" 17 ) 18 19 const ( 20 marshaledSizeMD5 = 92 21 marshaledSizeSHA1 = 96 22 marshaledSizeSHA256 = 108 23 marshaledSizeSHA512 = 204 24 25 marshaledSize = marshaledSizeMD5 + marshaledSizeSHA1 + marshaledSizeSHA256 + marshaledSizeSHA512 26 ) 27 28 // HashSummer provide a Sums method 29 type HashSummer interface { 30 Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512 []byte) 31 } 32 33 // MultiHasher calculates multiple checksums 34 type MultiHasher struct { 35 md5 hash.Hash 36 sha1 hash.Hash 37 sha256 hash.Hash 38 sha512 hash.Hash 39 40 combinedWriter io.Writer 41 } 42 43 // NewMultiHasher creates a multi hasher 44 func NewMultiHasher() *MultiHasher { 45 md5 := md5.New() 46 sha1 := sha1.New() 47 sha256 := sha256.New() 48 sha512 := sha512.New() 49 50 combinedWriter := io.MultiWriter(md5, sha1, sha256, sha512) 51 52 return &MultiHasher{ 53 md5, 54 sha1, 55 sha256, 56 sha512, 57 combinedWriter, 58 } 59 } 60 61 // MarshalBinary implements encoding.BinaryMarshaler 62 func (h *MultiHasher) MarshalBinary() ([]byte, error) { 63 md5Bytes, err := h.md5.(encoding.BinaryMarshaler).MarshalBinary() 64 if err != nil { 65 return nil, err 66 } 67 sha1Bytes, err := h.sha1.(encoding.BinaryMarshaler).MarshalBinary() 68 if err != nil { 69 return nil, err 70 } 71 sha256Bytes, err := h.sha256.(encoding.BinaryMarshaler).MarshalBinary() 72 if err != nil { 73 return nil, err 74 } 75 sha512Bytes, err := h.sha512.(encoding.BinaryMarshaler).MarshalBinary() 76 if err != nil { 77 return nil, err 78 } 79 80 b := make([]byte, 0, marshaledSize) 81 b = append(b, md5Bytes...) 82 b = append(b, sha1Bytes...) 83 b = append(b, sha256Bytes...) 84 b = append(b, sha512Bytes...) 85 return b, nil 86 } 87 88 // UnmarshalBinary implements encoding.BinaryUnmarshaler 89 func (h *MultiHasher) UnmarshalBinary(b []byte) error { 90 if len(b) != marshaledSize { 91 return errors.New("invalid hash state size") 92 } 93 94 if err := h.md5.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeMD5]); err != nil { 95 return err 96 } 97 98 b = b[marshaledSizeMD5:] 99 if err := h.sha1.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA1]); err != nil { 100 return err 101 } 102 103 b = b[marshaledSizeSHA1:] 104 if err := h.sha256.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA256]); err != nil { 105 return err 106 } 107 108 b = b[marshaledSizeSHA256:] 109 return h.sha512.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA512]) 110 } 111 112 // Write implements io.Writer 113 func (h *MultiHasher) Write(p []byte) (int, error) { 114 return h.combinedWriter.Write(p) 115 } 116 117 // Sums gets the MD5, SHA1, SHA256 and SHA512 checksums of the data 118 func (h *MultiHasher) Sums() (hashMD5, hashSHA1, hashSHA256, hashSHA512 []byte) { 119 hashMD5 = h.md5.Sum(nil) 120 hashSHA1 = h.sha1.Sum(nil) 121 hashSHA256 = h.sha256.Sum(nil) 122 hashSHA512 = h.sha512.Sum(nil) 123 return 124 }