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.

md5_crypt.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // (C) Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>. All
  2. // rights reserved. Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package md5_crypt implements the standard Unix MD5-crypt algorithm created by
  5. // Poul-Henning Kamp for FreeBSD.
  6. package md5_crypt
  7. import (
  8. "bytes"
  9. "crypto/md5"
  10. "crypto/subtle"
  11. "github.com/GehirnInc/crypt"
  12. "github.com/GehirnInc/crypt/common"
  13. "github.com/GehirnInc/crypt/internal"
  14. )
  15. func init() {
  16. crypt.RegisterCrypt(crypt.MD5, New, MagicPrefix)
  17. }
  18. // NOTE: Cisco IOS only allows salts of length 4.
  19. const (
  20. MagicPrefix = "$1$"
  21. SaltLenMin = 1 // Real minimum is 0, but that isn't useful.
  22. SaltLenMax = 8
  23. RoundsDefault = 1000
  24. )
  25. type crypter struct{ Salt common.Salt }
  26. // New returns a new crypt.Crypter computing the MD5-crypt password hashing.
  27. func New() crypt.Crypter {
  28. return &crypter{
  29. common.Salt{
  30. MagicPrefix: []byte(MagicPrefix),
  31. SaltLenMin: SaltLenMin,
  32. SaltLenMax: SaltLenMax,
  33. RoundsDefault: RoundsDefault,
  34. },
  35. }
  36. }
  37. func (c *crypter) Generate(key, salt []byte) (result string, err error) {
  38. if len(salt) == 0 {
  39. salt = c.Salt.Generate(SaltLenMax)
  40. }
  41. salt, _, _, _, err = c.Salt.Decode(salt)
  42. if err != nil {
  43. return
  44. }
  45. keyLen := len(key)
  46. h := md5.New()
  47. // Compute sumB
  48. h.Write(key)
  49. h.Write(salt)
  50. h.Write(key)
  51. sumB := h.Sum(nil)
  52. // Compute sumA
  53. h.Reset()
  54. h.Write(key)
  55. h.Write(c.Salt.MagicPrefix)
  56. h.Write(salt)
  57. h.Write(internal.RepeatByteSequence(sumB, keyLen))
  58. // The original implementation now does something weird:
  59. // For every 1 bit in the key, the first 0 is added to the buffer
  60. // For every 0 bit, the first character of the key
  61. // This does not seem to be what was intended but we have to follow this to
  62. // be compatible.
  63. for i := keyLen; i > 0; i >>= 1 {
  64. if i%2 == 0 {
  65. h.Write(key[0:1])
  66. } else {
  67. h.Write([]byte{0})
  68. }
  69. }
  70. sumA := h.Sum(nil)
  71. internal.CleanSensitiveData(sumB)
  72. // In fear of password crackers here comes a quite long loop which just
  73. // processes the output of the previous round again.
  74. // We cannot ignore this here.
  75. for i := 0; i < RoundsDefault; i++ {
  76. h.Reset()
  77. // Add key or last result.
  78. if i%2 != 0 {
  79. h.Write(key)
  80. } else {
  81. h.Write(sumA)
  82. }
  83. // Add salt for numbers not divisible by 3.
  84. if i%3 != 0 {
  85. h.Write(salt)
  86. }
  87. // Add key for numbers not divisible by 7.
  88. if i%7 != 0 {
  89. h.Write(key)
  90. }
  91. // Add key or last result.
  92. if i&1 != 0 {
  93. h.Write(sumA)
  94. } else {
  95. h.Write(key)
  96. }
  97. copy(sumA, h.Sum(nil))
  98. }
  99. buf := bytes.Buffer{}
  100. buf.Grow(len(c.Salt.MagicPrefix) + len(salt) + 1 + 22)
  101. buf.Write(c.Salt.MagicPrefix)
  102. buf.Write(salt)
  103. buf.WriteByte('$')
  104. buf.Write(common.Base64_24Bit([]byte{
  105. sumA[12], sumA[6], sumA[0],
  106. sumA[13], sumA[7], sumA[1],
  107. sumA[14], sumA[8], sumA[2],
  108. sumA[15], sumA[9], sumA[3],
  109. sumA[5], sumA[10], sumA[4],
  110. sumA[11],
  111. }))
  112. return buf.String(), nil
  113. }
  114. func (c *crypter) Verify(hashedKey string, key []byte) error {
  115. newHash, err := c.Generate(key, []byte(hashedKey))
  116. if err != nil {
  117. return err
  118. }
  119. if subtle.ConstantTimeCompare([]byte(newHash), []byte(hashedKey)) != 1 {
  120. return crypt.ErrKeyMismatch
  121. }
  122. return nil
  123. }
  124. func (c *crypter) Cost(hashedKey string) (int, error) { return RoundsDefault, nil }
  125. func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }