diff --git a/server/common/config.go b/server/common/config.go index b2542a20..b9a296d3 100644 --- a/server/common/config.go +++ b/server/common/config.go @@ -15,7 +15,6 @@ import ( var ( Config Configuration configPath string = filepath.Join(GetCurrentDir(), CONFIG_PATH + "config.json") - SECRET_KEY string ) type Configuration struct { @@ -321,7 +320,7 @@ func (this *Configuration) Initialise() { } this.Save() } - SECRET_KEY = this.Get("general.secret_key").String() + InitSecretDerivate(this.Get("general.secret_key").String()) } func (this Configuration) Save() Configuration { diff --git a/server/common/constants.go b/server/common/constants.go index bd3517cc..5e464471 100644 --- a/server/common/constants.go +++ b/server/common/constants.go @@ -16,4 +16,22 @@ const ( 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)) +} diff --git a/server/common/crypto.go b/server/common/crypto.go index 2d0eb0f6..485b6db7 100644 --- a/server/common/crypto.go +++ b/server/common/crypto.go @@ -6,8 +6,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" - "crypto/sha1" - "encoding/base32" + "crypto/sha256" "encoding/base64" "io" "io/ioutil" @@ -45,10 +44,19 @@ func DecryptString(secret string, data string) (string, error){ return string(d), nil } -func Hash(str string) string { - hasher := sha1.New() +func Hash(str string, n int) string { + hasher := sha256.New() hasher.Write([]byte(str)) - return "sha1::" + base32.HexEncoding.EncodeToString(hasher.Sum(nil)) + d := hasher.Sum(nil) + size := len(Letters) + h := "" + for i:=0; i 0 && i >= n { + break + } + h += string(Letters[int(d[i]) % size]) + } + return h } 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 func GenerateID(ctx *App) string { + p := "" params := ctx.Session - p := "salt => " + SECRET_KEY if params["type"] != "" { p += "type =>" + params["type"] } @@ -172,8 +180,10 @@ func GenerateID(ctx *App) string { if 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) } diff --git a/server/ctrl/admin.go b/server/ctrl/admin.go index 4ccb0163..e4619eff 100644 --- a/server/ctrl/admin.go +++ b/server/ctrl/admin.go @@ -22,7 +22,7 @@ func AdminSessionGet(ctx App, res http.ResponseWriter, req *http.Request) { return c.Value }() - str, err := DecryptString(SECRET_KEY, obfuscate); + str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, obfuscate); if err != nil { SendSuccessResult(res, false) return @@ -61,7 +61,7 @@ func AdminSessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Reques // Step 3: Send response to the client body, _ := json.Marshal(NewAdminToken()) - obfuscate, err := EncryptString(SECRET_KEY, string(body)) + obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, string(body)) if err != nil { SendErrorResult(res, err) return @@ -85,7 +85,7 @@ func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) { } 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 { res.WriteHeader(http.StatusNotModified) return diff --git a/server/ctrl/config.go b/server/ctrl/config.go index 8d1bdf62..15c450d7 100644 --- a/server/ctrl/config.go +++ b/server/ctrl/config.go @@ -92,7 +92,7 @@ func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) { cfg := Config.Export() 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 { res.WriteHeader(http.StatusNotModified) return diff --git a/server/ctrl/files.go b/server/ctrl/files.go index 38d76fbf..30988d7d 100644 --- a/server/ctrl/files.go +++ b/server/ctrl/files.go @@ -85,7 +85,7 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) { Tmp1 interface{} }{ files, perms } if j, err := json.Marshal(tmp); err == nil { - return Hash(string(j)) + return Hash(string(j), 20) } return "" }() diff --git a/server/ctrl/session.go b/server/ctrl/session.go index d40a8189..0ccf183d 100644 --- a/server/ctrl/session.go +++ b/server/ctrl/session.go @@ -72,7 +72,7 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) { SendErrorResult(res, NewError(err.Error(), 500)) return } - obfuscate, err := EncryptString(SECRET_KEY, string(s)) + obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_USER, string(s)) if err != nil { SendErrorResult(res, NewError(err.Error(), 500)) return diff --git a/server/ctrl/share.go b/server/ctrl/share.go index b6ea0027..3d16cb2a 100644 --- a/server/ctrl/share.go +++ b/server/ctrl/share.go @@ -44,7 +44,7 @@ func ShareUpsert(ctx App, res http.ResponseWriter, req *http.Request) { a, err := req.Cookie(COOKIE_NAME_AUTH) if err != nil { return "" - } + } return a.Value } return ctx.Share.Auth @@ -146,7 +146,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) { } if submittedProof.Key != "" { - submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value) + submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value, 20) verifiedProof = append(verifiedProof, submittedProof) } @@ -158,7 +158,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) { Name: COOKIE_NAME_PROOF, Value: func(p []model.Proof) string { j, _ := json.Marshal(p) - str, _ := EncryptString(SECRET_KEY, string(j)) + str, _ := EncryptString(SECRET_KEY_DERIVATE_FOR_PROOF, string(j)) return str }(verifiedProof), Path: COOKIE_PATH, diff --git a/server/middleware/session.go b/server/middleware/session.go index 94fe8c77..90bca82f 100644 --- a/server/middleware/session.go +++ b/server/middleware/session.go @@ -30,7 +30,7 @@ func AdminOnly(fn func(App, http.ResponseWriter, *http.Request)) func(ctx App, r return } - str, err := DecryptString(SECRET_KEY, c.Value); + str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, c.Value); if err != nil { SendErrorResult(res, ErrPermissionDenied) 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) 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 { // This typically happen when changing the secret key return session, nil @@ -223,7 +223,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) { return session, nil } str = cookie.Value - str, err = DecryptString(SECRET_KEY, str) + str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, str) if err != nil { // This typically happen when changing the secret key return session, nil diff --git a/server/model/share.go b/server/model/share.go index f173741f..3fa930ac 100644 --- a/server/model/share.go +++ b/server/model/share.go @@ -261,7 +261,7 @@ func ShareProofGetAlreadyVerified(req *http.Request) []Proof { if len(cookieValue) > 500 { return p } - j, err := DecryptString(SECRET_KEY, cookieValue) + j, err := DecryptString(SECRET_KEY_DERIVATE_FOR_PROOF, cookieValue) if err != nil { return p } @@ -306,7 +306,7 @@ func shareProofAreEquivalent(ref Proof, p Proof) bool { } for _, chunk := range strings.Split(ref.Value, ",") { chunk = strings.Trim(chunk, " ") - if p.Id == Hash(ref.Key + "::" + chunk) { + if p.Id == Hash(ref.Key + "::" + chunk, 20) { return true } }