improve (crypto): derivate secret_key for each usage to reduce attack surface in the worst case scenario

This commit is contained in:
Mickael KERJEAN
2019-01-18 13:48:04 +11:00
parent 7af12753ca
commit ec6eb0e8fa
10 changed files with 53 additions and 26 deletions

View File

@ -15,7 +15,6 @@ import (
var ( var (
Config Configuration Config Configuration
configPath string = filepath.Join(GetCurrentDir(), CONFIG_PATH + "config.json") configPath string = filepath.Join(GetCurrentDir(), CONFIG_PATH + "config.json")
SECRET_KEY string
) )
type Configuration struct { type Configuration struct {
@ -321,7 +320,7 @@ func (this *Configuration) Initialise() {
} }
this.Save() this.Save()
} }
SECRET_KEY = this.Get("general.secret_key").String() InitSecretDerivate(this.Get("general.secret_key").String())
} }
func (this Configuration) Save() Configuration { func (this Configuration) Save() Configuration {

View File

@ -16,4 +16,22 @@ const (
URL_SETUP = "/admin/setup" URL_SETUP = "/admin/setup"
) )
var BUILD_NUMBER string var (
BUILD_NUMBER string
SECRET_KEY string
SECRET_KEY_DERIVATE_FOR_PROOF string
SECRET_KEY_DERIVATE_FOR_ADMIN string
SECRET_KEY_DERIVATE_FOR_USER string
)
/*
* Improve security by calculating derivative of the secret key to restrict the attack surface
* in the worst case scenario with one compromise secret key
*/
func InitSecretDerivate(secret string) {
SECRET_KEY = secret
SECRET_KEY_DERIVATE_FOR_PROOF = Hash("PROOF_" + SECRET_KEY, len(SECRET_KEY))
SECRET_KEY_DERIVATE_FOR_ADMIN = Hash("ADMIN_" + SECRET_KEY, len(SECRET_KEY))
SECRET_KEY_DERIVATE_FOR_USER = Hash("USER_" + SECRET_KEY, len(SECRET_KEY))
}

View File

@ -6,8 +6,7 @@ import (
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
"crypto/sha1" "crypto/sha256"
"encoding/base32"
"encoding/base64" "encoding/base64"
"io" "io"
"io/ioutil" "io/ioutil"
@ -45,10 +44,19 @@ func DecryptString(secret string, data string) (string, error){
return string(d), nil return string(d), nil
} }
func Hash(str string) string { func Hash(str string, n int) string {
hasher := sha1.New() hasher := sha256.New()
hasher.Write([]byte(str)) hasher.Write([]byte(str))
return "sha1::" + base32.HexEncoding.EncodeToString(hasher.Sum(nil)) d := hasher.Sum(nil)
size := len(Letters)
h := ""
for i:=0; i<len(d); i++ {
if n > 0 && i >= n {
break
}
h += string(Letters[int(d[i]) % size])
}
return h
} }
func RandomString(n int) string { func RandomString(n int) string {
@ -140,8 +148,8 @@ func verify(something []byte) ([]byte, error) {
// Create a unique ID that can be use to identify different session // Create a unique ID that can be use to identify different session
func GenerateID(ctx *App) string { func GenerateID(ctx *App) string {
p := ""
params := ctx.Session params := ctx.Session
p := "salt => " + SECRET_KEY
if params["type"] != "" { if params["type"] != "" {
p += "type =>" + params["type"] p += "type =>" + params["type"]
} }
@ -172,8 +180,10 @@ func GenerateID(ctx *App) string {
if params["token"] != "" { if params["token"] != "" {
p += "token =>" + params["token"] p += "token =>" + params["token"]
} }
if p == "salt => " + SECRET_KEY {
return "" if p == "" {
return Hash("N/A", 20)
} }
return Hash(p) p += "salt => " + SECRET_KEY
return Hash(p, 20)
} }

View File

@ -22,7 +22,7 @@ func AdminSessionGet(ctx App, res http.ResponseWriter, req *http.Request) {
return c.Value return c.Value
}() }()
str, err := DecryptString(SECRET_KEY, obfuscate); str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, obfuscate);
if err != nil { if err != nil {
SendSuccessResult(res, false) SendSuccessResult(res, false)
return return
@ -61,7 +61,7 @@ func AdminSessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Reques
// Step 3: Send response to the client // Step 3: Send response to the client
body, _ := json.Marshal(NewAdminToken()) body, _ := json.Marshal(NewAdminToken())
obfuscate, err := EncryptString(SECRET_KEY, string(body)) obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, string(body))
if err != nil { if err != nil {
SendErrorResult(res, err) SendErrorResult(res, err)
return return
@ -85,7 +85,7 @@ func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) {
} }
if c, err := json.Marshal(backends); err == nil { if c, err := json.Marshal(backends); err == nil {
hash := Hash(string(c)) hash := Hash(string(c), 20)
if req.Header.Get("If-None-Match") == hash { if req.Header.Get("If-None-Match") == hash {
res.WriteHeader(http.StatusNotModified) res.WriteHeader(http.StatusNotModified)
return return

View File

@ -92,7 +92,7 @@ func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) {
cfg := Config.Export() cfg := Config.Export()
if c, err := json.Marshal(cfg); err == nil { if c, err := json.Marshal(cfg); err == nil {
hash := Hash(string(c)) hash := Hash(string(c), 20)
if req.Header.Get("If-None-Match") == hash { if req.Header.Get("If-None-Match") == hash {
res.WriteHeader(http.StatusNotModified) res.WriteHeader(http.StatusNotModified)
return return

View File

@ -85,7 +85,7 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
Tmp1 interface{} Tmp1 interface{}
}{ files, perms } }{ files, perms }
if j, err := json.Marshal(tmp); err == nil { if j, err := json.Marshal(tmp); err == nil {
return Hash(string(j)) return Hash(string(j), 20)
} }
return "" return ""
}() }()

View File

@ -72,7 +72,7 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
SendErrorResult(res, NewError(err.Error(), 500)) SendErrorResult(res, NewError(err.Error(), 500))
return return
} }
obfuscate, err := EncryptString(SECRET_KEY, string(s)) obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_USER, string(s))
if err != nil { if err != nil {
SendErrorResult(res, NewError(err.Error(), 500)) SendErrorResult(res, NewError(err.Error(), 500))
return return

View File

@ -146,7 +146,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
} }
if submittedProof.Key != "" { if submittedProof.Key != "" {
submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value) submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value, 20)
verifiedProof = append(verifiedProof, submittedProof) verifiedProof = append(verifiedProof, submittedProof)
} }
@ -158,7 +158,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
Name: COOKIE_NAME_PROOF, Name: COOKIE_NAME_PROOF,
Value: func(p []model.Proof) string { Value: func(p []model.Proof) string {
j, _ := json.Marshal(p) j, _ := json.Marshal(p)
str, _ := EncryptString(SECRET_KEY, string(j)) str, _ := EncryptString(SECRET_KEY_DERIVATE_FOR_PROOF, string(j))
return str return str
}(verifiedProof), }(verifiedProof),
Path: COOKIE_PATH, Path: COOKIE_PATH,

View File

@ -30,7 +30,7 @@ func AdminOnly(fn func(App, http.ResponseWriter, *http.Request)) func(ctx App, r
return return
} }
str, err := DecryptString(SECRET_KEY, c.Value); str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, c.Value);
if err != nil { if err != nil {
SendErrorResult(res, ErrPermissionDenied) SendErrorResult(res, ErrPermissionDenied)
return return
@ -195,7 +195,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
var session map[string]string = make(map[string]string) var session map[string]string = make(map[string]string)
if ctx.Share.Id != "" { if ctx.Share.Id != "" {
str, err = DecryptString(SECRET_KEY, ctx.Share.Auth) str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, ctx.Share.Auth)
if err != nil { if err != nil {
// This typically happen when changing the secret key // This typically happen when changing the secret key
return session, nil return session, nil
@ -223,7 +223,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
return session, nil return session, nil
} }
str = cookie.Value str = cookie.Value
str, err = DecryptString(SECRET_KEY, str) str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, str)
if err != nil { if err != nil {
// This typically happen when changing the secret key // This typically happen when changing the secret key
return session, nil return session, nil

View File

@ -261,7 +261,7 @@ func ShareProofGetAlreadyVerified(req *http.Request) []Proof {
if len(cookieValue) > 500 { if len(cookieValue) > 500 {
return p return p
} }
j, err := DecryptString(SECRET_KEY, cookieValue) j, err := DecryptString(SECRET_KEY_DERIVATE_FOR_PROOF, cookieValue)
if err != nil { if err != nil {
return p return p
} }
@ -306,7 +306,7 @@ func shareProofAreEquivalent(ref Proof, p Proof) bool {
} }
for _, chunk := range strings.Split(ref.Value, ",") { for _, chunk := range strings.Split(ref.Value, ",") {
chunk = strings.Trim(chunk, " ") chunk = strings.Trim(chunk, " ")
if p.Id == Hash(ref.Key + "::" + chunk) { if p.Id == Hash(ref.Key + "::" + chunk, 20) {
return true return true
} }
} }