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