mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 10:37:56 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			87 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package scram
 | |
| 
 | |
| //
 | |
| // @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
 | |
| 
 | |
| // Implementation from https://github.com/supercaracal/scram-sha-256/blob/d3c05cd927770a11c6e12de3e3a99c3446a1f78d/main.go
 | |
| import (
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/sha256"
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 
 | |
| 	"golang.org/x/crypto/pbkdf2"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/include/common/scram-common.h#L36-L41
 | |
| 	saltSize = 16
 | |
| 
 | |
| 	// @see https://github.com/postgres/postgres/blob/c30f54ad732ca5c8762bb68bbe0f51de9137dd72/src/include/common/sha2.h#L22
 | |
| 	digestLen = 32
 | |
| 
 | |
| 	// @see https://github.com/postgres/postgres/blob/e6bdfd9700ebfc7df811c97c2fc46d7e94e329a2/src/include/common/scram-common.h#L43-L47
 | |
| 	iterationCnt = 4096
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	clientRawKey = []byte("Client Key")
 | |
| 	serverRawKey = []byte("Server Key")
 | |
| )
 | |
| 
 | |
| func genSalt(size int) ([]byte, error) {
 | |
| 	salt := make([]byte, size)
 | |
| 	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return salt, nil
 | |
| }
 | |
| 
 | |
| func encodeB64(src []byte) (dst []byte) {
 | |
| 	dst = make([]byte, base64.StdEncoding.EncodedLen(len(src)))
 | |
| 	base64.StdEncoding.Encode(dst, src)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func getHMACSum(key, msg []byte) []byte {
 | |
| 	h := hmac.New(sha256.New, key)
 | |
| 	_, _ = h.Write(msg)
 | |
| 	return h.Sum(nil)
 | |
| }
 | |
| 
 | |
| func getSHA256Sum(key []byte) []byte {
 | |
| 	h := sha256.New()
 | |
| 	_, _ = h.Write(key)
 | |
| 	return h.Sum(nil)
 | |
| }
 | |
| 
 | |
| func hashPassword(rawPassword, salt []byte, iter, keyLen int) string {
 | |
| 	digestKey := pbkdf2.Key(rawPassword, salt, iter, keyLen, sha256.New)
 | |
| 	clientKey := getHMACSum(digestKey, clientRawKey)
 | |
| 	storedKey := getSHA256Sum(clientKey)
 | |
| 	serverKey := getHMACSum(digestKey, serverRawKey)
 | |
| 
 | |
| 	return fmt.Sprintf("SCRAM-SHA-256$%d:%s$%s:%s",
 | |
| 		iter,
 | |
| 		string(encodeB64(salt)),
 | |
| 		string(encodeB64(storedKey)),
 | |
| 		string(encodeB64(serverKey)),
 | |
| 	)
 | |
| }
 | |
| 
 | |
| func Hash(password string) (string, error) {
 | |
| 	salt, err := genSalt(saltSize)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	hashedPassword := hashPassword([]byte(password), salt, iterationCnt, digestLen)
 | |
| 	return hashedPassword, nil
 | |
| }
 | 
