md5.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:generate go run gen.go -full -output md5block.go
  5. // Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
  6. package md5
  7. import (
  8. "crypto"
  9. "hash"
  10. )
  11. func init() {
  12. crypto.RegisterHash(crypto.MD5, New)
  13. }
  14. // The size of an MD5 checksum in bytes.
  15. const Size = 16
  16. // The blocksize of MD5 in bytes.
  17. const BlockSize = 64
  18. const (
  19. chunk = 64
  20. init0 = 0x67452301
  21. init1 = 0xEFCDAB89
  22. init2 = 0x98BADCFE
  23. init3 = 0x10325476
  24. )
  25. // digest represents the partial evaluation of a checksum.
  26. type digest struct {
  27. s [4]uint32
  28. x [chunk]byte
  29. nx int
  30. len uint64
  31. }
  32. func (d *digest) Reset() {
  33. d.s[0] = init0
  34. d.s[1] = init1
  35. d.s[2] = init2
  36. d.s[3] = init3
  37. d.nx = 0
  38. d.len = 0
  39. }
  40. // New returns a new hash.Hash computing the MD5 checksum.
  41. func New() hash.Hash {
  42. d := new(digest)
  43. d.Reset()
  44. return d
  45. }
  46. func (d *digest) Size() int { return Size }
  47. func (d *digest) BlockSize() int { return BlockSize }
  48. func (d *digest) Write(p []byte) (nn int, err error) {
  49. nn = len(p)
  50. d.len += uint64(nn)
  51. if d.nx > 0 {
  52. n := len(p)
  53. if n > chunk-d.nx {
  54. n = chunk - d.nx
  55. }
  56. for i := 0; i < n; i++ {
  57. d.x[d.nx+i] = p[i]
  58. }
  59. d.nx += n
  60. if d.nx == chunk {
  61. block(d, d.x[0:chunk])
  62. d.nx = 0
  63. }
  64. p = p[n:]
  65. }
  66. if len(p) >= chunk {
  67. n := len(p) &^ (chunk - 1)
  68. block(d, p[:n])
  69. p = p[n:]
  70. }
  71. if len(p) > 0 {
  72. d.nx = copy(d.x[:], p)
  73. }
  74. return
  75. }
  76. func (d0 *digest) Sum(in []byte) []byte {
  77. // Make a copy of d0 so that caller can keep writing and summing.
  78. d := *d0
  79. hash := d.checkSum()
  80. return append(in, hash[:]...)
  81. }
  82. func (d *digest) checkSum() [Size]byte {
  83. // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
  84. len := d.len
  85. var tmp [64]byte
  86. tmp[0] = 0x80
  87. if len%64 < 56 {
  88. d.Write(tmp[0 : 56-len%64])
  89. } else {
  90. d.Write(tmp[0 : 64+56-len%64])
  91. }
  92. // Length in bits.
  93. len <<= 3
  94. for i := uint(0); i < 8; i++ {
  95. tmp[i] = byte(len >> (8 * i))
  96. }
  97. d.Write(tmp[0:8])
  98. if d.nx != 0 {
  99. panic("d.nx != 0")
  100. }
  101. var digest [Size]byte
  102. for i, s := range d.s {
  103. digest[i*4] = byte(s)
  104. digest[i*4+1] = byte(s >> 8)
  105. digest[i*4+2] = byte(s >> 16)
  106. digest[i*4+3] = byte(s >> 24)
  107. }
  108. return digest
  109. }
  110. // Sum returns the MD5 checksum of the data.
  111. func Sum(data []byte) [Size]byte {
  112. var d digest
  113. d.Reset()
  114. d.Write(data)
  115. return d.checkSum()
  116. }