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  }