util: password: Add a helper to generate salted, hashed passwords

I have no idea if I'm doing this correctly, and I have no idea if the
library I am using is doing this correctly. Please check!
This commit is contained in:
James Shubin
2024-03-07 17:33:00 -05:00
parent 9351eee3f1
commit b496f8d70a
3 changed files with 33 additions and 0 deletions

1
go.mod
View File

@@ -118,6 +118,7 @@ require (
github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect
github.com/src-d/gcfg v1.4.0 // indirect github.com/src-d/gcfg v1.4.0 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // 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/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect

2
go.sum
View File

@@ -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-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 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= 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/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-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME= github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME=

View File

@@ -36,10 +36,12 @@ import (
"io" "io"
"os" "os"
"runtime" "runtime"
"strings"
"sync" "sync"
"syscall" "syscall"
"time" "time"
sha512Crypt "github.com/tredoe/osutil/v2/userutil/crypt/sha512_crypt"
"golang.org/x/sys/unix" "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
}