diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 93a85c0..4510d67 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,20 +20,20 @@ jobs: shell: bash steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true cache: true - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v3 + uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest - args: release --rm-dist + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 92104f8..ae1ab13 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -52,10 +52,10 @@ jobs: run: sudo apt update && sudo apt install -y --no-install-recommends postgresql-client - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true @@ -68,7 +68,7 @@ jobs: run: | echo -n "CREATE ROLE test WITH LOGIN PASSWORD " >> $SQL_FILE_PATH echo -n "'" >> $SQL_FILE_PATH - ./encrypt test | tr -d '\n' >> $SQL_FILE_PATH + ./cmd/tool/encrypt test | tr -d '\n' >> $SQL_FILE_PATH echo "';" >> $SQL_FILE_PATH cat $SQL_FILE_PATH | tee /dev/stderr | psql env: diff --git a/.gitignore b/.gitignore index 61a7d57..5086168 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -encrypt +/cmd/tool/encrypt diff --git a/.goreleaser.yaml b/.goreleaser.yaml index a59950b..294a58b 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -22,10 +22,9 @@ builds: goarm: - 6 - 7 + main: ./cmd/tool # https://goreleaser.com/customization/archive/ archives: - name_template: '{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}-v{{ . }}{{ end }}' format: binary - replacements: - amd64: x86_64 diff --git a/Makefile b/Makefile index 983351f..9587fa6 100644 --- a/Makefile +++ b/Makefile @@ -3,5 +3,7 @@ GOOS ?= $(shell go env GOOS) GOARCH ?= $(shell go env GOARCH) CGO_ENABLED ?= $(shell go env CGO_ENABLED) -encrypt: main.go - GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=${CGO_ENABLED} go build -ldflags="-s -w" -trimpath -o $@ +cmd/tool/encrypt: cmd/tool/main.go + GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=${CGO_ENABLED} go build -ldflags="-s -w" -trimpath -o $@ $^ + +.PHONY: cmd/tool/encrypt diff --git a/cmd/tool/main.go b/cmd/tool/main.go new file mode 100644 index 0000000..943114a --- /dev/null +++ b/cmd/tool/main.go @@ -0,0 +1,54 @@ +package main + +// @see https://github.com/postgres/postgres/blob/c30f54ad732ca5c8762bb68bbe0f51de9137dd72/src/interfaces/libpq/fe-auth.c#L1167-L1285 +// @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/interfaces/libpq/fe-auth-scram.c#L868-L905 +// @see https://github.com/postgres/postgres/blob/c30f54ad732ca5c8762bb68bbe0f51de9137dd72/src/port/pg_strong_random.c#L66-L96 +// @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/common/scram-common.c#L160-L274 +// @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/common/scram-common.c#L27-L85 + +import ( + "fmt" + "os" + "syscall" + + "github.com/supercaracal/scram-sha-256/pkg/pgpasswd" + "golang.org/x/crypto/ssh/terminal" +) + +func readRawPassword(fd int) ([]byte, error) { + input, err := terminal.ReadPassword(fd) + if err != nil { + return nil, err + } + return input, nil +} + +func main() { + var rawPassword []byte + + if len(os.Args) > 1 { + rawPassword = []byte(os.Args[1]) + } else { + fmt.Print("Raw password: ") + passwd, err := readRawPassword(int(syscall.Stdin)) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + rawPassword = passwd + fmt.Println() + } + + if len(rawPassword) == 0 { + fmt.Println("empty password") + os.Exit(1) + } + + if password, err := pgpasswd.Encrypt(rawPassword); err != nil { + fmt.Println(err) + os.Exit(1) + } else { + fmt.Printf("%s\n", password) + os.Exit(0) + } +} diff --git a/go.mod b/go.mod index 623ae6a..190ba40 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,9 @@ module github.com/supercaracal/scram-sha-256 go 1.19 -require golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be +require golang.org/x/crypto v0.19.0 require ( - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect ) diff --git a/go.sum b/go.sum index ba6abb3..8145e8f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,6 @@ -golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A= -golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= diff --git a/main.go b/pkg/pgpasswd/crypto.go similarity index 76% rename from main.go rename to pkg/pgpasswd/crypto.go index 7f13711..166d7cd 100644 --- a/main.go +++ b/pkg/pgpasswd/crypto.go @@ -1,4 +1,4 @@ -package main +package pgpasswd // @see https://github.com/postgres/postgres/blob/c30f54ad732ca5c8762bb68bbe0f51de9137dd72/src/interfaces/libpq/fe-auth.c#L1167-L1285 // @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/interfaces/libpq/fe-auth-scram.c#L868-L905 @@ -13,11 +13,8 @@ import ( "encoding/base64" "fmt" "io" - "os" - "syscall" "golang.org/x/crypto/pbkdf2" - "golang.org/x/crypto/ssh/terminal" ) const ( @@ -44,14 +41,6 @@ func genSalt(size int) ([]byte, error) { return salt, nil } -func readRawPassword(fd int) ([]byte, error) { - input, err := terminal.ReadPassword(fd) - if err != nil { - return nil, err - } - return input, nil -} - func encodeB64(src []byte) (dst []byte) { dst = make([]byte, base64.StdEncoding.EncodedLen(len(src))) base64.StdEncoding.Encode(dst, src) @@ -84,33 +73,12 @@ func encryptPassword(rawPassword, salt []byte, iter, keyLen int) string { ) } -func main() { - var rawPassword []byte - - if len(os.Args) > 1 { - rawPassword = []byte(os.Args[1]) - } else { - fmt.Print("Raw password: ") - passwd, err := readRawPassword(int(syscall.Stdin)) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - rawPassword = passwd - fmt.Println() - } - - if len(rawPassword) == 0 { - fmt.Println("empty password") - os.Exit(1) - } - +// Encrypt encrypts a raw password with scram-sha-256 +func Encrypt(rawPassword []byte) (string, error) { salt, err := genSalt(saltSize) if err != nil { - fmt.Println(err) - os.Exit(1) + return "", err } - fmt.Printf("%s\n", encryptPassword(rawPassword, salt, iterationCnt, digestLen)) - os.Exit(0) + return encryptPassword(rawPassword, salt, iterationCnt, digestLen), nil }