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

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