Skip to content

Commit

Permalink
Implementing password hashing using bycrypt
Browse files Browse the repository at this point in the history
  • Loading branch information
ukane-philemon committed Dec 17, 2021
1 parent 913b38b commit 2e6789a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 8 deletions.
7 changes: 1 addition & 6 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func loadConfig() (*config, error) {
}
return nil, err
}

// Set the active network.
minRequired := 1
switch cfg.Network {
Expand Down Expand Up @@ -302,11 +302,6 @@ func loadConfig() (*config, error) {
return nil, errors.New("the supportemail option is not set")
}

// Ensure the administrator password is set.
if cfg.AdminPass == "" {
return nil, errors.New("the adminpass option is not set")
}

// Ensure the dcrd RPC username is set.
if cfg.DcrdUser == "" {
return nil, errors.New("the dcrduser option is not set")
Expand Down
27 changes: 27 additions & 0 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"crypto/ed25519"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -52,6 +53,8 @@ var (
lastAddressIndexK = []byte("lastaddressindex")
// altSignAddrBktK stores alternate signing addresses.
altSignAddrBktK = []byte("altsigbkt")
//AdminPassHash is the hashed form of the AdminPass
adminPassHashK = []byte("adminPassHash")
)

const (
Expand Down Expand Up @@ -457,3 +460,27 @@ func (vdb *VspDatabase) CheckIntegrity(ctx context.Context, params *chaincfg.Par

return nil
}

func (vdb *VspDatabase) UpdateAdminPass(adminPassHash string) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
vspBkt := tx.Bucket(vspBktK)

// Add AdminPassHash to database.
return vspBkt.Put(adminPassHashK, []byte(adminPassHash))
})
}

func (vdb *VspDatabase) GetAdminHash() ([]byte, error) {
var adminPassHash []byte
err := vdb.db.View(func(tx *bolt.Tx) error {
vspBkt := tx.Bucket(vspBktK)

adminPassHash = vspBkt.Get(adminPassHashK)
if adminPassHash == nil {
return errors.New("AdminPassHash has not been set")
}
return nil
})

return adminPassHash, err
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ require (
github.com/jrick/logrotate v1.0.0
github.com/jrick/wsrpc/v2 v2.3.4
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
Expand All @@ -200,6 +202,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -220,13 +224,19 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
Expand Down
29 changes: 29 additions & 0 deletions vspd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/decred/vspd/rpc"
"github.com/decred/vspd/version"
"github.com/decred/vspd/webapi"
"golang.org/x/crypto/bcrypt"
)

// maxVoteChangeRecords defines how many vote change records will be stored for
Expand All @@ -37,6 +38,13 @@ func main() {
}
}

//Implementing password hash to increase security for AdminPass
//hashPassword hash cfg.AdminPass and returns the hash.
func hashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 15)
return string(bytes), err
}

// run is the main startup and teardown logic performed by the main package. It
// is responsible for parsing the config, creating a dcrwallet RPC client,
// opening the database, starting the webserver, and stopping all started
Expand Down Expand Up @@ -74,6 +82,27 @@ func run(ctx context.Context) error {
}
defer db.Close()

//Check if adminPass Hash is set in db.
hash, err := db.GetAdminHash()

//Ensure adminpass option is set
if cfg.AdminPass == "" && err != nil {
return errors.New("the adminpass option is not set")
}

if hash != nil && cfg.AdminPass != "" {
//Hash the cfg.AdminPass value
cfg.AdminPass, err = hashPassword(cfg.AdminPass)

if err != nil {
return fmt.Errorf("Hashing AdminPass Failed: %w", err)
}

//if adminpass is set, overwrite the saved adminpass hash in database.
db.UpdateAdminPass(cfg.AdminPass)

}

// Create RPC client for local dcrd instance (used for broadcasting and
// checking the status of fee transactions).
dcrd := rpc.SetupDcrd(cfg.DcrdUser, cfg.DcrdPass, cfg.DcrdHost, cfg.dcrdCert, nil)
Expand Down
17 changes: 15 additions & 2 deletions webapi/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/decred/vspd/rpc"
"github.com/gin-gonic/gin"
"github.com/gorilla/sessions"
"golang.org/x/crypto/bcrypt"
)

// WalletStatus describes the current status of a single voting wallet. This is
Expand Down Expand Up @@ -197,12 +198,24 @@ func ticketSearch(c *gin.Context) {
})
}

//checkPasswordHash compare hash value of given AdminPass with AdminPass hash.
func CheckPasswordHash(hash []byte, password string) bool {
err := bcrypt.CompareHashAndPassword(hash, []byte(password))
return err == nil
}

// adminLogin is the handler for "POST /admin". If a valid password is provided,
// the current session will be authenticated as an admin.
func adminLogin(c *gin.Context) {
password := c.PostForm("password")

if password != cfg.AdminPass {
hashedPass, err := db.GetAdminHash()
if err != nil {
log.Warnf("Not able to get Admin Hash: %w", err)
}

ok := CheckPasswordHash(hashedPass, password)

if !ok {
log.Warnf("Failed login attempt from %s", c.ClientIP())
c.HTML(http.StatusUnauthorized, "login.html", gin.H{
"WebApiCache": getCache(),
Expand Down

0 comments on commit 2e6789a

Please sign in to comment.