-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tommi2Day
committed
Mar 1, 2024
1 parent
f09cb2e
commit c807175
Showing
5 changed files
with
120 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package pwlib | ||
|
||
// Origin: https://github.com/tv42/scram-password/tree/main/internal/scramble | ||
// License: https://github.com/tv42/scram-password/blob/main/LICENSE | ||
|
||
import ( | ||
"crypto/rand" | ||
"encoding/base64" | ||
"fmt" | ||
|
||
"github.com/xdg-go/scram" | ||
) | ||
|
||
func makeSalt(size int) ([]byte, error) { | ||
salt := make([]byte, size) | ||
if _, err := rand.Read(salt); err != nil { | ||
return nil, err | ||
} | ||
return salt, nil | ||
} | ||
|
||
func hashWithKF(username string, password string, kf scram.KeyFactors) (string, error) { | ||
// We could expose this as a command-line flag, but first need a use case we can test against. | ||
const authID = "" | ||
// We could make the algorithm a command-line flag. | ||
client, err := scram.SHA256.NewClient(username, password, authID) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
credentials := client.GetStoredCredentials(kf) | ||
|
||
// SCRAM-SHA-256$<iter>:<salt>$<StoredKey>:<ServerKey> | ||
hashed := fmt.Sprintf("SCRAM-SHA-256$%d:%s$%s:%s", | ||
credentials.Iters, | ||
base64.StdEncoding.EncodeToString([]byte(credentials.Salt)), | ||
base64.StdEncoding.EncodeToString(credentials.StoredKey), | ||
base64.StdEncoding.EncodeToString(credentials.ServerKey), | ||
) | ||
return hashed, nil | ||
} | ||
|
||
// ScramPassword returns a SCRAM-SHA-256 password hash for the given username and password as used by postgresql11+ | ||
func ScramPassword(username string, password string) (string, error) { | ||
// We could take a known salt (as base64) as a command-line flag. | ||
|
||
// We could take salt size as a command-line flag. | ||
// | ||
// Postgres 14 uses salt size 16. | ||
// We'd rather be ahead of the curve than behind. | ||
const saltSize = 24 | ||
salt, err := makeSalt(saltSize) | ||
if err != nil { | ||
return "", err | ||
} | ||
kf := scram.KeyFactors{ | ||
Salt: string(salt), | ||
// We could take iterations as a command-line flag. | ||
Iters: 4096, | ||
} | ||
return hashWithKF(username, password, kf) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package pwlib | ||
|
||
// Origin: https://github.com/tv42/scram-password/tree/main/internal/scramble | ||
// License: https://github.com/tv42/scram-password/blob/main/LICENSE | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/xdg-go/scram" | ||
) | ||
|
||
func TestScram(t *testing.T) { | ||
salt := [32]byte{ | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
} | ||
hash, err := hashWithKF("jdoe", "s3kr1t", scram.KeyFactors{ | ||
Iters: 4096, | ||
Salt: string(salt[:]), | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
// nolint: gosec | ||
const want = `SCRAM-SHA-256$4096:AAECAwQFBgcAAQIDBAUGBwABAgMEBQYHAAECAwQFBgc=$3OKulhqxk9w6FbPtpUHCuIkEsW+2F2cjX0/ABNgYsbI=:BZ55glbzmkm4V5VjvpHHENWSEZE/IVxZWuAqeLUsikQ=` | ||
if g, e := hash, want; g != e { | ||
t.Errorf("wrong hash:\n\tgot\t%s\n\twant\t%s\n", g, e) | ||
} | ||
} | ||
|
||
func TestScramPassword(t *testing.T) { | ||
username := "testuser" | ||
password := "verySecret" | ||
actual, err := ScramPassword(username, password) | ||
assert.NoError(t, err, "should not return error:%s", err) | ||
assert.NotEmpty(t, actual, "Value should not be empty") | ||
t.Log(actual) | ||
} |