80 lines
2.0 KiB
Go
80 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
)
|
|
|
|
func connectDB() (*sql.DB, error) {
|
|
return sql.Open("mysql", "rosetta:code@/rc")
|
|
}
|
|
|
|
func createUser(db *sql.DB, user, pwd string) error {
|
|
salt := make([]byte, 16)
|
|
rand.Reader.Read(salt)
|
|
_, err := db.Exec(`insert into users (username, pass_salt, pass_md5)
|
|
values (?, ?, ?)`, user, salt, saltHash(salt, pwd))
|
|
if err != nil {
|
|
return fmt.Errorf("User %s already exits", user)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func authenticateUser(db *sql.DB, user, pwd string) error {
|
|
var salt, hash []byte
|
|
row := db.QueryRow(`select pass_salt, pass_md5 from users
|
|
where username=?`, user)
|
|
if err := row.Scan(&salt, &hash); err != nil {
|
|
return fmt.Errorf("User %s unknown", user)
|
|
}
|
|
if !bytes.Equal(saltHash(salt, pwd), hash) {
|
|
return fmt.Errorf("User %s invalid password", user)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func saltHash(salt []byte, pwd string) []byte {
|
|
h := md5.New()
|
|
h.Write(salt)
|
|
h.Write([]byte(pwd))
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
func main() {
|
|
// demonstrate
|
|
db, err := connectDB()
|
|
defer db.Close()
|
|
createUser(db, "sam", "123")
|
|
err = authenticateUser(db, "sam", "123")
|
|
if err == nil {
|
|
fmt.Println("User sam authenticated")
|
|
}
|
|
|
|
// extra
|
|
fmt.Println()
|
|
// show contents of database
|
|
rows, _ := db.Query(`select username, pass_salt, pass_md5 from users`)
|
|
var user string
|
|
var salt, hash []byte
|
|
for rows.Next() {
|
|
rows.Scan(&user, &salt, &hash)
|
|
fmt.Printf("%s %x %x\n", user, salt, hash)
|
|
}
|
|
// try creating same user again
|
|
err = createUser(db, "sam", "123")
|
|
fmt.Println(err)
|
|
// try authenticating unknown user
|
|
err = authenticateUser(db, "pam", "123")
|
|
fmt.Println(err)
|
|
// try wrong password
|
|
err = authenticateUser(db, "sam", "1234")
|
|
fmt.Println(err)
|
|
// clear table to run program again
|
|
db.Exec(`truncate table users`)
|
|
}
|