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  }