1 // Copyright 2013, Jonas mg 2 // All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style license 5 // that can be found in the LICENSE file. 6 7 // Package crypt provides interface for password crypt functions and collects 8 // common constants. 9 package crypt 10 11 import ( 12 "errors" 13 "strings" 14 15 "edge-infra.dev/pkg/lib/crypto/osutilcrypt/common" 16 ) 17 18 var ErrKeyMismatch = errors.New("hashed value is not the hash of the given password") 19 20 // Crypter is the common interface implemented by all crypt functions. 21 type Crypter interface { 22 // Generate performs the hashing algorithm, returning a full hash suitable 23 // for storage and later password verification. 24 // 25 // If the salt is empty, a randomly-generated salt will be generated with a 26 // length of SaltLenMax and number RoundsDefault of rounds. 27 // 28 // Any error only can be got when the salt argument is not empty. 29 Generate(key, salt []byte) (string, error) 30 31 // Verify compares a hashed key with its possible key equivalent. 32 // Returns nil on success, or an error on failure; if the hashed key is 33 // different, the error is "ErrKeyMismatch". 34 Verify(hashedKey string, key []byte) error 35 36 // Cost returns the hashing cost (in rounds) used to create the given hashed 37 // key. 38 // 39 // When, in the future, the hashing cost of a key needs to be increased in 40 // order to adjust for greater computational power, this function allows one 41 // to establish which keys need to be updated. 42 // 43 // The algorithms based in MD5-crypt use a fixed value of rounds. 44 Cost(hashedKey string) (int, error) 45 46 // SetSalt sets a different salt. It is used to easily create derivated 47 // algorithms, i.e. "apr1_crypt" from "md5_crypt". 48 SetSalt(salt common.Salt) 49 } 50 51 // Crypt identifies a crypt function that is implemented in another package. 52 type Crypt uint 53 54 const ( 55 APR1 Crypt = iota + 1 // import "github.com/tredoe/osutil/v2/user/crypt/apr1_crypt" 56 MD5 // import "github.com/tredoe/osutil/v2/user/crypt/md5_crypt" 57 SHA256 // import "github.com/tredoe/osutil/v2/user/crypt/sha256_crypt" 58 SHA512 // import "github.com/tredoe/osutil/v2/user/crypt/sha512_crypt" 59 maxCrypt 60 ) 61 62 var cryptPrefixes = make([]string, maxCrypt) 63 64 var crypts = make([]func() Crypter, maxCrypt) 65 66 // RegisterCrypt registers a function that returns a new instance of the given 67 // crypt function. This is intended to be called from the init function in 68 // packages that implement crypt functions. 69 func RegisterCrypt(c Crypt, f func() Crypter, prefix string) { 70 if c >= maxCrypt { 71 panic("crypt: RegisterHash of unknown crypt function") 72 } 73 crypts[c] = f 74 cryptPrefixes[c] = prefix 75 } 76 77 // New returns a new crypter. 78 func New(c Crypt) Crypter { 79 f := crypts[c] 80 if f != nil { 81 return f() 82 } 83 panic("crypt: requested crypt function is unavailable") 84 } 85 86 // NewFromHash returns a new Crypter using the prefix in the given hashed key. 87 func NewFromHash(hashedKey string) Crypter { 88 var f func() Crypter 89 90 if strings.HasPrefix(hashedKey, cryptPrefixes[SHA512]) { 91 f = crypts[SHA512] 92 } else if strings.HasPrefix(hashedKey, cryptPrefixes[SHA256]) { 93 f = crypts[SHA256] 94 } else if strings.HasPrefix(hashedKey, cryptPrefixes[MD5]) { 95 f = crypts[MD5] 96 } else if strings.HasPrefix(hashedKey, cryptPrefixes[APR1]) { 97 f = crypts[APR1] 98 } else { 99 toks := strings.SplitN(hashedKey, "$", 3) 100 prefix := "$" + toks[1] + "$" 101 panic("crypt: unknown cryp function from prefix: " + prefix) 102 } 103 104 if f != nil { 105 return f() 106 } 107 panic("crypt: requested cryp function is unavailable") 108 } 109