You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

multi_hasher.go 2.9KB

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