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