diff --git a/go.mod b/go.mod index 576c01d4..3aec20e9 100644 --- a/go.mod +++ b/go.mod @@ -118,6 +118,7 @@ require ( github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect github.com/src-d/gcfg v1.4.0 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect + github.com/tredoe/osutil/v2 v2.0.0-rc.16 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect diff --git a/go.sum b/go.sum index d017a9ea..39ff925d 100644 --- a/go.sum +++ b/go.sum @@ -780,6 +780,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/tredoe/osutil/v2 v2.0.0-rc.16 h1:5A2SKvyB2c3lhPYUIHyFtu6jbaXlaA3Hu5gWIam8Pik= +github.com/tredoe/osutil/v2 v2.0.0-rc.16/go.mod h1:uLRVx/3pb7Y4RQhG8cQFbPE9ha5r81e6MXpBsxbTAYc= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME= diff --git a/util/password/password.go b/util/password/password.go index 5b0c124c..24594a4c 100644 --- a/util/password/password.go +++ b/util/password/password.go @@ -36,10 +36,12 @@ import ( "io" "os" "runtime" + "strings" "sync" "syscall" "time" + sha512Crypt "github.com/tredoe/osutil/v2/userutil/crypt/sha512_crypt" "golang.org/x/sys/unix" ) @@ -152,3 +154,31 @@ func ReadPasswordCtxFdPrompt(ctx context.Context, fd int, prompt string) ([]byte } } } + +// SaltedSHA512Password is meant to generate Ulrich Drepper's salted SHA512 unix +// crypt password hash as seen at https://www.akkadia.org/drepper/SHA-crypt.txt +// and used for /etc/shadow and anaconda kickstart files. Please read the +// following disclaimer carefully before using this: XXX: I have no idea if I am +// doing this correctly, and I have no idea if the library I am using is doing +// this correctly. Please check! Also: https://github.com/golang/go/issues/21865 +func SaltedSHA512Password(password []byte) (string, error) { + crypter := sha512Crypt.New() + saltObj := sha512Crypt.GetSalt() // New() builds us one, this is another + crypter.SetSalt(saltObj) + salt := saltObj.GenerateWRounds(sha512Crypt.SaltLenMax, sha512Crypt.RoundsDefault) + // NOTE: We could pass an empty salt and the above should happen, but we + // wouldn't notice it if the API changed and no longer did this magic... + hash, err := crypter.Generate(password, salt) + if err != nil { + return "", err + } + if len(hash) != 106 { // XXX: the rounds=? stuff feels not part of spec + return "", fmt.Errorf("password was not generated correctly") + } + if !strings.HasPrefix(hash, sha512Crypt.MagicPrefix) { + // programming error + return "", fmt.Errorf("magic prefix was missing") + } + + return hash, nil +}